[07/11] gdb, dap: fix DAP events if no thread is selected

Message ID 20260518183316.127043-8-mohamed.bouhaouel@intel.com
State New
Headers
Series Enable non-stop mode by default for remote targets |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed

Commit Message

Bouhaouel, Mohamed May 18, 2026, 6:33 p.m. UTC
  From: "Rohr, Stephan" <stephan.rohr@intel.com>

The DAP protocol requires a thread-id for a continue event.  It is
optional for the stopped event.  If we force the remote target to run in
non-stop mode, i.e., "-iex maint set target-non-stop on", GDB does not
have a thread selected.  Default to '0' for continue events in this
case.  Omit the 'threadID' for stopped events if no thread is selected.
---
 gdb/python/lib/gdb/dap/events.py | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)
  

Patch

diff --git a/gdb/python/lib/gdb/dap/events.py b/gdb/python/lib/gdb/dap/events.py
index 27e3b5ab8bc..85e672b4c9e 100644
--- a/gdb/python/lib/gdb/dap/events.py
+++ b/gdb/python/lib/gdb/dap/events.py
@@ -138,10 +138,14 @@  def _cont(event):
         log("_suppress_cont case")
         _suppress_cont = False
     else:
+        thread = gdb.selected_thread()
+
+        # We may not have a selected thread if the target is running in
+        # non-stop mode.  Default to '0' in this case.
         send_event(
             "continued",
             {
-                "threadId": gdb.selected_thread().global_num,
+                "threadId": thread.global_num if thread else 0,
                 "allThreadsContinued": True,
             },
         )
@@ -213,9 +217,11 @@  def _on_stop(event):
     if hasattr(event, "details"):
         log("   details: " + repr(event.details))
     obj = {
-        "threadId": gdb.selected_thread().global_num,
         "allThreadsStopped": True,
     }
+    # The thread-id parameter is optional for stopped events.
+    if gdb.selected_thread():
+        obj["threadId"] = gdb.selected_thread().global_num
     if isinstance(event, gdb.BreakpointEvent):
         obj["hitBreakpointIds"] = [x.number for x in event.breakpoints]
     if hasattr(event, "details") and "finish-value" in event.details:
@@ -266,11 +272,14 @@  def _on_inferior_call(event):
         if not _infcall_was_running and inferior_running:
             inferior_running = False
             obj = {
-                "threadId": gdb.selected_thread().global_num,
                 "allThreadsStopped": True,
                 # DAP says any string is ok.
                 "reason": "function call",
             }
+            # The thread-id parameter is optional for stopped events.
+            if gdb.selected_thread():
+                obj["threadId"] = gdb.selected_thread().global_num
+
             global _expected_pause
             _expected_pause = False
             send_event("stopped", obj)