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~