gilles grimaud <[email protected]> writes:

> Thanks for the comments.
>
> Since this is an RFC, this is exactly the kind of guidance I’m looking for.
> I am new to QEMU, so I am mainly trying to understand what the right model
> should be if this patch is not the right approach.
>
> To clarify the motivation: I hit this while working on RP2040/Pico support,
> but I do not think the issue is RP2040-specific. The Pico SDK uses a
> breakpoint instruction as part of its normal exit/debug path. On Arm
> M-profile this is BKPT; on RP2350/RISC-V the analogous pattern use
> EBREAK.
>
> So the practical question for me is how QEMU should model firmware that
> deliberately executes a breakpoint instruction as a debugger stop point 
> through
> The J-TAG.
>
> For Arm M-profile, my understanding is that BKPT can be consumed by the
> debug system when an external debugger is present, otherwise it follows the
> architectural guest exception path. I was led to this interpretation partly
> by QEMU's own gdbstub documentation, which describes the gdbstub as a
> low-level debugging facility in the same general space as JTAG-style
> debugging.
>
> That led me to the proposed rule:
>
>   M-profile guest BKPT + attached QEMU gdbstub client:
>       report a stop to the gdbstub
>
>   otherwise:
>       keep the existing architectural guest-visible path
>
> I understand Peter's point that guest breakpoint instructions may also be
> part of a guest-visible debugging mechanism, for example with a debugger
> running inside the guest. This RFC was not trying to solve that broader
> problem.
>
> If there is a better way to emulate this bare-metal firmware pattern,
> ideally without touching QEMU's normal execution path, I would be very
> happy to drop this RFC and try that instead.

Not for breakpoints but this is the sort of stuff that semihosting is
meant to deal with. On real hardware your code can make a semihosting
request and the jtag attached debugger will then service it for you. We
do support this in the gdbstub.

  https://qemu.readthedocs.io/en/master/about/emulation.html#semihosting

>
> Thanks again for your time,
> Gilles
>
>  Le 7 juil. 2026 à 19:27, Richard Henderson <[email protected]> a 
> écrit :
>
>  On 7/6/26 02:21, Peter Maydell wrote:
>
>  On Sun, 5 Jul 2026 at 23:44, Gilles Grimaud
>  <[email protected]> wrote:
>
>  While working on Raspberry Pi Pico/RP2040 support, I noticed that Pico SDK
>  programs deliberately execute BKPT from _exit(). On real hardware this is
>  useful when a debug probe is attached: returning from main() stops the
>  debugger at the program exit point.
>
>  Under QEMU this currently does not behave like the debug-probe case. For
>  M-profile guests, the BKPT instruction is routed through the architectural
>  guest debug exception path. Without halting debug, that path should remain a
>  guest-visible DebugMonitor exception when DebugMonitor is enabled, or 
> escalate
>  towards HardFault otherwise. This patch deliberately leaves that no-debugger
>  architectural path unchanged.
>
>  The problem addressed here is the case where GDB is connected to QEMU's
>  gdbstub. In that situation, firmware that uses BKPT as a debugger stop point
>  should stop in the attached debugger. Instead, the M-profile guest currently
>  continues down the guest exception path and may end in HardFault/lockup 
> rather
>  than reporting a clean trap to GDB.
>
>  This is not specific to the RP2040 machine model. It is a generic
>  Cortex-M/gdbstub interaction: firmware that uses BKPT as a debugger stop 
> point
>  should be reported to the attached debugger, while keeping the guest
>  architectural exception path when no debugger is attached.
>
>  Expose a small gdbstub helper to test whether a CPU is visible to an attached
>  debugger. When an M-profile BKPT instruction is executed with such a debugger
>  attached, leave the translated block with EXCP_DEBUG so the existing gdbstub
>  stop path reports a trap to GDB.
>
>  Signed-off-by: Gilles Grimaud <[email protected]>
>  ---
>   gdbstub/gdbstub.c      | 13 ++++++++++++-
>   include/exec/gdbstub.h |  6 ++++++
>   target/arm/tcg/debug.c |  9 +++++++++
>   3 files changed, 27 insertions(+), 1 deletion(-)
>
>  diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
>  index c3c944e965..9f259fc005 100644
>  --- a/gdbstub/gdbstub.c
>  +++ b/gdbstub/gdbstub.c
>  @@ -237,6 +237,18 @@ static GDBProcess *gdb_get_cpu_process(CPUState *cpu)
>       return gdb_get_process(gdb_get_cpu_pid(cpu));
>   }
>
>  +bool gdb_cpu_is_attached(CPUState *cpu)
>  +{
>  +    GDBProcess *process;
>  +
>  +    if (!gdbserver_state.init || !cpu) {
>  +        return false;
>  +    }
>  +
>  +    process = gdb_get_cpu_process(cpu);
>  +    return process && process->attached;
>  +}
>
>  No other architecture, CPU or board in QEMU needs to do this,
>  so my instinct is to say that M-profile should not be special here.
>  Richard, Alex: how do we usually handle breakpoint insns for the
>  gdbstub ?
>
>  We handle them via CPUBreakpoint structures; we never inject code changes.
>
>  The patch description explains the confusion: this is attempting to 
> replicate a feature of the Raspberry Pi Pico SDK, wherein a
>  guest BPKT really is trapped by an external debugger.
>
>  The only question is whether we want to follow that, and I suspect the 
> answer is no.
>
>  r~

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro

Reply via email to