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~

Reply via email to