Hello, Thomas!
On 8/25/25 07:29, Thomas Huth wrote:
On 19/08/2025 16.39, Gustavo Romero wrote:
The goal of this series is to remove Avocado as a dependency for running
the reverse_debugging functional test.
This test, the last one I’m aware of that relies on Avocado, requires it
because of the need for GDB to test reverse stepping and continue.
Hi!
Please note that there are currently also some efforts going on to extract the
GDB part from avocado into a more self-contained python module called aautils,
which might help here, too:
https://github.com/avocado-framework/aautils/issues/82
Thanks, I was not aware of it. But note that the Avocado GDB API requires one
to deal with GDB packets directly, which is unnecessary for tests like reverse
debug. I think that in general, in QEMU, we should try to avoid using it as
much as possible because the tests became annoying to read without any strong
need for it.
In the commit message for 4/4 I mention that benefit of using the GDB Python
API instead.
I think we should aim to make the tests in QEMU _extremely_ easy to list, run,
and read. The original reverse_debugging test, using Avocado's GDB API, for
instance, is one example we should try to avoid. Say some developer is changing
something not related to RR but ends up breaking reverse_debugging. The
developer
should at least be able to promptly run the QEMU, connect GDB, and reproduce the
issue manually following the exact commands in the test, without having to
consult the GDB protocol manual and to find out which GDB command is mapped to
which GDB packet.
In that sense I confess I'm not 100% happy with the output of reverse_debugging
yet, but one problem at a time :)
In this series, we leveraged the run-test.py script used in the
check-tcg tests, making it a GDB runner capable of calling a test script
without spawning any VMs. In this configuration, the test script can
manage the VMs and also import gdb from the test script, making the
Python GDB API available inside the functional test.
The test is kept “skipped” for aarch64, ppc64, and x86_64, so it is
necessary to set QEMU_TEST_FLAKY_TESTS=1 in the test environment to
effectively run the test on these archs.
On aarch64, the test is flaky, but there is a fix that I’ve tested while
writing this series [0] that resolves it. On ppc64 and x86_64, the test
always fails: on ppc64, GDB gets a bogus PC, and on x86_64, the last
part of the test (reverse-continue) does not hit the last executed PC
(as it should) but instead jumps to the beginning of the code (fist PC
in forward order).
At least the x86 test used to work for me most of the time, it just fails
occasionally. Same for the ppc64 test if I disable the powernv subtest there.
ok, I'll double check the state on x86 in master. I understand we're not
testing reverse_debugging in our CI currently?
>> Thus, to run the reverse_debugging test effectively on aarch64:
$ export QEMU_TEST_FLAKY_TESTS=1
$ make check-functional
I gave it a try, but this did not work for me, the test was not run at all
anymore. Are there any patches needed on top?
hmm that's odd. I'm able to run it with 'make check-functional' and with 'meson
test'...
This is how I'm running it (let me know if I'm missing something):
gromero@gromero0:/mnt/git/qemu_$ b4 shazam
20250819143916.4138035-1-gustavo.rom...@linaro.org
Grabbing thread from
lore.kernel.org/all/20250819143916.4138035-1-gustavo.rom...@linaro.org/t.mbox.gz
Checking for newer revisions
Grabbing search results from lore.kernel.org
Analyzing 9 messages in the thread
Looking for additional code-review trailers on lore.kernel.org
Analyzing 0 code-review messages
Checking attestation on all messages, may take a moment...
---
✓ [PATCH 1/4] tests/guest-debug: Make QEMU optional in run-test.py
✓ [PATCH 2/4] tests/functional: Support tests that require a runner
✓ [PATCH 3/4] tests/functional: Mark main in QemuBaseTest class as a static
method
+ Reviewed-by: Daniel P. Berrangé <berra...@redhat.com> (✓ DKIM/redhat.com)
✓ [PATCH 4/4] tests/functional: Adapt reverse_debugging to run w/o Avocado
---
✓ Signed: DKIM/linaro.org
---
Total patches: 4
---
Applying: tests/guest-debug: Make QEMU optional in run-test.py
Applying: tests/functional: Support tests that require a runner
Applying: tests/functional: Mark main in QemuBaseTest class as a static method
Applying: tests/functional: Adapt reverse_debugging to run w/o Avocado
gromero@gromero0:/mnt/git/qemu_$
gromero@gromero0:/mnt/git/qemu_/build$ ../configure
--target-list=aarch64-softmmu --disable-docs
gromero@gromero0:/mnt/git/qemu_/build$ make -j 32
gromero@gromero0:/mnt/git/qemu_/build$ time make -j 15 check-functional
[1/2] Generating tests/functional/func-precache-aarch64-aarch64_reverse_debug
with a custom command (wrapped by meson to set env)
2025-08-25 12:50:04,215 - qemu-test - INFO - Attempting to cache
'/home/gromero/.cache/qemu/download/7e1430b81c26bdd0da025eeb8fbd77b5dc961da4364af26e771bd39f379cbbf7'
2025-08-25 12:50:04,225 - qemu-test - DEBUG - Using cached asset
/home/gromero/.cache/qemu/download/7e1430b81c26bdd0da025eeb8fbd77b5dc961da4364af26e771bd39f379cbbf7
for
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/29/Everything/aarch64/os/images/pxeboot/vmlinuz
GDB CMD: /usr/bin/gdb-multiarch -q -n -batch -ex 'set pagination off' -ex 'set confirm
off' -ex "py
sys.argv=['/mnt/git/qemu_/tests/functional/test_aarch64_reverse_debug.py']" -x
/mnt/git/qemu_/tests/functional/test_aarch64_reverse_debug.py
[0/1] Running external command precache-functional (wrapped by meson to set env)
make[1]: Entering directory '/mnt/git/qemu_/build'
[1/6] Generating qemu-version.h with a custom command (wrapped by meson to
capture output)
/mnt/git/qemu_/build/pyvenv/bin/meson test --no-rebuild -t 1 --setup thorough
--num-processes 10 --print-errorlogs --suite func --suite func-quick --suite
func-thorough
1/27 qemu:func-thorough+func-aarch64-thorough+thorough /
func-aarch64-aarch64_virt_gpu SKIP 1.95s 0
subtests passed
2/27 qemu:func-thorough+func-aarch64-thorough+thorough /
func-aarch64-aarch64_smmu SKIP 4.17s 0
subtests passed
3/27 qemu:func-thorough+func-aarch64-thorough+thorough /
func-aarch64-aarch64_raspi4 OK 28.11s 2
subtests passed
4/27 qemu:func-thorough+func-aarch64-thorough+thorough /
func-aarch64-aarch64_device_passthrough OK 31.34s 1
subtests passed
5/27 qemu:func-thorough+func-aarch64-thorough+thorough /
func-aarch64-aarch64_reverse_debug OK 11.73s
<------ 'exitcode', not TAP, so no subtests-like output
6/27 qemu:func-quick+func-aarch64 / func-aarch64-migration
OK 0.97s 2 subtests passed
7/27 qemu:func-quick+func-aarch64 / func-aarch64-empty_cpu_model
OK 0.17s 1 subtests passed
[...]
gromero@gromero0:/mnt/git/qemu_/build$ grep -A 58 "= 5/27 ="
/mnt/git/qemu_/build/meson-logs/testlog-thorough.txt
==================================== 5/27 ====================================
test: qemu:func-thorough+func-aarch64-thorough+thorough /
func-aarch64-aarch64_reverse_debug
start time: 13:44:21
duration: 11.73s
result: exit status 0
command:
LD_LIBRARY_PATH=/mnt/git/qemu_/build/contrib/plugins:/mnt/git/qemu_/build/tests/tcg/plugins
QEMU_BUILD_ROOT=/mnt/git/qemu_/build MALLOC_PERTURB_=138 G_TEST_SLOW=1
ASAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1 RUST_BACKTRACE=1
QEMU_TEST_QEMU_IMG=/mnt/git/qemu_/build/qemu-img MESON_TEST_ITERATION=1
PYTHONPATH=/mnt/git/qemu_/python:/mnt/git/qemu_/tests/functional:/mnt/git/qemu_/build/pyvenv/lib/python3.10/site-packages
QEMU_TEST_QEMU_BINARY=/mnt/git/qemu_/build/qemu-system-aarch64
UBSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1
MSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1
/mnt/git/qemu_/build/pyvenv/bin/python3
/mnt/git/qemu_/tests/guest-debug/run-test.py --gdb /usr/bin/gdb-multiarch
--test /mnt/git/qemu_/tests/functional/test_aarch64_reverse_debug.py
----------------------------------- stdout -----------------------------------
Formatting
'/mnt/git/qemu_/build/tests/functional/aarch64/test_aarch64_reverse_debug.ReverseDebugging_AArch64.test_aarch64_virt/scratch/disk.qcow2',
fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib
size=134217728 lazy_refcounts=off refcount_bits=16
TAP version 13
0x0000000040000000 in ?? ()
0x0000000040000004 in ?? ()
0x0000000040000008 in ?? ()
0x000000004000000c in ?? ()
0x0000000040000010 in ?? ()
0x0000000040000014 in ?? ()
0x0000000040080000 in ?? ()
0x0000000040080004 in ?? ()
0x00000000410d0000 in ?? ()
0x00000000410d0020 in ?? ()
0x00000000410d0024 in ?? ()
0x00000000410d0020 in ?? ()
0x00000000410d0000 in ?? ()
0x0000000040080004 in ?? ()
0x0000000040080000 in ?? ()
0x0000000040000014 in ?? ()
0x0000000040000010 in ?? ()
0x000000004000000c in ?? ()
0x0000000040000008 in ?? ()
0x0000000040000004 in ?? ()
0x0000000040000000 in ?? ()
0x0000000040000004 in ?? ()
0x0000000040000008 in ?? ()
0x000000004000000c in ?? ()
0x0000000040000010 in ?? ()
0x0000000040000014 in ?? ()
0x0000000040080000 in ?? ()
0x0000000040080004 in ?? ()
0x00000000410d0000 in ?? ()
0x00000000410d0020 in ?? ()
0x00000000410d0024 in ?? ()
Breakpoint 1 at 0x40000000
Breakpoint 2 at 0x40000004
Breakpoint 3 at 0x40000008
Breakpoint 4 at 0x4000000c
Breakpoint 5 at 0x40000010
Breakpoint 6 at 0x40000014
Breakpoint 7 at 0x40080000
Breakpoint 8 at 0x40080004
Breakpoint 9 at 0x410d0000
Breakpoint 10 at 0x410d0020
Program received signal SIGINT, Interrupt.
0xffff3e25348a2050 in ?? ()
Breakpoint 10, 0x00000000410d0020 in ?? ()
ok 1 test_aarch64_reverse_debug.ReverseDebugging_AArch64.test_aarch64_virt
1..1
GDB CMD: /usr/bin/gdb-multiarch -q -n -batch -ex 'set pagination off' -ex 'set confirm
off' -ex "py
sys.argv=['/mnt/git/qemu_/tests/functional/test_aarch64_reverse_debug.py']" -x
/mnt/git/qemu_/tests/functional/test_aarch64_reverse_debug.py
==============================================================================
gromero@gromero0:/mnt/git/qemu_/build$
Also, using meson test:
gromero@gromero0:/mnt/git/qemu_/build$ cat
/mnt/git/qemu_/build/meson-logs/testlog-thorough.txt
Log of Meson test suite run on 2025-08-25T13:54:13.544507
Inherited environment: SHELL=/bin/bash PYENV_SHELL=bash LC_ADDRESS=en_US.UTF-8
LC_NAME=en_US.UTF-8 LC_MONETARY=en_US.UTF-8 PWD=/mnt/git/qemu_/build
LOGNAME=gromero XDG_SESSION_TYPE=tty TVM_HOME=/home/gromero/git/tvm
MOTD_SHOWN=pam HOME=/home/gromero LANG=en_US.UTF-8 LC_PAPER=en_US.UTF-8
LS_COLORS='rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.webp=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:'
SSH_CONNECTION='192.168.122.1 57300 192.168.122.158 22'
LESSCLOSE='/usr/bin/lesspipe %s %s' XDG_SESSION_CLASS=user
PYTHONPATH=/home/gromero/git/tvm/python: TERM=xterm-256color
LC_IDENTIFICATION=en_US.UTF-8 LESSOPEN='| /usr/bin/lesspipe %s'
QEMU_TEST_FLAKY_TESTS=1 USER=gromero SHLVL=1 LC_TELEPHONE=en_US.UTF-8
LC_MEASUREMENT=en_US.UTF-8 XDG_SESSION_ID=2738 XDG_RUNTIME_DIR=/run/user/1000
SSH_CLIENT='192.168.122.1 57300 22' PYENV_ROOT=/home/gromero/.pyenv
LC_TIME=en_US.UTF-8
XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop
PATH=/home/gromero/.pyenv/shims:/home/gromero/.pyenv/bin:/home/gromero/.local/bin:/home/gromero/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus SSH_TTY=/dev/pts/0
LC_NUMERIC=en_US.UTF-8 OLDPWD=/mnt/git/qemu_
_=/mnt/git/qemu_rr_fix/build/pyvenv/bin/meson
==================================== 1/1 =====================================
test: qemu:func-thorough+func-aarch64-thorough+thorough /
func-aarch64-aarch64_reverse_debug
start time: 13:54:13
duration: 2.65s
result: exit status 0
command:
PYTHONPATH=/mnt/git/qemu_/python:/mnt/git/qemu_/tests/functional:/mnt/git/qemu_/build/pyvenv/lib/python3.10/site-packages
MSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1
LD_LIBRARY_PATH=/mnt/git/qemu_/build/contrib/plugins:/mnt/git/qemu_/build/tests/tcg/plugins
RUST_BACKTRACE=1 MALLOC_PERTURB_=243
ASAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1
QEMU_TEST_QEMU_BINARY=/mnt/git/qemu_/build/qemu-system-aarch64
QEMU_BUILD_ROOT=/mnt/git/qemu_/build
UBSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1
G_TEST_SLOW=1 MESON_TEST_ITERATION=1
QEMU_TEST_QEMU_IMG=/mnt/git/qemu_/build/qemu-img SPEED=thorough
/mnt/git/qemu_/build/pyvenv/bin/python3
/mnt/git/qemu_/tests/guest-debug/run-test.py --gdb /usr/bin/gdb-multiarch
--test /mnt/git/qemu_/tests/functional/test_aarch64_reverse_debug.py
----------------------------------- stdout -----------------------------------
Formatting
'/mnt/git/qemu_/build/tests/functional/aarch64/test_aarch64_reverse_debug.ReverseDebugging_AArch64.test_aarch64_virt/scratch/disk.qcow2',
fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib
size=134217728 lazy_refcounts=off refcount_bits=16
TAP version 13
0x0000000040000000 in ?? ()
0x0000000040000004 in ?? ()
0x0000000040000008 in ?? ()
0x000000004000000c in ?? ()
0x0000000040000010 in ?? ()
0x0000000040000014 in ?? ()
0x0000000040080000 in ?? ()
0x0000000040080004 in ?? ()
0x00000000410d0000 in ?? ()
0x00000000410d0020 in ?? ()
0x00000000410d0024 in ?? ()
0x00000000410d0020 in ?? ()
0x00000000410d0000 in ?? ()
0x0000000040080004 in ?? ()
0x0000000040080000 in ?? ()
0x0000000040000014 in ?? ()
0x0000000040000010 in ?? ()
0x000000004000000c in ?? ()
0x0000000040000008 in ?? ()
0x0000000040000004 in ?? ()
0x0000000040000000 in ?? ()
0x0000000040000004 in ?? ()
0x0000000040000008 in ?? ()
0x000000004000000c in ?? ()
0x0000000040000010 in ?? ()
0x0000000040000014 in ?? ()
0x0000000040080000 in ?? ()
0x0000000040080004 in ?? ()
0x00000000410d0000 in ?? ()
0x00000000410d0020 in ?? ()
0x00000000410d0024 in ?? ()
Breakpoint 1 at 0x40000000
Breakpoint 2 at 0x40000004
Breakpoint 3 at 0x40000008
Breakpoint 4 at 0x4000000c
Breakpoint 5 at 0x40000010
Breakpoint 6 at 0x40000014
Breakpoint 7 at 0x40080000
Breakpoint 8 at 0x40080004
Breakpoint 9 at 0x410d0000
Breakpoint 10 at 0x410d0020
Program received signal SIGINT, Interrupt.
0xffff47bcc84a2050 in ?? ()
Breakpoint 10, 0x00000000410d0020 in ?? ()
ok 1 test_aarch64_reverse_debug.ReverseDebugging_AArch64.test_aarch64_virt
1..1
GDB CMD: /usr/bin/gdb-multiarch -q -n -batch -ex 'set pagination off' -ex 'set confirm
off' -ex "py
sys.argv=['/mnt/git/qemu_/tests/functional/test_aarch64_reverse_debug.py']" -x
/mnt/git/qemu_/tests/functional/test_aarch64_reverse_debug.py
==============================================================================
Ok: 1
Fail: 0
gromero@gromero0:/mnt/git/qemu_/build$
Any chance you got confused by no subtests-like output caused by 'exitcode'
used instead of ´tap'?
Anyway, shifting to a different test harness here makes me wonder whether the
whole reverse_debug test should maybe be rather moved to tests/tcg instead,
where we already have the basic support for the stuff from tests/guest-debug/ ?
The aarch64 would require a different guest payload, of course, in that case,
so not sure whether it's feasible?
I think reverse_debugging is really a functional test. It requires GDB, yes,
but also QMP and booting a whole kernel and the feature itself makes me think
it's a functional test. I wouldn't move it to tcg-check just for the sake of
no adding a new way to run test in meson.build in functional tests.
Cheers,
Gustavo