All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: marcandre.lureau@redhat.com
Cc: qemu-devel@nongnu.org, "Kyle Evans" <kevans@freebsd.org>,
	"Song Gao" <gaosong@loongson.cn>,
	"Ani Sinha" <anisinha@redhat.com>, "Warner Losh" <imp@bsdimp.com>,
	"Richard Henderson" <richard.henderson@linaro.org>,
	"John Snow" <jsnow@redhat.com>, "Keith Busch" <kbusch@kernel.org>,
	"Cornelia Huck" <cohuck@redhat.com>,
	"Thomas Huth" <th.huth+qemu@posteo.eu>,
	"Zhao Liu" <zhao1.liu@intel.com>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	"Laurent Vivier" <laurent@vivier.eu>,
	"Brad Smith" <brad@comstyle.com>, "Peter Xu" <peterx@redhat.com>,
	"Daniel P. Berrangé" <berrange@redhat.com>,
	"Ilya Leoshkevich" <iii@linux.ibm.com>,
	"Matthew Rosato" <mjrosato@linux.ibm.com>,
	"Philippe Mathieu-Daudé" <philmd@oss.qualcomm.com>,
	"Eric Farman" <farman@linux.ibm.com>,
	"Anders Roxell" <anders.roxell@linaro.org>,
	"Pierrick Bouvier" <pierrick.bouvier@oss.qualcomm.com>,
	"Brian Cain" <brian.cain@oss.qualcomm.com>,
	"Klaus Jensen" <its@irrelevant.dk>,
	"Paolo Bonzini" <pbonzini@redhat.com>
Subject: Re: [PATCH 05/13] tests/functional: add basic gdbstub test for KVM
Date: Fri, 02 Oct 2026 10:46:08 +0100	[thread overview]
Message-ID: <87v77kjuzj.fsf@draig.linaro.org> (raw)
In-Reply-To: <179085353196.2170790.3865077624161009164.b4-review@b4> (marcandre lureau's message of "Thu, 01 Oct 2026 15:18:51 +0400")

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


  reply	other threads:[~2026-10-02  9:46 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87v77kjuzj.fsf@draig.linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=anders.roxell@linaro.org \
    --cc=anisinha@redhat.com \
    --cc=berrange@redhat.com \
    --cc=brad@comstyle.com \
    --cc=brian.cain@oss.qualcomm.com \
    --cc=cohuck@redhat.com \
    --cc=farman@linux.ibm.com \
    --cc=gaosong@loongson.cn \
    --cc=iii@linux.ibm.com \
    --cc=imp@bsdimp.com \
    --cc=its@irrelevant.dk \
    --cc=jsnow@redhat.com \
    --cc=kbusch@kernel.org \
    --cc=kevans@freebsd.org \
    --cc=laurent@vivier.eu \
    --cc=marcandre.lureau@redhat.com \
    --cc=mjrosato@linux.ibm.com \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=peterx@redhat.com \
    --cc=philmd@oss.qualcomm.com \
    --cc=pierrick.bouvier@oss.qualcomm.com \
    --cc=qemu-devel@nongnu.org \
    --cc=richard.henderson@linaro.org \
    --cc=th.huth+qemu@posteo.eu \
    --cc=zhao1.liu@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.