Avoid exception from attach in DAP
authorTom Tromey <tromey@adacore.com>
Tue, 12 Dec 2023 17:09:55 +0000 (10:09 -0700)
committerTom Tromey <tromey@adacore.com>
Fri, 22 Dec 2023 16:57:49 +0000 (09:57 -0700)
I noticed that the DAP attach test case (and similarly
remoted-dap.exp) had a rogue exception stack trace in the log.  It
turns out that an attach will generate a stop that does not have a
reason.

This patch fixes the problem in the _on_stop event listener by making
it a bit more careful when examining the event reason.  It also adds
some machinery so that attach stops can be suppressed, which I think
is the right thing to do.

Reviewed-By: Kévin Le Gouguec <legouguec@adacore.com>
gdb/python/lib/gdb/dap/events.py
gdb/python/lib/gdb/dap/launch.py

index cbefe90..311bdc3 100644 (file)
@@ -147,6 +147,16 @@ def _cont(event):
         )
 
 
+_suppress_stop = False
+
+
+@in_gdb_thread
+def suppress_stop():
+    """Indicate that the next stop should not emit an event."""
+    global _suppress_stop
+    _suppress_stop = True
+
+
 _expected_pause = False
 
 
@@ -198,6 +208,13 @@ stop_reason_map = {
 def _on_stop(event):
     global inferior_running
     inferior_running = False
+
+    global _suppress_stop
+    if _suppress_stop:
+        _suppress_stop = False
+        log("suppressing stop in _on_stop")
+        return
+
     log("entering _on_stop: " + repr(event))
     log("   details: " + repr(event.details))
     obj = {
@@ -206,17 +223,23 @@ def _on_stop(event):
     }
     if isinstance(event, gdb.BreakpointEvent):
         obj["hitBreakpointIds"] = [x.number for x in event.breakpoints]
-    global stop_reason_map
-    reason = event.details["reason"]
     global _expected_pause
-    if (
+    # Some stop events still do not emit details.  For example,
+    # 'attach' causes a reason-less stop.
+    if "reason" not in event.details:
+        # This can only really happen via a "repl" evaluation of
+        # something like "attach".  In this case just emit a generic
+        # stop.
+        obj["reason"] = "stopped"
+    elif (
         _expected_pause
-        and reason == "signal-received"
+        and event.details["reason"] == "signal-received"
         and event.details["signal-name"] in ("SIGINT", "SIGSTOP")
     ):
         obj["reason"] = "pause"
     else:
-        obj["reason"] = stop_reason_map[reason]
+        global stop_reason_map
+        obj["reason"] = stop_reason_map[event.details["reason"]]
     _expected_pause = False
     send_event("stopped", obj)
 
index 5f95bfd..5ddf5e6 100644 (file)
@@ -18,7 +18,7 @@ import gdb
 # These are deprecated in 3.9, but required in older versions.
 from typing import Mapping, Optional, Sequence
 
-from .events import exec_and_expect_stop, expect_process
+from .events import exec_and_expect_stop, expect_process, suppress_stop
 from .server import request, capability
 from .startup import exec_and_log, DAPException
 
@@ -88,6 +88,7 @@ def attach(
     else:
         raise DAPException("attach requires either 'pid' or 'target'")
     expect_process("attach")
+    suppress_stop()
     exec_and_log(cmd)