From 0b32d225818f04390a576b1a68ef1a3060fdeb34 Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@adacore.com>
Date: Tue, 12 Dec 2023 10:09:55 -0700
Subject: Avoid exception from attach in DAP
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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 | 33 ++++++++++++++++++++++++++++-----
 gdb/python/lib/gdb/dap/launch.py |  3 ++-
 2 files changed, 30 insertions(+), 6 deletions(-)

(limited to 'gdb/python/lib')

diff --git a/gdb/python/lib/gdb/dap/events.py b/gdb/python/lib/gdb/dap/events.py
index cbefe90..311bdc3 100644
--- a/gdb/python/lib/gdb/dap/events.py
+++ b/gdb/python/lib/gdb/dap/events.py
@@ -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)
 
diff --git a/gdb/python/lib/gdb/dap/launch.py b/gdb/python/lib/gdb/dap/launch.py
index 5f95bfd..5ddf5e6 100644
--- a/gdb/python/lib/gdb/dap/launch.py
+++ b/gdb/python/lib/gdb/dap/launch.py
@@ -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)
 
 
-- 
cgit v1.1