All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/13] testing/next: functional testing updates for gdb
@ 2026-09-30 16:46 Alex Bennée
  2026-09-30 16:46 ` [PATCH 01/13] tests/functional: test_acpi_bits requires TCG Alex Bennée
                   ` (12 more replies)
  0 siblings, 13 replies; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen

Hi,

This is the current state of my testing/next tree. There a are a few
minor tweaks and fixes that I've picked up. The majority of the new
code adds testing for the gdb stub when used via KVM. There are two
approaches.

The first is an attempt to work just with the default bios code. It's
a little limited and I'm not super happy with the "special" heuristics
due to the fragility but it does work without symbols.

As a result I spoke to Anders who handles the tuxrun images and he was
able to turn on debugging symbols and provide a vmlinux alongside the
bootable image. With these updates I was able to resurrect the old
test script I was running by hand and then plumb it into a functional
test.

So far I've only done x86_64 but if people are happy with the result
I'll do the remaining KVM hosts and test the ones where I can (do we
have a riscv kvm host anywhere?).

The reason I went on the side-quest is because when working on
cleaning up QEMU's internal KVM api I realised that quite a large
chunk of it is not exercised by our functional tests. This would
ensure that at least:

  kvm_arch_update_guest_debug
  kvm_arch_get_registers
  kvm_arch_set_registers

is exercised and I'm less likely to break things in my r-factor ;-)

Alex.

Alex Bennée (12):
  tests/functional: test_acpi_bits requires TCG
  tests/functional: add migration diagnostics and pace nvme activity
    (HACK!)
  meson: move gdb detection into the top level build file
  tests/functional: add basic gdbstub test for KVM
  tests/functional: allow tuxrun tests to be passed "accel"
  tests/functional: split x86_64 tuxrun into tcg and kvm run
  tests/functional: split aarch64 tuxrun into tcg and kvm run
  tests/functional: update x86_64 tuxrun images
  tests/guest-debug: add --kargs option to run-test
  tests/guest-debug: add --symbols option to run-test
  tests/functional: teach tuxrun about launching gdb tests
  tests/functional: add tuxrun kvm gdb test for x86_64

Max Filippov (1):
  tests/tcg: fix buffer overflow in multiarch/linux/linux-sigrtminmax

 meson.build                                   |  15 +-
 tests/tcg/multiarch/linux/linux-sigrtminmax.c |   2 +-
 tests/functional/aarch64/test_tuxrun.py       |  10 ++
 .../functional/gdb-scripts/kernel_gdb_test.py | 157 ++++++++++++++++++
 .../functional/gdb-scripts/kvm_fw_gdb_test.py | 119 +++++++++++++
 tests/functional/meson.build                  |   5 +-
 tests/functional/migration.py                 |  37 ++++-
 tests/functional/qemu_test/tuxruntest.py      |  99 +++++++++--
 tests/functional/x86_64/meson.build           |   1 +
 tests/functional/x86_64/test_acpi_bits.py     |   2 +
 tests/functional/x86_64/test_kvm_gdbstub.py   |  55 ++++++
 .../functional/x86_64/test_nvme_migration.py  |   1 +
 tests/functional/x86_64/test_tuxrun.py        |  45 ++++-
 tests/guest-debug/run-test.py                 |  10 ++
 tests/tcg/meson.build                         |   5 -
 15 files changed, 523 insertions(+), 40 deletions(-)
 create mode 100644 tests/functional/gdb-scripts/kernel_gdb_test.py
 create mode 100644 tests/functional/gdb-scripts/kvm_fw_gdb_test.py
 create mode 100755 tests/functional/x86_64/test_kvm_gdbstub.py

-- 
2.47.3



^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 01/13] tests/functional: test_acpi_bits requires TCG
  2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
@ 2026-09-30 16:46 ` Alex Bennée
  2026-10-01 11:18   ` marcandre.lureau
  2026-09-30 16:46 ` [PATCH 02/13] tests/functional: add migration diagnostics and pace nvme activity (HACK!) Alex Bennée
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Michael S. Tsirkin, Paolo Bonzini

Running a full thorough test suite on a KVM-only build fails due to
acpi bits needing icount, therefor tcg. Declare the restriction so the
test harness can skip it.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/functional/x86_64/test_acpi_bits.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tests/functional/x86_64/test_acpi_bits.py b/tests/functional/x86_64/test_acpi_bits.py
index ec716d643bf..62c57d23f6c 100755
--- a/tests/functional/x86_64/test_acpi_bits.py
+++ b/tests/functional/x86_64/test_acpi_bits.py
@@ -303,6 +303,8 @@ def test_acpi_smbios_bits(self):
         """The main test case implementation."""
 
         self.set_machine('pc')
+        self.require_accelerator('tcg')
+
         iso_file = self.scratch_file('bits-%d.iso' % self.BITS_INTERNAL_VER)
 
         self.assertTrue(os.access(iso_file, os.R_OK))
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 02/13] tests/functional: add migration diagnostics and pace nvme activity (HACK!)
  2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
  2026-09-30 16:46 ` [PATCH 01/13] tests/functional: test_acpi_bits requires TCG Alex Bennée
@ 2026-09-30 16:46 ` Alex Bennée
  2026-09-30 16:46 ` [PATCH 03/13] tests/tcg: fix buffer overflow in multiarch/linux/linux-sigrtminmax Alex Bennée
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Fabiano Rosas, Jesper Devantier, Paolo Bonzini,
	open list:nvme

This is a hacky patch for comment but I've included the diagnostic
hacks to the migration test as well as my workaround to get itworking.

This test was failing on my KVM system. On investigation I found the
nVME activity meant the migration never completed. I ended up
inserting some sleeps into the workload script until I was able to
get it to run.

*NOTE*: obviously this can't be merged as is but I think we could
certainly do with more tracking in the test to see when things aren't
working with possibly the sleep as another patch.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/functional/migration.py                 | 37 +++++++++++++++----
 .../functional/x86_64/test_nvme_migration.py  |  1 +
 2 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/tests/functional/migration.py b/tests/functional/migration.py
index 8d2428efc24..e51a82c22f4 100644
--- a/tests/functional/migration.py
+++ b/tests/functional/migration.py
@@ -22,18 +22,41 @@ class MigrationTest(QemuSystemTest):
     timeout = 10
 
     @staticmethod
-    def migration_finished(vm):
-        return vm.cmd('query-migrate')['status'] in ('completed', 'failed')
+    def migration_finished(query):
+        return query['status'] in ('completed', 'failed')
 
-    def assert_migration(self, src_vm, dst_vm):
+    def wait_for_vm(self, src_or_dst, vm):
+        "Track the state of one VM in the migration"
+        current_state = last_state = vm.cmd('query-migrate')
 
-        end = time.monotonic() + self.timeout
-        while time.monotonic() < end and not self.migration_finished(src_vm):
-            time.sleep(0.1)
+        self.log.info(f"waiting for {src_or_dst} to complete")
 
         end = time.monotonic() + self.timeout
-        while time.monotonic() < end and not self.migration_finished(dst_vm):
+        while time.monotonic() < end:
+            if self.migration_finished(current_state):
+                break
+            else:
+                last_remain = last_state['remaining']
+                current_remain = current_state['remaining']
+
+                if current_remain > last_remain:
+                    self.log.warning(f"slow migration {current_remain} > {last_remain}")
+
             time.sleep(0.1)
+            last_state = current_state
+            current_state = vm.cmd('query-migrate')
+
+
+    def assert_migration(self, src_vm, dst_vm):
+
+        self.wait_for_vm("src", src_vm)
+
+        # if we hit this we never completed...
+        self.assertEqual(src_vm.cmd('query-migrate')['status'], 'completed')
+
+        self.wait_for_vm("dst", dst_vm)
+
+        self.log.info("checking everything is OK")
 
         self.assertEqual(src_vm.cmd('query-migrate')['status'], 'completed')
         self.assertEqual(dst_vm.cmd('query-migrate')['status'], 'completed')
diff --git a/tests/functional/x86_64/test_nvme_migration.py b/tests/functional/x86_64/test_nvme_migration.py
index 890f0aab6d6..58596f63cd3 100755
--- a/tests/functional/x86_64/test_nvme_migration.py
+++ b/tests/functional/x86_64/test_nvme_migration.py
@@ -109,6 +109,7 @@ def launch_source_vm(self, vm):
                 rm -f /tmp/test_nvme_mig_workload.iter_finished; \
                 echo 3 > /proc/sys/vm/drop_caches; \
                 find /usr/bin -type f -exec cksum {} \\;; \
+                sleep 0.3; \
                 touch /tmp/test_nvme_mig_workload.iter_finished; \
             done) > /dev/null 2> /tmp/test_nvme_mig_workload.errors &",
             prompt, vm=vm)
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 03/13] tests/tcg: fix buffer overflow in multiarch/linux/linux-sigrtminmax
  2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
  2026-09-30 16:46 ` [PATCH 01/13] tests/functional: test_acpi_bits requires TCG Alex Bennée
  2026-09-30 16:46 ` [PATCH 02/13] tests/functional: add migration diagnostics and pace nvme activity (HACK!) Alex Bennée
@ 2026-09-30 16:46 ` Alex Bennée
  2026-10-01 11:18   ` marcandre.lureau
  2026-09-30 16:46 ` [PATCH 04/13] meson: move gdb detection into the top level build file Alex Bennée
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Max Filippov

From: Max Filippov <jcmvbkbc@gmail.com>

Fix new_argv allocation size to be `(argc + 2) * sizeof(char *)` bytes,
which matches the way it's used to store `argc + 2` pointers.

This fixes the test for me, which otherwise fails on xtensa with the
following message

  linux-sigrtminmax.c: 59: main: Assertion `execve(new_argv[0], new_argv, environ) == 0' failed.'.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Fixes: 6f58b090328 ("tests/tcg: Add SIGRTMIN/SIGRTMAX test")
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Ilya Leoshkevich <iii@linux.ibm.com>
Message-ID: <20260708150541.2137546-1-jcmvbkbc@gmail.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/tcg/multiarch/linux/linux-sigrtminmax.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/tcg/multiarch/linux/linux-sigrtminmax.c b/tests/tcg/multiarch/linux/linux-sigrtminmax.c
index a7059aacd9c..b5ea65f3d39 100644
--- a/tests/tcg/multiarch/linux/linux-sigrtminmax.c
+++ b/tests/tcg/multiarch/linux/linux-sigrtminmax.c
@@ -39,7 +39,7 @@ int main(int argc, char **argv)
     assert(qemu);
 
     if (!getenv("QEMU_RTSIG_MAP")) {
-        char **new_argv = malloc((argc + 2) + sizeof(char *));
+        char **new_argv = malloc((argc + 2) * sizeof(char *));
         int tsig1, hsig1, count1, tsig2, hsig2, count2;
         char rt_sigmap[64];
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 04/13] meson: move gdb detection into the top level build file
  2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
                   ` (2 preceding siblings ...)
  2026-09-30 16:46 ` [PATCH 03/13] tests/tcg: fix buffer overflow in multiarch/linux/linux-sigrtminmax Alex Bennée
@ 2026-09-30 16:46 ` Alex Bennée
  2026-09-30 18:20   ` Pierrick Bouvier
  2026-10-01 11:18   ` marcandre.lureau
  2026-09-30 16:46 ` [PATCH 05/13] tests/functional: add basic gdbstub test for KVM Alex Bennée
                   ` (8 subsequent siblings)
  12 siblings, 2 replies; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Paolo Bonzini

Currently gdb is only used by TCG based tests but hypervisors want to
use gdbstub too. To be able to test this case we need to always probe
and report the gdb we have.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 meson.build                  | 15 +++++++--------
 tests/functional/meson.build |  5 ++---
 tests/tcg/meson.build        |  5 -----
 3 files changed, 9 insertions(+), 16 deletions(-)

diff --git a/meson.build b/meson.build
index cae1591cd28..ea97047362c 100644
--- a/meson.build
+++ b/meson.build
@@ -163,6 +163,12 @@ else
   iasl = find_program(get_option('iasl'), required: true)
 endif
 
+if get_option('gdb') == ''
+  gdb = find_program(['gdb-multiarch', 'gdb'], required: false)
+else
+  gdb = find_program(get_option('gdb'), required: true)
+endif
+
 edk2_targets = [ 'arm-softmmu', 'aarch64-softmmu', 'i386-softmmu', 'x86_64-softmmu', 'riscv64-softmmu', 'loongarch64-softmmu' ]
 unpack_edk2_blobs = false
 foreach target : edk2_targets
@@ -4707,14 +4713,7 @@ summary(summary_info, bool_yn: true, section: 'Directories')
 summary_info = {}
 summary_info += {'python':            '@0@ (version: @1@)'.format(python.full_path(), python.language_version())}
 summary_info += {'sphinx-build':      sphinx_build}
-
-# FIXME: the [binaries] section of machine files, which can be probed
-# with find_program(), would be great for passing gdb and genisoimage
-# paths from configure to Meson.  However, there seems to be no way to
-# hide a program (for example if gdb is too old).
-if config_host.has_key('GDB')
-  summary_info += {'gdb':             config_host['GDB']}
-endif
+summary_info += {'gdb':               gdb}
 summary_info += {'iasl':              iasl}
 summary_info += {'genisoimage':       config_host['GENISOIMAGE']}
 if host_os == 'windows' and have_ga
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
index c7362dd00ef..68c601d4036 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -83,9 +83,8 @@ foreach speed : ['quick', 'thorough']
                      separator : ':')
 
     # Define the GDB environment variable if gdb is available.
-    gdb = get_option('gdb')
-    if gdb != ''
-      test_env.set('QEMU_TEST_GDB', gdb)
+    if gdb.found()
+      test_env.set('QEMU_TEST_GDB', gdb.full_path())
     endif
 
     foreach test : target_tests
diff --git a/tests/tcg/meson.build b/tests/tcg/meson.build
index 96d5d1249f2..5861ff5ed25 100644
--- a/tests/tcg/meson.build
+++ b/tests/tcg/meson.build
@@ -1,11 +1,6 @@
 env = find_program('env')
 
 docker_wrapper = find_program('../docker/docker.py')
-if get_option('gdb') != ''
-  gdb = find_program(get_option('gdb'), required: true)
-else
-  gdb = find_program(['gdb-multiarch', 'gdb'], required: false)
-endif
 prog_check_plugin_output = find_program('./scripts/check_plugin_output.sh')
 prog_gdb_test = find_program('../guest-debug/run-test.py')
 prog_record_replay = find_program('./scripts/record_replay.sh')
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 05/13] tests/functional: add basic gdbstub test for KVM
  2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
                   ` (3 preceding siblings ...)
  2026-09-30 16:46 ` [PATCH 04/13] meson: move gdb detection into the top level build file Alex Bennée
@ 2026-09-30 16:46 ` Alex Bennée
  2026-10-01 11:18   ` marcandre.lureau
  2026-09-30 16:46 ` [PATCH 06/13] tests/functional: allow tuxrun tests to be passed "accel" Alex Bennée
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Paolo Bonzini

We don't really exercise the KVM bits of gdbstub very much as the TCG
tests are TCG only and the ones in functional tests are focused on
record/replay and reverse debugging.

Add a basic gdbstub test case which uses heuristics to single step
through the default firmware of guests and kick the tyres and check
things are working as expected.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
vAJB:
  - rewrote to use gdb run-test.py framework
  - simplified subprocess code
---
 .../functional/gdb-scripts/kvm_fw_gdb_test.py | 119 ++++++++++++++++++
 tests/functional/x86_64/meson.build           |   1 +
 tests/functional/x86_64/test_kvm_gdbstub.py   |  55 ++++++++
 3 files changed, 175 insertions(+)
 create mode 100644 tests/functional/gdb-scripts/kvm_fw_gdb_test.py
 create mode 100755 tests/functional/x86_64/test_kvm_gdbstub.py

diff --git a/tests/functional/gdb-scripts/kvm_fw_gdb_test.py b/tests/functional/gdb-scripts/kvm_fw_gdb_test.py
new file mode 100644
index 00000000000..b38b874dc58
--- /dev/null
+++ b/tests/functional/gdb-scripts/kvm_fw_gdb_test.py
@@ -0,0 +1,119 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Generic GDB script to verify gdbstub functionality on guest firmware:
+#  - Single-stepping across VM-exits
+#  - Placing a hardware breakpoint at a branch or ahead in disassembly
+#  - Continuing to the breakpoint and validating that registers changed
+#
+# Copyright (c) 2026 Linaro Limited
+#
+# Author:
+#  Alex Bennée <alex.bennee@linaro.org>
+
+import gdb
+from test_gdbstub import main, report
+
+def parse_registers():
+    """Parse 'info registers' into a name -> value dictionary."""
+    regs = {}
+    for line in gdb.execute("info registers", to_string=True).splitlines():
+        parts = line.split()
+        if len(parts) >= 2:
+            regs[parts[0]] = parts[1]
+    return regs
+
+def test_single_step():
+    """
+    Single-step a few instructions and verify PC advances
+    """
+    current_pc = int(gdb.parse_and_eval("$pc"))
+    for step in range(1, 6):
+        gdb.execute("stepi")
+        gdb.execute("x/3i $pc")
+        pc = int(gdb.parse_and_eval("$pc"))
+        report(pc != current_pc, f"single-step {step} advanced pc")
+        current_pc = pc
+
+
+def might_be_jump(asm):
+    """
+    Return true if the assembly string might contain a branch/jump instruction
+    """
+    branch_keywords = {
+        "jmp", "b", "bl", "bx", "bne", "beq", "bgt", "blt", "bge", "ble",
+        "call", "ret", "br", "jal", "jalr", "bc", "bctrl", "j"
+    }
+
+    parts = asm.split()
+    if not parts:
+        return False
+    mnemonic = parts[0].lower()
+    return mnemonic in branch_keywords
+
+
+def test_hw_bkpt():
+    """
+    Set a hwbkpt somewhere in the future.
+    """
+
+    # FIXME - this is fragile
+    disas = gdb.execute("x/10i $pc", to_string=True)
+    lines = disas.strip().splitlines()
+    insns = 0
+    bp = None
+
+    for line in lines:
+        clean = line.lstrip("=>").strip()
+        parts = clean.split(":", 1)
+        if len(parts) < 2 or not parts[1].strip():
+            continue
+        insns += 1
+
+        if might_be_jump(parts[1]):
+            # jump too close, bail out?
+            if insns < 2:
+                report(False, "found jump far enough away")
+                return
+            else:
+                addr = int(parts[0].split()[0], 16)
+                bp = gdb.Breakpoint(f"*{hex(addr)}",
+                                    type=gdb.BP_HARDWARE_BREAKPOINT)
+                break
+        elif insns == 10:
+            addr = int(parts[0].split()[0], 16)
+            bp = gdb.Breakpoint(f"*{hex(addr)}",
+                                type=gdb.BP_HARDWARE_BREAKPOINT)
+            break
+
+    report(bp is not None, f"set hwbkpt @ {bp.location}")
+    gdb.execute("continue")
+
+    end_pc = gdb.parse_and_eval('$pc')
+    report(bp.hit_count == 1,
+           "break @ %s (%d hits)" % (end_pc, bp.hit_count))
+
+    bp.delete()
+    return
+
+def test_reg_updates(regs_start):
+    regs_end = parse_registers()
+
+    changed = [k for k in regs_start
+               if k in regs_end and regs_start[k] != regs_end[k]]
+
+    report(len(changed) > 0, f"{len(changed)} registers changed.")
+
+def run_test():
+    regs_start = parse_registers()
+
+    test_single_step()
+
+    # skip any pesky mode switching code
+    gdb.execute("stepi 50")
+
+    test_hw_bkpt()
+
+    test_reg_updates(regs_start)
+
+
+main(run_test)
diff --git a/tests/functional/x86_64/meson.build b/tests/functional/x86_64/meson.build
index 0353b2af8e1..080e12ddef1 100644
--- a/tests/functional/x86_64/meson.build
+++ b/tests/functional/x86_64/meson.build
@@ -13,6 +13,7 @@ tests_x86_64_system_quick = [
   'bad_vmstate',
   'cpu_model_versions',
   'cpu_queries',
+  'kvm_gdbstub',
   'mem_addr_space',
   'migration',
   'pc_cpu_hotplug_props',
diff --git a/tests/functional/x86_64/test_kvm_gdbstub.py b/tests/functional/x86_64/test_kvm_gdbstub.py
new file mode 100755
index 00000000000..26876c3dc58
--- /dev/null
+++ b/tests/functional/x86_64/test_kvm_gdbstub.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Functional test verifying KVM gdbstub operations on firmware:
+#  - Single-stepping across VM-exits
+#  - Register sampling across execution steps
+#  - Hardware breakpoint at branch destination or instruction
+#
+# Copyright (c) 2026 Linaro Limited
+#
+# Author:
+#  Alex Bennée <alex.bennee@linaro.org>
+
+import os
+import subprocess
+from pathlib import Path
+from qemu_test import QemuSystemTest, skipIfMissingEnv
+
+
+class KvmGdbstubTest(QemuSystemTest):
+
+    @skipIfMissingEnv("QEMU_TEST_GDB")
+    def test_x86_64_kvm_fw_gdb(self):
+        self.require_accelerator("kvm")
+
+        gdb_path = os.getenv("QEMU_TEST_GDB")
+
+        tests_dir = Path(__file__).resolve().parents[2]
+        run_test = tests_dir / "guest-debug" / "run-test.py"
+        gdb_script = (tests_dir / "functional" / "gdb-scripts" /
+                      "kvm_fw_gdb_test.py")
+
+        qargs = "-machine pc -accel kvm -cpu host -smp 1 -m 512M -display none"
+        cmd = [
+            str(run_test),
+            "--qemu", self.qemu_bin,
+            "--qargs", qargs,
+            "--binary", "",
+            "--test", str(gdb_script),
+            "--gdb", gdb_path,
+        ]
+
+        res = subprocess.run(cmd, text=True,
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.STDOUT)
+        if res.stdout:
+            self.log.info('run-test.py: %s', res.stdout)
+
+        self.assertEqual(res.returncode, 0,
+                         f"run-test.py failed ({res.returncode}):\n")
+
+
+if __name__ == '__main__':
+    QemuSystemTest.main()
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 06/13] tests/functional: allow tuxrun tests to be passed "accel"
  2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
                   ` (4 preceding siblings ...)
  2026-09-30 16:46 ` [PATCH 05/13] tests/functional: add basic gdbstub test for KVM Alex Bennée
@ 2026-09-30 16:46 ` Alex Bennée
  2026-10-01 11:18   ` marcandre.lureau
  2026-09-30 16:46 ` [PATCH 07/13] tests/functional: split x86_64 tuxrun into tcg and kvm run Alex Bennée
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen

For some tests we are about to add we want the flexibility to force
"kvm" so give them that ability.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/functional/qemu_test/tuxruntest.py | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py
index 6c442ff0dc4..ca1589fea37 100644
--- a/tests/functional/qemu_test/tuxruntest.py
+++ b/tests/functional/qemu_test/tuxruntest.py
@@ -65,7 +65,7 @@ def fetch_tuxrun_assets(self, kernel_asset, rootfs_asset, dtb_asset=None):
 
         return (kernel_image, disk_image, dtb)
 
-    def prepare_run(self, kernel, disk, drive, dtb=None, console_index=0):
+    def prepare_run(self, accel, kernel, disk, drive, dtb=None, console_index=0):
         """
         Setup to run and add the common parameters to the system
         """
@@ -79,6 +79,10 @@ def prepare_run(self, kernel, disk, drive, dtb=None, console_index=0):
         self.kcmd_line += f" root=/dev/{self.root}"
         self.kcmd_line += f" console={self.console}"
 
+        # have we specified an accelerator?
+        if accel:
+            self.vm.add_args('-accel', accel)
+
         self.vm.add_args('-kernel', kernel,
                          '-append', self.kcmd_line,
                          '-blockdev', blockdev)
@@ -118,6 +122,7 @@ def run_tuxtest_tests(self, haltmsg):
     def common_tuxrun(self,
                       kernel_asset,
                       rootfs_asset,
+                      accel=None,
                       dtb_asset=None,
                       drive="virtio-blk-device",
                       haltmsg="reboot: System halted",
@@ -130,7 +135,7 @@ def common_tuxrun(self,
         (kernel, disk, dtb) = self.fetch_tuxrun_assets(kernel_asset, rootfs_asset,
                                                        dtb_asset)
 
-        self.prepare_run(kernel, disk, drive, dtb, console_index)
+        self.prepare_run(accel, kernel, disk, drive, dtb, console_index)
         self.vm.launch()
         self.run_tuxtest_tests(haltmsg)
         os.remove(disk)
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 07/13] tests/functional: split x86_64 tuxrun into tcg and kvm run
  2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
                   ` (5 preceding siblings ...)
  2026-09-30 16:46 ` [PATCH 06/13] tests/functional: allow tuxrun tests to be passed "accel" Alex Bennée
@ 2026-09-30 16:46 ` Alex Bennée
  2026-10-01 11:18   ` marcandre.lureau
  2026-09-30 16:46 ` [PATCH 08/13] tests/functional: split aarch64 " Alex Bennée
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Michael S. Tsirkin, Paolo Bonzini

Add an explicit "kvm" run to the tuxrun tests. Although running on an
x86_64 host would probably have defaulted to "kvm" anyway we want to
exercise specific features later.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/functional/x86_64/test_tuxrun.py | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/tests/functional/x86_64/test_tuxrun.py b/tests/functional/x86_64/test_tuxrun.py
index fcbc62b1b0f..729f6447d05 100755
--- a/tests/functional/x86_64/test_tuxrun.py
+++ b/tests/functional/x86_64/test_tuxrun.py
@@ -24,13 +24,28 @@ class TuxRunX86Test(TuxRunBaselineTest):
         '4b8b2a99117519c5290e1202cb36eb6c7aaba92b357b5160f5970cf5fb78a751')
 
     def test_x86_64(self):
+        self.require_accelerator("tcg")
+
+        self.set_machine('q35')
+        self.cpu="Nehalem"
+        self.root='sda'
+        self.wait_for_shutdown=False
+        self.common_tuxrun(kernel_asset=self.ASSET_X86_64_KERNEL,
+                           rootfs_asset=self.ASSET_X86_64_ROOTFS,
+                           drive="driver=ide-hd,bus=ide.0,unit=0",
+                           accel="tcg")
+
+    def test_x86_64_kvm(self):
+        self.require_accelerator("kvm")
+
         self.set_machine('q35')
         self.cpu="Nehalem"
         self.root='sda'
         self.wait_for_shutdown=False
         self.common_tuxrun(kernel_asset=self.ASSET_X86_64_KERNEL,
                            rootfs_asset=self.ASSET_X86_64_ROOTFS,
-                           drive="driver=ide-hd,bus=ide.0,unit=0")
+                           drive="driver=ide-hd,bus=ide.0,unit=0",
+                           accel="kvm")
 
 if __name__ == '__main__':
     TuxRunBaselineTest.main()
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 08/13] tests/functional: split aarch64 tuxrun into tcg and kvm run
  2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
                   ` (6 preceding siblings ...)
  2026-09-30 16:46 ` [PATCH 07/13] tests/functional: split x86_64 tuxrun into tcg and kvm run Alex Bennée
@ 2026-09-30 16:46 ` Alex Bennée
  2026-10-01 11:18   ` marcandre.lureau
  2026-09-30 16:46 ` [PATCH 09/13] tests/functional: update x86_64 tuxrun images Alex Bennée
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, open list:Virt

Add an explicit "kvm" run to the tuxrun tests. Although running on an
aarch64 host would probably have defaulted to "kvm" anyway we want to
exercise specific features later.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/functional/aarch64/test_tuxrun.py | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/tests/functional/aarch64/test_tuxrun.py b/tests/functional/aarch64/test_tuxrun.py
index 7dd50c3de17..3870be8b6e3 100755
--- a/tests/functional/aarch64/test_tuxrun.py
+++ b/tests/functional/aarch64/test_tuxrun.py
@@ -32,6 +32,16 @@ def test_arm64(self):
         self.common_tuxrun(kernel_asset=self.ASSET_ARM64_KERNEL,
                            rootfs_asset=self.ASSET_ARM64_ROOTFS)
 
+    def test_arm64_kvm(self):
+        self.set_machine('virt')
+        self.require_accelerator('kvm')
+        self.cpu='cortex-a57'
+        self.console='ttyAMA0'
+        self.wait_for_shutdown=False
+        self.common_tuxrun(kernel_asset=self.ASSET_ARM64_KERNEL,
+                           rootfs_asset=self.ASSET_ARM64_ROOTFS,
+                           accel="kvm")
+
     ASSET_ARM64BE_KERNEL = Asset(
         'https://storage.tuxboot.com/buildroot/20241119/arm64be/Image',
         'fd6af4f16689d17a2c24fe0053cc212edcdf77abdcaf301800b8d38fa9f6e109')
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 09/13] tests/functional: update x86_64 tuxrun images
  2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
                   ` (7 preceding siblings ...)
  2026-09-30 16:46 ` [PATCH 08/13] tests/functional: split aarch64 " Alex Bennée
@ 2026-09-30 16:46 ` Alex Bennée
  2026-10-01 11:18   ` marcandre.lureau
  2026-09-30 16:46 ` [PATCH 10/13] tests/guest-debug: add --kargs option to run-test Alex Bennée
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Michael S. Tsirkin, Paolo Bonzini

We now split the fetching of the buildroot image from the kernel
itself. This is because we will want to access additional metadata in
future tests.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/functional/x86_64/test_tuxrun.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tests/functional/x86_64/test_tuxrun.py b/tests/functional/x86_64/test_tuxrun.py
index 729f6447d05..026b373accb 100755
--- a/tests/functional/x86_64/test_tuxrun.py
+++ b/tests/functional/x86_64/test_tuxrun.py
@@ -17,11 +17,11 @@
 class TuxRunX86Test(TuxRunBaselineTest):
 
     ASSET_X86_64_KERNEL = Asset(
-        'https://storage.tuxboot.com/buildroot/20241119/x86_64/bzImage',
-        'f57bfc6553bcd6e0a54aab86095bf642b33b5571d14e3af1731b18c87ed5aef8')
+        'https://storage.tuxboot.com/kernels/6.18.54/x86_64/bzImage',
+        '24a3ade610c2cc426ff821050de8a35930b0371357d94cc2c334abac6658552b')
     ASSET_X86_64_ROOTFS = Asset(
-        'https://storage.tuxboot.com/buildroot/20241119/x86_64/rootfs.ext4.zst',
-        '4b8b2a99117519c5290e1202cb36eb6c7aaba92b357b5160f5970cf5fb78a751')
+        'https://storage.tuxboot.com/buildroot/20260924/x86_64/rootfs.ext4.zst',
+        '8e310455b0244414ccff29c507f7ccfd4032e3587cc405e49ab0322738e3e27c')
 
     def test_x86_64(self):
         self.require_accelerator("tcg")
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 10/13] tests/guest-debug: add --kargs option to run-test
  2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
                   ` (8 preceding siblings ...)
  2026-09-30 16:46 ` [PATCH 09/13] tests/functional: update x86_64 tuxrun images Alex Bennée
@ 2026-09-30 16:46 ` Alex Bennée
  2026-10-01 11:18   ` marcandre.lureau
  2026-09-30 16:46 ` [PATCH 11/13] tests/guest-debug: add --symbols " Alex Bennée
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen

When passing kernel arguments to QEMU with --append we need to take
care that things are properly escaped. It's easier if we get the run
script to do it for us that constructed the nested escaped --qargs.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/guest-debug/run-test.py | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py
index 838c1c26971..4aa24939b7d 100755
--- a/tests/guest-debug/run-test.py
+++ b/tests/guest-debug/run-test.py
@@ -25,6 +25,7 @@ def get_args():
                         required=True)
     parser.add_argument("--qargs", help="Qemu arguments for test")
     parser.add_argument("--pargs", help="Program arguments for test")
+    parser.add_argument("--kargs", help="Kernel args to --append")
     parser.add_argument("--binary", help="Binary to debug",
                         required=True)
     parser.add_argument("--test", help="GDB test script")
@@ -82,6 +83,8 @@ def log(output, msg):
             suspend = ' -S'
         cmd = f'{args.qemu} {args.qargs} {args.binary}' \
             f'{suspend} -gdb unix:path={socket_name},server=on'
+        if args.kargs:
+            cmd += f" --append '{args.kargs}'"
         # There is no guest program command-line in system mode.
         assert not args.pargs
     else:
@@ -93,6 +96,8 @@ def log(output, msg):
             f' {args.binary}'
         if args.pargs:
             cmd += f' {args.pargs}'
+        # There are no appended args in user-mode
+        assert not args.kargs
 
     log(output, "QEMU CMD: %s" % (cmd))
     inferior = subprocess.Popen(shlex.split(cmd))
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 11/13] tests/guest-debug: add --symbols option to run-test
  2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
                   ` (9 preceding siblings ...)
  2026-09-30 16:46 ` [PATCH 10/13] tests/guest-debug: add --kargs option to run-test Alex Bennée
@ 2026-09-30 16:46 ` Alex Bennée
  2026-10-01 11:18   ` marcandre.lureau
  2026-09-30 16:46 ` [PATCH 12/13] tests/functional: teach tuxrun about launching gdb tests Alex Bennée
  2026-09-30 16:46 ` [PATCH 13/13] tests/functional: add tuxrun kvm gdb test for x86_64 Alex Bennée
  12 siblings, 1 reply; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen

Sometimes the debug symbols are not in the kernel binary image but in
a separate elf blob. Provide --symbols to facilitate using them.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/guest-debug/run-test.py | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py
index 4aa24939b7d..0c7cbd137ef 100755
--- a/tests/guest-debug/run-test.py
+++ b/tests/guest-debug/run-test.py
@@ -28,6 +28,7 @@ def get_args():
     parser.add_argument("--kargs", help="Kernel args to --append")
     parser.add_argument("--binary", help="Binary to debug",
                         required=True)
+    parser.add_argument("--symbols", help="Symbol file for binary to debug")
     parser.add_argument("--test", help="GDB test script")
     parser.add_argument('test_args', nargs='*',
                         help="Additional args for GDB test script. "
@@ -114,6 +115,10 @@ def log(output, msg):
     gdb_cmd += " -ex 'set confirm off'"
     # connect to remote
     gdb_cmd += " -ex 'target remote %s'" % (socket_name)
+
+    if args.symbols:
+        gdb_cmd += " -ex 'symbol-file %s'" % args.symbols
+
     # finally the test script itself
     if args.test:
         if args.test_args:
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 12/13] tests/functional: teach tuxrun about launching gdb tests
  2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
                   ` (10 preceding siblings ...)
  2026-09-30 16:46 ` [PATCH 11/13] tests/guest-debug: add --symbols " Alex Bennée
@ 2026-09-30 16:46 ` Alex Bennée
  2026-10-01 11:18   ` marcandre.lureau
  2026-09-30 16:46 ` [PATCH 13/13] tests/functional: add tuxrun kvm gdb test for x86_64 Alex Bennée
  12 siblings, 1 reply; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen

This resurrects the hand run test script from d84842be6c5 (tests:
remove test-gdbstub.py) and modernises it to use the shared test
infrastructure for run-test.

We then tweak the common tuxrun code to over an alternative "launch
via gdbstub" helper which reuses the existing code but:

  - needs a vmlinux with symbols
  - passes kargs directly
  - runs with the gdb run-test script
  - log the run-test output to the console log

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 .../functional/gdb-scripts/kernel_gdb_test.py | 157 ++++++++++++++++++
 tests/functional/qemu_test/tuxruntest.py      |  92 +++++++++-
 2 files changed, 240 insertions(+), 9 deletions(-)
 create mode 100644 tests/functional/gdb-scripts/kernel_gdb_test.py

diff --git a/tests/functional/gdb-scripts/kernel_gdb_test.py b/tests/functional/gdb-scripts/kernel_gdb_test.py
new file mode 100644
index 00000000000..5ca9aa43de3
--- /dev/null
+++ b/tests/functional/gdb-scripts/kernel_gdb_test.py
@@ -0,0 +1,157 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Generic Kernel GDB script to verify functionality:
+#  - Single-stepping
+#  - Hardware breakpoints
+#  - Software breakpoints
+#  - Watchpoints
+#
+# It relies on fairly common kernel points to break at and symbols for
+# the kernel. Address space randomisation (kaslr) needs to be disabled.
+#
+# Copyright (c) 2026 Linaro Limited
+#
+# Author:
+#  Alex Bennée <alex.bennee@linaro.org>
+#
+# This is launched by the tuxrun functional tests via tests/guest-debug/run-test.py
+
+import gdb
+from test_gdbstub import main, report
+
+failcount = 0
+
+
+def check_step():
+    "Step an instruction, check it moved."
+    start_pc = gdb.parse_and_eval('$pc')
+    gdb.execute("si")
+    end_pc = gdb.parse_and_eval('$pc')
+
+    return not (start_pc == end_pc)
+
+
+def check_break(sym_name):
+    "Setup breakpoint, continue and check we stopped."
+    sym, ok = gdb.lookup_symbol(sym_name)
+    bp = gdb.Breakpoint(sym_name)
+
+    gdb.execute("c")
+
+    # hopefully we came back
+    end_pc = gdb.parse_and_eval('$pc')
+    print ("%s == %s %d" % (end_pc, sym.value(), bp.hit_count))
+    bp.delete()
+
+    # can we test we hit bp?
+    return end_pc == sym.value()
+
+
+# We need to do hbreak manually as the python interface doesn't export it
+def check_hbreak(sym_name):
+    "Setup hardware breakpoint, continue and check we stopped."
+    sym, ok = gdb.lookup_symbol(sym_name)
+    gdb.execute("hbreak %s" % (sym_name))
+    gdb.execute("c")
+
+    # hopefully we came back
+    end_pc = gdb.parse_and_eval('$pc')
+    print ("%s == %s" % (end_pc, sym.value()))
+
+    if end_pc == sym.value():
+        gdb.execute("d 1")
+        return True
+    else:
+        return False
+
+
+class WatchPoint(gdb.Breakpoint):
+
+    def get_wpstr(self, sym_name):
+        "Setup sym and wp_str for given symbol."
+        self.sym, ok = gdb.lookup_symbol(sym_name)
+        wp_addr = gdb.parse_and_eval(sym_name).address
+        self.wp_str = '*(%(type)s)(&%(address)s)' % dict(
+            type = wp_addr.type, address = sym_name)
+
+        return(self.wp_str)
+
+    def __init__(self, sym_name, type):
+        wp_str = self.get_wpstr(sym_name)
+        super(WatchPoint, self).__init__(wp_str, gdb.BP_WATCHPOINT, type)
+
+    def stop(self):
+        end_pc = gdb.parse_and_eval('$pc')
+        print ("HIT WP @ %s" % (end_pc))
+        return True
+
+
+def do_one_watch(sym, wtype, text):
+
+    wp = WatchPoint(sym, wtype)
+    gdb.execute("c")
+    report_str = "%s for %s (%s)" % (text, sym, wp.sym.value())
+
+    if wp.hit_count > 0:
+        report(True, report_str)
+        wp.delete()
+    else:
+        report(False, report_str)
+
+
+def check_watches(sym_name):
+    "Watch a symbol for any access."
+
+    # Should hit for any read
+    do_one_watch(sym_name, gdb.WP_ACCESS, "awatch")
+
+    # Again should hit for reads
+    do_one_watch(sym_name, gdb.WP_READ, "rwatch")
+
+    # Finally when it is written
+    do_one_watch(sym_name, gdb.WP_WRITE, "watch")
+
+
+class CatchBreakpoint(gdb.Breakpoint):
+    def __init__(self, sym_name):
+        super(CatchBreakpoint, self).__init__(sym_name)
+        self.sym, ok = gdb.lookup_symbol(sym_name)
+
+    def stop(self):
+        end_pc = gdb.parse_and_eval('$pc')
+        print ("CB: %s == %s" % (end_pc, self.sym.value()))
+        if end_pc == self.sym.value():
+            report(False, "Hit final catchpoint")
+
+
+def run_test():
+    "Run through the tests one by one"
+
+    print ("Checking we can step the first few instructions")
+    step_ok = 0
+    for i in range(3):
+        if check_step():
+            step_ok += 1
+
+    report(step_ok == 3, "single step in boot code")
+
+    print ("Checking HW breakpoint works")
+    break_ok = check_hbreak("kernel_init")
+    report(break_ok, "hbreak @ kernel_init")
+
+    # Can't set this up until we are in the kernel proper
+    # if we make it to run_init_process we've over-run and
+    # one of the tests failed
+    print ("Setup catch-all for run_init_process")
+    cbp = CatchBreakpoint("run_init_process")
+    cpb2 = CatchBreakpoint("try_to_run_init_process")
+
+    print ("Checking Normal breakpoint works")
+    break_ok = check_break("wait_for_completion")
+    report(break_ok, "break @ wait_for_completion")
+
+    print ("Checking watchpoint works")
+    check_watches("system_state")
+
+
+main(run_test)
diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py
index ca1589fea37..e6b32fbcab2 100644
--- a/tests/functional/qemu_test/tuxruntest.py
+++ b/tests/functional/qemu_test/tuxruntest.py
@@ -9,7 +9,9 @@
 #
 # SPDX-License-Identifier: GPL-2.0-or-later
 
+import logging
 import os
+import subprocess
 
 from qemu_test import QemuSystemTest
 from qemu_test import exec_command_and_wait_for_pattern
@@ -18,7 +20,7 @@
 
 class TuxRunBaselineTest(QemuSystemTest):
 
-    KERNEL_COMMON_COMMAND_LINE = 'printk.time=0'
+    KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 nokaslr'
     # Tests are ~10-40s, allow for --debug/--enable-gcov overhead
     timeout = 100
 
@@ -55,17 +57,20 @@ def wait_for_console_pattern(self, success_message, vm=None):
                                  failure_message='Kernel panic - not syncing',
                                  vm=vm)
 
-    def fetch_tuxrun_assets(self, kernel_asset, rootfs_asset, dtb_asset=None):
+    def fetch_tuxrun_assets(self, kernel_asset, rootfs_asset,
+                            dtb_asset=None, vmlinux_asset=None):
         """
         Fetch the TuxBoot assets.
         """
         kernel_image =  kernel_asset.fetch()
         disk_image = self.uncompress(rootfs_asset)
         dtb = dtb_asset.fetch() if dtb_asset is not None else None
+        vmlinux = self.uncompress(vmlinux_asset) if vmlinux_asset is not None else None
 
-        return (kernel_image, disk_image, dtb)
+        return (kernel_image, disk_image, dtb, vmlinux)
 
-    def prepare_run(self, accel, kernel, disk, drive, dtb=None, console_index=0):
+    def prepare_run(self, accel, kernel, disk, drive,
+                    dtb=None, console_index=0, append = True):
         """
         Setup to run and add the common parameters to the system
         """
@@ -83,9 +88,15 @@ def prepare_run(self, accel, kernel, disk, drive, dtb=None, console_index=0):
         if accel:
             self.vm.add_args('-accel', accel)
 
-        self.vm.add_args('-kernel', kernel,
-                         '-append', self.kcmd_line,
-                         '-blockdev', blockdev)
+        if kernel:
+            self.vm.add_args('-kernel', kernel)
+
+        # When using the gdb run script we might not want to include
+        # the kcmd line directly in the QEMU args.
+        if append:
+            self.vm.add_args('-append', self.kcmd_line)
+
+        self.vm.add_args('-blockdev', blockdev)
 
         # Sometimes we need extra devices attached
         if self.extradev:
@@ -132,10 +143,73 @@ def common_tuxrun(self,
         special with the command line we can process most things using
         the tag metadata.
         """
-        (kernel, disk, dtb) = self.fetch_tuxrun_assets(kernel_asset, rootfs_asset,
-                                                       dtb_asset)
+        (kernel, disk, dtb, _) = self.fetch_tuxrun_assets(kernel_asset,
+                                                          rootfs_asset,
+                                                          dtb_asset)
 
         self.prepare_run(accel, kernel, disk, drive, dtb, console_index)
         self.vm.launch()
         self.run_tuxtest_tests(haltmsg)
         os.remove(disk)
+
+    def common_tuxrun_gdb(self,
+                          kernel_asset,
+                          vmlinux_asset,
+                          rootfs_asset,
+                          accel=None,
+                          dtb_asset=None,
+                          drive="virtio-blk-device",
+                          haltmsg="reboot: System halted",
+                          console_index=0):
+        """
+        Common path for LKFT tests under gdb. Unlike the common_tuxrun
+        function we need to launch with the gdb test script and deal
+        with munging the arguments for that especially.
+        """
+        (kernel, disk, dtb, vmlinux) = self.fetch_tuxrun_assets(kernel_asset,
+                                                                rootfs_asset,
+                                                                dtb_asset,
+                                                                vmlinux_asset)
+
+        gdb_path = os.getenv("QEMU_TEST_GDB")
+        run_script = self.data_file('..', 'guest-debug','run-test.py')
+        test_script = self.data_file('gdb-scripts', 'kernel_gdb_test.py')
+
+        # Instead of launching QEMU via the functional test machinery
+        # we need to launch it with the gdb run script. We utilise the
+        # existing prepare_run machinery to build the command line but
+        # we pass the kernel args separately to avoid horrible string
+        # escaping.
+
+        self.prepare_run(accel, kernel, disk, drive, dtb,
+                         console_index, append = False)
+
+        # the functional test machinery adds more stuff for handling
+        # console redirection which we need to do manually.
+
+        qargs = self.vm.args
+        qargs.extend(["-display", "none", "-serial", "stdio"])
+
+        cmd = [
+            str(run_script),
+            "--qemu", self.qemu_bin,
+            "--qargs", " ".join(qargs),
+            "--kargs", self.kcmd_line,
+            "--binary", "",
+            "--symbols", str(vmlinux),
+            "--test", str(test_script),
+            "--gdb", gdb_path,
+        ]
+
+        self.log.info(f"run-test: {' '.join(cmd)}")
+
+        res = subprocess.run(cmd, text=True,
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.STDOUT)
+
+        if res.stdout:
+            console_logger = logging.getLogger('console')
+            console_logger.info(res.stdout)
+
+        self.assertEqual(res.returncode, 0,
+                         f"run-test.py failed ({res.returncode}):\n")
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 13/13] tests/functional: add tuxrun kvm gdb test for x86_64
  2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
                   ` (11 preceding siblings ...)
  2026-09-30 16:46 ` [PATCH 12/13] tests/functional: teach tuxrun about launching gdb tests Alex Bennée
@ 2026-09-30 16:46 ` Alex Bennée
  2026-10-01 11:18   ` marcandre.lureau
  12 siblings, 1 reply; 28+ messages in thread
From: Alex Bennée @ 2026-09-30 16:46 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh, Alex Bennée,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Michael S. Tsirkin, Paolo Bonzini

With all the bits in place we can now exercise the KVM gdb interfaces.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/functional/x86_64/test_tuxrun.py | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/tests/functional/x86_64/test_tuxrun.py b/tests/functional/x86_64/test_tuxrun.py
index 026b373accb..1a1138d16ae 100755
--- a/tests/functional/x86_64/test_tuxrun.py
+++ b/tests/functional/x86_64/test_tuxrun.py
@@ -11,7 +11,7 @@
 #
 # SPDX-License-Identifier: GPL-2.0-or-later
 
-from qemu_test import Asset
+from qemu_test import Asset, skipIfMissingEnv
 from qemu_test.tuxruntest import TuxRunBaselineTest
 
 class TuxRunX86Test(TuxRunBaselineTest):
@@ -19,6 +19,9 @@ class TuxRunX86Test(TuxRunBaselineTest):
     ASSET_X86_64_KERNEL = Asset(
         'https://storage.tuxboot.com/kernels/6.18.54/x86_64/bzImage',
         '24a3ade610c2cc426ff821050de8a35930b0371357d94cc2c334abac6658552b')
+    ASSET_X86_64_VMLINUX = Asset(
+        'https://storage.tuxboot.com/kernels/6.18.54/x86_64/vmlinux.xz',
+        '77bf44cca48c9c1b9c142e16a2311d58b8ae3462b61bce44bcaf9243b5f26628')
     ASSET_X86_64_ROOTFS = Asset(
         'https://storage.tuxboot.com/buildroot/20260924/x86_64/rootfs.ext4.zst',
         '8e310455b0244414ccff29c507f7ccfd4032e3587cc405e49ab0322738e3e27c')
@@ -47,5 +50,20 @@ def test_x86_64_kvm(self):
                            drive="driver=ide-hd,bus=ide.0,unit=0",
                            accel="kvm")
 
+    @skipIfMissingEnv("QEMU_TEST_GDB")
+    def test_x86_64_kvm_gdb(self):
+        self.require_accelerator("kvm")
+
+        self.set_machine('q35')
+        self.cpu="Nehalem"
+        self.root='sda'
+        self.wait_for_shutdown=False
+        self.common_tuxrun_gdb(kernel_asset=self.ASSET_X86_64_KERNEL,
+                               vmlinux_asset=self.ASSET_X86_64_VMLINUX,
+                               rootfs_asset=self.ASSET_X86_64_ROOTFS,
+                               drive="driver=ide-hd,bus=ide.0,unit=0",
+                               accel="kvm")
+
+
 if __name__ == '__main__':
     TuxRunBaselineTest.main()
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH 04/13] meson: move gdb detection into the top level build file
  2026-09-30 16:46 ` [PATCH 04/13] meson: move gdb detection into the top level build file Alex Bennée
@ 2026-09-30 18:20   ` Pierrick Bouvier
  2026-10-01 11:18   ` marcandre.lureau
  1 sibling, 0 replies; 28+ messages in thread
From: Pierrick Bouvier @ 2026-09-30 18:20 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel
  Cc: Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Brian Cain, Klaus Jensen,
	Paolo Bonzini

On 9/30/26 9:46 AM, Alex Bennée wrote:
> Currently gdb is only used by TCG based tests but hypervisors want to
> use gdbstub too. To be able to test this case we need to always probe
> and report the gdb we have.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>   meson.build                  | 15 +++++++--------
>   tests/functional/meson.build |  5 ++---
>   tests/tcg/meson.build        |  5 -----
>   3 files changed, 9 insertions(+), 16 deletions(-)
> 

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 01/13] tests/functional: test_acpi_bits requires TCG
  2026-09-30 16:46 ` [PATCH 01/13] tests/functional: test_acpi_bits requires TCG Alex Bennée
@ 2026-10-01 11:18   ` marcandre.lureau
  0 siblings, 0 replies; 28+ messages in thread
From: marcandre.lureau @ 2026-10-01 11:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Michael S. Tsirkin, Paolo Bonzini

On Wed, 30 Sep 2026 17:46:37 +0100, Alex Bennée <alex.bennee@linaro.org> wrote:
> Running a full thorough test suite on a KVM-only build fails due to
> acpi bits needing icount, therefor tcg. Declare the restriction so the
> test harness can skip it.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Marc-André Lureau <marcandre.lureau@redhat.com>



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 07/13] tests/functional: split x86_64 tuxrun into tcg and kvm run
  2026-09-30 16:46 ` [PATCH 07/13] tests/functional: split x86_64 tuxrun into tcg and kvm run Alex Bennée
@ 2026-10-01 11:18   ` marcandre.lureau
  0 siblings, 0 replies; 28+ messages in thread
From: marcandre.lureau @ 2026-10-01 11:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Michael S. Tsirkin, Paolo Bonzini

On Wed, 30 Sep 2026 17:46:43 +0100, Alex Bennée <alex.bennee@linaro.org> wrote:
> Add an explicit "kvm" run to the tuxrun tests. Although running on an
> x86_64 host would probably have defaulted to "kvm" anyway we want to
> exercise specific features later.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Marc-André Lureau <marcandre.lureau@redhat.com>



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 06/13] tests/functional: allow tuxrun tests to be passed "accel"
  2026-09-30 16:46 ` [PATCH 06/13] tests/functional: allow tuxrun tests to be passed "accel" Alex Bennée
@ 2026-10-01 11:18   ` marcandre.lureau
  0 siblings, 0 replies; 28+ messages in thread
From: marcandre.lureau @ 2026-10-01 11:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen

> For some tests we are about to add we want the flexibility to force
> "kvm" so give them that ability.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Message-ID: <20260930164649.433573-7-alex.bennee@linaro.org>
>
> diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py
> index 6c442ff0dc43..ca1589fea37d 100644
> --- a/tests/functional/qemu_test/tuxruntest.py
> +++ b/tests/functional/qemu_test/tuxruntest.py
> @@ -65,7 +65,7 @@ def fetch_tuxrun_assets(self, kernel_asset, rootfs_asset, dtb_asset=None):
>  
>          return (kernel_image, disk_image, dtb)
>  
> -    def prepare_run(self, kernel, disk, drive, dtb=None, console_index=0):
> +    def prepare_run(self, accel, kernel, disk, drive, dtb=None, console_index=0):

This breaks the direct caller in tests/functional/sh4/test_tuxrun.py
which passes kernel as the first positional argument.

-- 
Marc-André Lureau <marcandre.lureau@redhat.com>



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 03/13] tests/tcg: fix buffer overflow in multiarch/linux/linux-sigrtminmax
  2026-09-30 16:46 ` [PATCH 03/13] tests/tcg: fix buffer overflow in multiarch/linux/linux-sigrtminmax Alex Bennée
@ 2026-10-01 11:18   ` marcandre.lureau
  0 siblings, 0 replies; 28+ messages in thread
From: marcandre.lureau @ 2026-10-01 11:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Max Filippov

On Wed, 30 Sep 2026 17:46:39 +0100, Alex Bennée <alex.bennee@linaro.org> wrote:
> Fix new_argv allocation size to be `(argc + 2) * sizeof(char *)` bytes,
> which matches the way it's used to store `argc + 2` pointers.
> 
> This fixes the test for me, which otherwise fails on xtensa with the
> following message
> 
>   linux-sigrtminmax.c: 59: main: Assertion `execve(new_argv[0], new_argv, environ) == 0' failed.'.
> 
> [...]

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Marc-André Lureau <marcandre.lureau@redhat.com>



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 05/13] tests/functional: add basic gdbstub test for KVM
  2026-09-30 16:46 ` [PATCH 05/13] tests/functional: add basic gdbstub test for KVM Alex Bennée
@ 2026-10-01 11:18   ` marcandre.lureau
  2026-10-02  9:46     ` Alex Bennée
  0 siblings, 1 reply; 28+ messages in thread
From: marcandre.lureau @ 2026-10-01 11:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Paolo Bonzini

> We don't really exercise the KVM bits of gdbstub very much as the TCG
> tests are TCG only and the ones in functional tests are focused on
> record/replay and reverse debugging.
> 
> Add a basic gdbstub test case which uses heuristics to single step
> through the default firmware of guests and kick the tyres and check
> things are working as expected.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> 
> Message-ID: <20260930164649.433573-6-alex.bennee@linaro.org>
>
> diff --git a/tests/functional/gdb-scripts/kvm_fw_gdb_test.py b/tests/functional/gdb-scripts/kvm_fw_gdb_test.py
> new file mode 100644
> index 000000000000..b38b874dc586
> --- /dev/null
> +++ b/tests/functional/gdb-scripts/kvm_fw_gdb_test.py
> @@ -0,0 +1,119 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# Generic GDB script to verify gdbstub functionality on guest firmware:
> +#  - Single-stepping across VM-exits
> +#  - Placing a hardware breakpoint at a branch or ahead in disassembly
> +#  - Continuing to the breakpoint and validating that registers changed
> +#
> +# Copyright (c) 2026 Linaro Limited
> +#
> +# Author:
> +#  Alex Bennée <alex.bennee@linaro.org>
> +
> +import gdb
> +from test_gdbstub import main, report
> +
> +def parse_registers():
> +    """Parse 'info registers' into a name -> value dictionary."""
> +    regs = {}
> +    for line in gdb.execute("info registers", to_string=True).splitlines():
> +        parts = line.split()
> +        if len(parts) >= 2:
> +            regs[parts[0]] = parts[1]
> +    return regs
> +
> +def test_single_step():
> +    """
> +    Single-step a few instructions and verify PC advances
> +    """
> +    current_pc = int(gdb.parse_and_eval("$pc"))
> +    for step in range(1, 6):
> +        gdb.execute("stepi")
> +        gdb.execute("x/3i $pc")
> +        pc = int(gdb.parse_and_eval("$pc"))
> +        report(pc != current_pc, f"single-step {step} advanced pc")
> +        current_pc = pc
> +
> +
> +def might_be_jump(asm):
> +    """
> +    Return true if the assembly string might contain a branch/jump instruction
> +    """
> +    branch_keywords = {
> +        "jmp", "b", "bl", "bx", "bne", "beq", "bgt", "blt", "bge", "ble",
> +        "call", "ret", "br", "jal", "jalr", "bc", "bctrl", "j"
> +    }


Do you plan to make this per-architecture? It doesn't cover x86 conditional jumps.

> +
> +    parts = asm.split()
> +    if not parts:
> +        return False
> +    mnemonic = parts[0].lower()
> +    return mnemonic in branch_keywords
> +
> +
> +def test_hw_bkpt():
> +    """
> +    Set a hwbkpt somewhere in the future.
> +    """
> +
> +    # FIXME - this is fragile
> +    disas = gdb.execute("x/10i $pc", to_string=True)
> +    lines = disas.strip().splitlines()
> +    insns = 0
> +    bp = None
> +
> +    for line in lines:
> +        clean = line.lstrip("=>").strip()
> +        parts = clean.split(":", 1)
> +        if len(parts) < 2 or not parts[1].strip():
> +            continue
> +        insns += 1
> +
> +        if might_be_jump(parts[1]):
> +            # jump too close, bail out?
> +            if insns < 2:
> +                report(False, "found jump far enough away")
> +                return
> +            else:
> +                addr = int(parts[0].split()[0], 16)
> +                bp = gdb.Breakpoint(f"*{hex(addr)}",
> +                                    type=gdb.BP_HARDWARE_BREAKPOINT)
> +                break
> +        elif insns == 10:
> +            addr = int(parts[0].split()[0], 16)
> +            bp = gdb.Breakpoint(f"*{hex(addr)}",
> +                                type=gdb.BP_HARDWARE_BREAKPOINT)
> +            break
> +
> +    report(bp is not None, f"set hwbkpt @ {bp.location}")

Maybe to make debugging easier:

  if bp is None:
      report(False, "failed to set hwbkpt (no suitable instruction found)")
      return
  report(True, f"set hwbkpt @ {bp.location}")

> +    gdb.execute("continue")
> +
> +    end_pc = gdb.parse_and_eval('$pc')
> +    report(bp.hit_count == 1,
> +           "break @ %s (%d hits)" % (end_pc, bp.hit_count))
> +
> +    bp.delete()
> +    return
> +
> +def test_reg_updates(regs_start):
> +    regs_end = parse_registers()
> +
> +    changed = [k for k in regs_start
> +               if k in regs_end and regs_start[k] != regs_end[k]]
> +
> +    report(len(changed) > 0, f"{len(changed)} registers changed.")
> +
> +def run_test():
> +    regs_start = parse_registers()
> +
> +    test_single_step()
> +
> +    # skip any pesky mode switching code
> +    gdb.execute("stepi 50")
> +
> +    test_hw_bkpt()
> +
> +    test_reg_updates(regs_start)
> +
> +
> +main(run_test)
> diff --git a/tests/functional/x86_64/meson.build b/tests/functional/x86_64/meson.build
> index 0353b2af8e1d..080e12ddef13 100644
> --- a/tests/functional/x86_64/meson.build
> +++ b/tests/functional/x86_64/meson.build
> @@ -13,6 +13,7 @@ tests_x86_64_system_quick = [
>    'bad_vmstate',
>    'cpu_model_versions',
>    'cpu_queries',
> +  'kvm_gdbstub',
>    'mem_addr_space',
>    'migration',
>    'pc_cpu_hotplug_props',
> diff --git a/tests/functional/x86_64/test_kvm_gdbstub.py b/tests/functional/x86_64/test_kvm_gdbstub.py
> new file mode 100755
> index 000000000000..26876c3dc580
> --- /dev/null
> +++ b/tests/functional/x86_64/test_kvm_gdbstub.py
> @@ -0,0 +1,55 @@
> +#!/usr/bin/env python3
> +#
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# Functional test verifying KVM gdbstub operations on firmware:
> +#  - Single-stepping across VM-exits
> +#  - Register sampling across execution steps
> +#  - Hardware breakpoint at branch destination or instruction
> +#
> +# Copyright (c) 2026 Linaro Limited
> +#
> +# Author:
> +#  Alex Bennée <alex.bennee@linaro.org>
> +
> +import os
> +import subprocess
> +from pathlib import Path
> +from qemu_test import QemuSystemTest, skipIfMissingEnv
> +
> +
> +class KvmGdbstubTest(QemuSystemTest):
> +
> +    @skipIfMissingEnv("QEMU_TEST_GDB")
> +    def test_x86_64_kvm_fw_gdb(self):
> +        self.require_accelerator("kvm")
> +
> +        gdb_path = os.getenv("QEMU_TEST_GDB")
> +
> +        tests_dir = Path(__file__).resolve().parents[2]
> +        run_test = tests_dir / "guest-debug" / "run-test.py"
> +        gdb_script = (tests_dir / "functional" / "gdb-scripts" /
> +                      "kvm_fw_gdb_test.py")
> +
> +        qargs = "-machine pc -accel kvm -cpu host -smp 1 -m 512M -display none"
> +        cmd = [
> +            str(run_test),
> +            "--qemu", self.qemu_bin,
> +            "--qargs", qargs,
> +            "--binary", "",
> +            "--test", str(gdb_script),
> +            "--gdb", gdb_path,
> +        ]
> +
> +        res = subprocess.run(cmd, text=True,
> +                             stdout=subprocess.PIPE,
> +                             stderr=subprocess.STDOUT)
> +        if res.stdout:
> +            self.log.info('run-test.py: %s', res.stdout)
> +
> +        self.assertEqual(res.returncode, 0,
> +                         f"run-test.py failed ({res.returncode}):\n")
> +
> +
> +if __name__ == '__main__':
> +    QemuSystemTest.main()

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Marc-André Lureau <marcandre.lureau@redhat.com>



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 08/13] tests/functional: split aarch64 tuxrun into tcg and kvm run
  2026-09-30 16:46 ` [PATCH 08/13] tests/functional: split aarch64 " Alex Bennée
@ 2026-10-01 11:18   ` marcandre.lureau
  0 siblings, 0 replies; 28+ messages in thread
From: marcandre.lureau @ 2026-10-01 11:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, qemu-arm

On Wed, 30 Sep 2026 17:46:44 +0100, Alex Bennée <alex.bennee@linaro.org> wrote:
> Add an explicit "kvm" run to the tuxrun tests. Although running on an
> aarch64 host would probably have defaulted to "kvm" anyway we want to
> exercise specific features later.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Marc-André Lureau <marcandre.lureau@redhat.com>



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 04/13] meson: move gdb detection into the top level build file
  2026-09-30 16:46 ` [PATCH 04/13] meson: move gdb detection into the top level build file Alex Bennée
  2026-09-30 18:20   ` Pierrick Bouvier
@ 2026-10-01 11:18   ` marcandre.lureau
  1 sibling, 0 replies; 28+ messages in thread
From: marcandre.lureau @ 2026-10-01 11:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Paolo Bonzini

On Wed, 30 Sep 2026 17:46:40 +0100, Alex Bennée <alex.bennee@linaro.org> wrote:
> Currently gdb is only used by TCG based tests but hypervisors want to
> use gdbstub too. To be able to test this case we need to always probe
> and report the gdb we have.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Marc-André Lureau <marcandre.lureau@redhat.com>



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 09/13] tests/functional: update x86_64 tuxrun images
  2026-09-30 16:46 ` [PATCH 09/13] tests/functional: update x86_64 tuxrun images Alex Bennée
@ 2026-10-01 11:18   ` marcandre.lureau
  0 siblings, 0 replies; 28+ messages in thread
From: marcandre.lureau @ 2026-10-01 11:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Michael S. Tsirkin, Paolo Bonzini

On Wed, 30 Sep 2026 17:46:45 +0100, Alex Bennée <alex.bennee@linaro.org> wrote:
> We now split the fetching of the buildroot image from the kernel
> itself. This is because we will want to access additional metadata in
> future tests.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Marc-André Lureau <marcandre.lureau@redhat.com>



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 10/13] tests/guest-debug: add --kargs option to run-test
  2026-09-30 16:46 ` [PATCH 10/13] tests/guest-debug: add --kargs option to run-test Alex Bennée
@ 2026-10-01 11:18   ` marcandre.lureau
  0 siblings, 0 replies; 28+ messages in thread
From: marcandre.lureau @ 2026-10-01 11:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen

On Wed, 30 Sep 2026 17:46:46 +0100, Alex Bennée <alex.bennee@linaro.org> wrote:
> When passing kernel arguments to QEMU with --append we need to take
> care that things are properly escaped. It's easier if we get the run
> script to do it for us that constructed the nested escaped --qargs.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Marc-André Lureau <marcandre.lureau@redhat.com>



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 11/13] tests/guest-debug: add --symbols option to run-test
  2026-09-30 16:46 ` [PATCH 11/13] tests/guest-debug: add --symbols " Alex Bennée
@ 2026-10-01 11:18   ` marcandre.lureau
  0 siblings, 0 replies; 28+ messages in thread
From: marcandre.lureau @ 2026-10-01 11:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen

On Wed, 30 Sep 2026 17:46:47 +0100, Alex Bennée <alex.bennee@linaro.org> wrote:
> Sometimes the debug symbols are not in the kernel binary image but in
> a separate elf blob. Provide --symbols to facilitate using them.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Marc-André Lureau <marcandre.lureau@redhat.com>



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 12/13] tests/functional: teach tuxrun about launching gdb tests
  2026-09-30 16:46 ` [PATCH 12/13] tests/functional: teach tuxrun about launching gdb tests Alex Bennée
@ 2026-10-01 11:18   ` marcandre.lureau
  0 siblings, 0 replies; 28+ messages in thread
From: marcandre.lureau @ 2026-10-01 11:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen

> This resurrects the hand run test script from d84842be6c5 (tests:
> remove test-gdbstub.py) and modernises it to use the shared test
> infrastructure for run-test.
> 
> We then tweak the common tuxrun code to over an alternative "launch
> via gdbstub" helper which reuses the existing code but:
> 
>   - needs a vmlinux with symbols
>   - passes kargs directly
>   - runs with the gdb run-test script
>   - log the run-test output to the console log
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Message-ID: <20260930164649.433573-13-alex.bennee@linaro.org>
>
> diff --git a/tests/functional/gdb-scripts/kernel_gdb_test.py b/tests/functional/gdb-scripts/kernel_gdb_test.py
> new file mode 100644
> index 000000000000..5ca9aa43de3c
> --- /dev/null
> +++ b/tests/functional/gdb-scripts/kernel_gdb_test.py
> @@ -0,0 +1,157 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# Generic Kernel GDB script to verify functionality:
> +#  - Single-stepping
> +#  - Hardware breakpoints
> +#  - Software breakpoints
> +#  - Watchpoints
> +#
> +# It relies on fairly common kernel points to break at and symbols for
> +# the kernel. Address space randomisation (kaslr) needs to be disabled.
> +#
> +# Copyright (c) 2026 Linaro Limited
> +#
> +# Author:
> +#  Alex Bennée <alex.bennee@linaro.org>
> +#
> +# This is launched by the tuxrun functional tests via tests/guest-debug/run-test.py
> +
> +import gdb
> +from test_gdbstub import main, report
> +
> +failcount = 0
> +
> +
> +def check_step():
> +    "Step an instruction, check it moved."
> +    start_pc = gdb.parse_and_eval('$pc')
> +    gdb.execute("si")
> +    end_pc = gdb.parse_and_eval('$pc')
> +
> +    return not (start_pc == end_pc)
> +
> +
> +def check_break(sym_name):
> +    "Setup breakpoint, continue and check we stopped."
> +    sym, ok = gdb.lookup_symbol(sym_name)
> +    bp = gdb.Breakpoint(sym_name)
> +
> +    gdb.execute("c")
> +
> +    # hopefully we came back
> +    end_pc = gdb.parse_and_eval('$pc')
> +    print ("%s == %s %d" % (end_pc, sym.value(), bp.hit_count))
> +    bp.delete()
> +
> +    # can we test we hit bp?
> +    return end_pc == sym.value()
> +
> +
> +# We need to do hbreak manually as the python interface doesn't export it
> +def check_hbreak(sym_name):
> +    "Setup hardware breakpoint, continue and check we stopped."
> +    sym, ok = gdb.lookup_symbol(sym_name)
> +    gdb.execute("hbreak %s" % (sym_name))
> +    gdb.execute("c")
> +
> +    # hopefully we came back
> +    end_pc = gdb.parse_and_eval('$pc')
> +    print ("%s == %s" % (end_pc, sym.value()))
> +
> +    if end_pc == sym.value():
> +        gdb.execute("d 1")

It may be worth to use gdb.Breakpoint() which gives a proper object with
.delete() instead.

> +        return True
> +    else:
> +        return False
> +
> +
> +class WatchPoint(gdb.Breakpoint):
> +
> +    def get_wpstr(self, sym_name):
> +        "Setup sym and wp_str for given symbol."
> +        self.sym, ok = gdb.lookup_symbol(sym_name)
> +        wp_addr = gdb.parse_and_eval(sym_name).address
> +        self.wp_str = '*(%(type)s)(&%(address)s)' % dict(
> +            type = wp_addr.type, address = sym_name)
> +
> +        return(self.wp_str)
> +
> +    def __init__(self, sym_name, type):
> +        wp_str = self.get_wpstr(sym_name)
> +        super(WatchPoint, self).__init__(wp_str, gdb.BP_WATCHPOINT, type)
> +
> +    def stop(self):
> +        end_pc = gdb.parse_and_eval('$pc')
> +        print ("HIT WP @ %s" % (end_pc))
> +        return True
> +
> +
> +def do_one_watch(sym, wtype, text):
> +
> +    wp = WatchPoint(sym, wtype)
> +    gdb.execute("c")
> +    report_str = "%s for %s (%s)" % (text, sym, wp.sym.value())
> +
> +    if wp.hit_count > 0:
> +        report(True, report_str)
> +        wp.delete()
> +    else:
> +        report(False, report_str)
> +
> +
> +def check_watches(sym_name):
> +    "Watch a symbol for any access."
> +
> +    # Should hit for any read
> +    do_one_watch(sym_name, gdb.WP_ACCESS, "awatch")
> +
> +    # Again should hit for reads
> +    do_one_watch(sym_name, gdb.WP_READ, "rwatch")
> +
> +    # Finally when it is written
> +    do_one_watch(sym_name, gdb.WP_WRITE, "watch")
> +
> +
> +class CatchBreakpoint(gdb.Breakpoint):
> +    def __init__(self, sym_name):
> +        super(CatchBreakpoint, self).__init__(sym_name)
> +        self.sym, ok = gdb.lookup_symbol(sym_name)
> +
> +    def stop(self):
> +        end_pc = gdb.parse_and_eval('$pc')
> +        print ("CB: %s == %s" % (end_pc, self.sym.value()))
> +        if end_pc == self.sym.value():
> +            report(False, "Hit final catchpoint")
> +
> +
> +def run_test():
> +    "Run through the tests one by one"
> +
> +    print ("Checking we can step the first few instructions")
> +    step_ok = 0
> +    for i in range(3):
> +        if check_step():
> +            step_ok += 1
> +
> +    report(step_ok == 3, "single step in boot code")
> +
> +    print ("Checking HW breakpoint works")
> +    break_ok = check_hbreak("kernel_init")
> +    report(break_ok, "hbreak @ kernel_init")
> +
> +    # Can't set this up until we are in the kernel proper
> +    # if we make it to run_init_process we've over-run and
> +    # one of the tests failed
> +    print ("Setup catch-all for run_init_process")
> +    cbp = CatchBreakpoint("run_init_process")
> +    cpb2 = CatchBreakpoint("try_to_run_init_process")


cbp2 ?

> +
> +    print ("Checking Normal breakpoint works")
> +    break_ok = check_break("wait_for_completion")
> +    report(break_ok, "break @ wait_for_completion")
> +
> +    print ("Checking watchpoint works")
> +    check_watches("system_state")
> +
> +
> +main(run_test)
> diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py
> index ca1589fea37d..e6b32fbcab26 100644
> --- a/tests/functional/qemu_test/tuxruntest.py
> +++ b/tests/functional/qemu_test/tuxruntest.py
> @@ -9,7 +9,9 @@
>  #
>  # SPDX-License-Identifier: GPL-2.0-or-later
>  
> +import logging
>  import os
> +import subprocess
>  
>  from qemu_test import QemuSystemTest
>  from qemu_test import exec_command_and_wait_for_pattern
> @@ -18,7 +20,7 @@
>  
>  class TuxRunBaselineTest(QemuSystemTest):
>  
> -    KERNEL_COMMON_COMMAND_LINE = 'printk.time=0'
> +    KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 nokaslr'

This affects every tuxrun test, worth to mention in commit message.
Or adjust the test to limit the scope

-- 
Marc-André Lureau <marcandre.lureau@redhat.com>



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 13/13] tests/functional: add tuxrun kvm gdb test for x86_64
  2026-09-30 16:46 ` [PATCH 13/13] tests/functional: add tuxrun kvm gdb test for x86_64 Alex Bennée
@ 2026-10-01 11:18   ` marcandre.lureau
  0 siblings, 0 replies; 28+ messages in thread
From: marcandre.lureau @ 2026-10-01 11:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: qemu-devel, Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Marc-André Lureau, Richard Henderson, John Snow, Keith Busch,
	Cornelia Huck, Thomas Huth, Zhao Liu, Peter Maydell,
	Laurent Vivier, Brad Smith, Peter Xu, Daniel P. Berrangé,
	Ilya Leoshkevich, Matthew Rosato, Philippe Mathieu-Daudé,
	Eric Farman, Anders Roxell, Pierrick Bouvier, Brian Cain,
	Klaus Jensen, Michael S. Tsirkin, Paolo Bonzini

On Wed, 30 Sep 2026 17:46:49 +0100, Alex Bennée <alex.bennee@linaro.org> wrote:
> With all the bits in place we can now exercise the KVM gdb interfaces.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Marc-André Lureau <marcandre.lureau@redhat.com>



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 05/13] tests/functional: add basic gdbstub test for KVM
  2026-10-01 11:18   ` marcandre.lureau
@ 2026-10-02  9:46     ` Alex Bennée
  0 siblings, 0 replies; 28+ messages in thread
From: Alex Bennée @ 2026-10-02  9:46 UTC (permalink / raw)
  To: marcandre.lureau
  Cc: qemu-devel, Kyle Evans, Song Gao, Ani Sinha, Warner Losh,
	Richard Henderson, John Snow, Keith Busch, Cornelia Huck,
	Thomas Huth, Zhao Liu, Peter Maydell, Laurent Vivier, Brad Smith,
	Peter Xu, Daniel P. Berrangé, Ilya Leoshkevich,
	Matthew Rosato, Philippe Mathieu-Daudé, Eric Farman,
	Anders Roxell, Pierrick Bouvier, Brian Cain, Klaus Jensen,
	Paolo Bonzini

marcandre.lureau@redhat.com writes:

>> We don't really exercise the KVM bits of gdbstub very much as the TCG
>> tests are TCG only and the ones in functional tests are focused on
>> record/replay and reverse debugging.
>> 
>> Add a basic gdbstub test case which uses heuristics to single step
>> through the default firmware of guests and kick the tyres and check
>> things are working as expected.
>> 
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>> 
>> Message-ID: <20260930164649.433573-6-alex.bennee@linaro.org>
>>
>> diff --git a/tests/functional/gdb-scripts/kvm_fw_gdb_test.py b/tests/functional/gdb-scripts/kvm_fw_gdb_test.py
>> new file mode 100644
>> index 000000000000..b38b874dc586
>> --- /dev/null
>> +++ b/tests/functional/gdb-scripts/kvm_fw_gdb_test.py
>> @@ -0,0 +1,119 @@
>> +# SPDX-License-Identifier: GPL-2.0-or-later
>> +#
>> +# Generic GDB script to verify gdbstub functionality on guest firmware:
>> +#  - Single-stepping across VM-exits
>> +#  - Placing a hardware breakpoint at a branch or ahead in disassembly
>> +#  - Continuing to the breakpoint and validating that registers changed
>> +#
>> +# Copyright (c) 2026 Linaro Limited
>> +#
>> +# Author:
>> +#  Alex Bennée <alex.bennee@linaro.org>
>> +
>> +import gdb
>> +from test_gdbstub import main, report
>> +
>> +def parse_registers():
>> +    """Parse 'info registers' into a name -> value dictionary."""
>> +    regs = {}
>> +    for line in gdb.execute("info registers", to_string=True).splitlines():
>> +        parts = line.split()
>> +        if len(parts) >= 2:
>> +            regs[parts[0]] = parts[1]
>> +    return regs
>> +
>> +def test_single_step():
>> +    """
>> +    Single-step a few instructions and verify PC advances
>> +    """
>> +    current_pc = int(gdb.parse_and_eval("$pc"))
>> +    for step in range(1, 6):
>> +        gdb.execute("stepi")
>> +        gdb.execute("x/3i $pc")
>> +        pc = int(gdb.parse_and_eval("$pc"))
>> +        report(pc != current_pc, f"single-step {step} advanced pc")
>> +        current_pc = pc
>> +
>> +
>> +def might_be_jump(asm):
>> +    """
>> +    Return true if the assembly string might contain a branch/jump instruction
>> +    """
>> +    branch_keywords = {
>> +        "jmp", "b", "bl", "bx", "bne", "beq", "bgt", "blt", "bge", "ble",
>> +        "call", "ret", "br", "jal", "jalr", "bc", "bctrl", "j"
>> +    }
>
>
> Do you plan to make this per-architecture? It doesn't cover x86
> conditional jumps.

I think I'm just going to wrap the register checking code into the other
test and drop this one as the heuristics are potentially flaky. It was
really just a workaround to not having symbols easily accessible (which I
have now).

>
>> +
>> +    parts = asm.split()
>> +    if not parts:
>> +        return False
>> +    mnemonic = parts[0].lower()
>> +    return mnemonic in branch_keywords
>> +
>> +
>> +def test_hw_bkpt():
>> +    """
>> +    Set a hwbkpt somewhere in the future.
>> +    """
>> +
>> +    # FIXME - this is fragile
>> +    disas = gdb.execute("x/10i $pc", to_string=True)
>> +    lines = disas.strip().splitlines()
>> +    insns = 0
>> +    bp = None
>> +
>> +    for line in lines:
>> +        clean = line.lstrip("=>").strip()
>> +        parts = clean.split(":", 1)
>> +        if len(parts) < 2 or not parts[1].strip():
>> +            continue
>> +        insns += 1
>> +
>> +        if might_be_jump(parts[1]):
>> +            # jump too close, bail out?
>> +            if insns < 2:
>> +                report(False, "found jump far enough away")
>> +                return
>> +            else:
>> +                addr = int(parts[0].split()[0], 16)
>> +                bp = gdb.Breakpoint(f"*{hex(addr)}",
>> +                                    type=gdb.BP_HARDWARE_BREAKPOINT)
>> +                break
>> +        elif insns == 10:
>> +            addr = int(parts[0].split()[0], 16)
>> +            bp = gdb.Breakpoint(f"*{hex(addr)}",
>> +                                type=gdb.BP_HARDWARE_BREAKPOINT)
>> +            break
>> +
>> +    report(bp is not None, f"set hwbkpt @ {bp.location}")
>
> Maybe to make debugging easier:
>
>   if bp is None:
>       report(False, "failed to set hwbkpt (no suitable instruction found)")
>       return
>   report(True, f"set hwbkpt @ {bp.location}")
>
>> +    gdb.execute("continue")
>> +
>> +    end_pc = gdb.parse_and_eval('$pc')
>> +    report(bp.hit_count == 1,
>> +           "break @ %s (%d hits)" % (end_pc, bp.hit_count))
>> +
>> +    bp.delete()
>> +    return
>> +
>> +def test_reg_updates(regs_start):
>> +    regs_end = parse_registers()
>> +
>> +    changed = [k for k in regs_start
>> +               if k in regs_end and regs_start[k] != regs_end[k]]
>> +
>> +    report(len(changed) > 0, f"{len(changed)} registers changed.")
>> +
>> +def run_test():
>> +    regs_start = parse_registers()
>> +
>> +    test_single_step()
>> +
>> +    # skip any pesky mode switching code
>> +    gdb.execute("stepi 50")
>> +
>> +    test_hw_bkpt()
>> +
>> +    test_reg_updates(regs_start)
>> +
>> +
>> +main(run_test)
>> diff --git a/tests/functional/x86_64/meson.build b/tests/functional/x86_64/meson.build
>> index 0353b2af8e1d..080e12ddef13 100644
>> --- a/tests/functional/x86_64/meson.build
>> +++ b/tests/functional/x86_64/meson.build
>> @@ -13,6 +13,7 @@ tests_x86_64_system_quick = [
>>    'bad_vmstate',
>>    'cpu_model_versions',
>>    'cpu_queries',
>> +  'kvm_gdbstub',
>>    'mem_addr_space',
>>    'migration',
>>    'pc_cpu_hotplug_props',
>> diff --git a/tests/functional/x86_64/test_kvm_gdbstub.py b/tests/functional/x86_64/test_kvm_gdbstub.py
>> new file mode 100755
>> index 000000000000..26876c3dc580
>> --- /dev/null
>> +++ b/tests/functional/x86_64/test_kvm_gdbstub.py
>> @@ -0,0 +1,55 @@
>> +#!/usr/bin/env python3
>> +#
>> +# SPDX-License-Identifier: GPL-2.0-or-later
>> +#
>> +# Functional test verifying KVM gdbstub operations on firmware:
>> +#  - Single-stepping across VM-exits
>> +#  - Register sampling across execution steps
>> +#  - Hardware breakpoint at branch destination or instruction
>> +#
>> +# Copyright (c) 2026 Linaro Limited
>> +#
>> +# Author:
>> +#  Alex Bennée <alex.bennee@linaro.org>
>> +
>> +import os
>> +import subprocess
>> +from pathlib import Path
>> +from qemu_test import QemuSystemTest, skipIfMissingEnv
>> +
>> +
>> +class KvmGdbstubTest(QemuSystemTest):
>> +
>> +    @skipIfMissingEnv("QEMU_TEST_GDB")
>> +    def test_x86_64_kvm_fw_gdb(self):
>> +        self.require_accelerator("kvm")
>> +
>> +        gdb_path = os.getenv("QEMU_TEST_GDB")
>> +
>> +        tests_dir = Path(__file__).resolve().parents[2]
>> +        run_test = tests_dir / "guest-debug" / "run-test.py"
>> +        gdb_script = (tests_dir / "functional" / "gdb-scripts" /
>> +                      "kvm_fw_gdb_test.py")
>> +
>> +        qargs = "-machine pc -accel kvm -cpu host -smp 1 -m 512M -display none"
>> +        cmd = [
>> +            str(run_test),
>> +            "--qemu", self.qemu_bin,
>> +            "--qargs", qargs,
>> +            "--binary", "",
>> +            "--test", str(gdb_script),
>> +            "--gdb", gdb_path,
>> +        ]
>> +
>> +        res = subprocess.run(cmd, text=True,
>> +                             stdout=subprocess.PIPE,
>> +                             stderr=subprocess.STDOUT)
>> +        if res.stdout:
>> +            self.log.info('run-test.py: %s', res.stdout)
>> +
>> +        self.assertEqual(res.returncode, 0,
>> +                         f"run-test.py failed ({res.returncode}):\n")
>> +
>> +
>> +if __name__ == '__main__':
>> +    QemuSystemTest.main()
>
> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2026-10-02  9:46 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-30 16:46 [PATCH 00/13] testing/next: functional testing updates for gdb Alex Bennée
2026-09-30 16:46 ` [PATCH 01/13] tests/functional: test_acpi_bits requires TCG Alex Bennée
2026-10-01 11:18   ` marcandre.lureau
2026-09-30 16:46 ` [PATCH 02/13] tests/functional: add migration diagnostics and pace nvme activity (HACK!) Alex Bennée
2026-09-30 16:46 ` [PATCH 03/13] tests/tcg: fix buffer overflow in multiarch/linux/linux-sigrtminmax Alex Bennée
2026-10-01 11:18   ` marcandre.lureau
2026-09-30 16:46 ` [PATCH 04/13] meson: move gdb detection into the top level build file Alex Bennée
2026-09-30 18:20   ` Pierrick Bouvier
2026-10-01 11:18   ` marcandre.lureau
2026-09-30 16:46 ` [PATCH 05/13] tests/functional: add basic gdbstub test for KVM Alex Bennée
2026-10-01 11:18   ` marcandre.lureau
2026-10-02  9:46     ` Alex Bennée
2026-09-30 16:46 ` [PATCH 06/13] tests/functional: allow tuxrun tests to be passed "accel" Alex Bennée
2026-10-01 11:18   ` marcandre.lureau
2026-09-30 16:46 ` [PATCH 07/13] tests/functional: split x86_64 tuxrun into tcg and kvm run Alex Bennée
2026-10-01 11:18   ` marcandre.lureau
2026-09-30 16:46 ` [PATCH 08/13] tests/functional: split aarch64 " Alex Bennée
2026-10-01 11:18   ` marcandre.lureau
2026-09-30 16:46 ` [PATCH 09/13] tests/functional: update x86_64 tuxrun images Alex Bennée
2026-10-01 11:18   ` marcandre.lureau
2026-09-30 16:46 ` [PATCH 10/13] tests/guest-debug: add --kargs option to run-test Alex Bennée
2026-10-01 11:18   ` marcandre.lureau
2026-09-30 16:46 ` [PATCH 11/13] tests/guest-debug: add --symbols " Alex Bennée
2026-10-01 11:18   ` marcandre.lureau
2026-09-30 16:46 ` [PATCH 12/13] tests/functional: teach tuxrun about launching gdb tests Alex Bennée
2026-10-01 11:18   ` marcandre.lureau
2026-09-30 16:46 ` [PATCH 13/13] tests/functional: add tuxrun kvm gdb test for x86_64 Alex Bennée
2026-10-01 11:18   ` marcandre.lureau

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.