public inbox for gdb-cvs@sourceware.org
help / color / mirror / Atom feed
* [binutils-gdb] Simplify DAP stop-reason code
@ 2023-12-11 18:43 Tom Tromey
  0 siblings, 0 replies; only message in thread
From: Tom Tromey @ 2023-12-11 18:43 UTC (permalink / raw)
  To: gdb-cvs

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=7729e7c0bdd01027a003181a99d58aadd981896a

commit 7729e7c0bdd01027a003181a99d58aadd981896a
Author: Tom Tromey <tromey@adacore.com>
Date:   Fri Nov 3 13:59:10 2023 -0600

    Simplify DAP stop-reason code
    
    Now that gdb adds stop-reason details to stop events, we can simplify
    the DAP code to emit correct stop reasons in its own events.  For the
    most part a simple renaming of gdb reasons is sufficient; however,
    "pause" must still be handled specially.

Diff:
---
 gdb/python/lib/gdb/dap/events.py | 95 ++++++++++++++++++++++++++++------------
 gdb/python/lib/gdb/dap/launch.py |  4 +-
 gdb/python/lib/gdb/dap/next.py   | 10 ++---
 gdb/python/lib/gdb/dap/pause.py  |  4 +-
 4 files changed, 76 insertions(+), 37 deletions(-)

diff --git a/gdb/python/lib/gdb/dap/events.py b/gdb/python/lib/gdb/dap/events.py
index b759ba43b5f..cbefe90e4ca 100644
--- a/gdb/python/lib/gdb/dap/events.py
+++ b/gdb/python/lib/gdb/dap/events.py
@@ -13,7 +13,6 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-import enum
 import gdb
 
 from .server import send_event
@@ -148,48 +147,77 @@ def _cont(event):
         )
 
 
-class StopKinds(enum.Enum):
-    # The values here are chosen to follow the DAP spec.
-    STEP = "step"
-    BREAKPOINT = "breakpoint"
-    PAUSE = "pause"
-    EXCEPTION = "exception"
-
-
-_expected_stop = None
+_expected_pause = False
 
 
 @in_gdb_thread
-def exec_and_expect_stop(cmd, reason):
-    """Indicate that a stop is expected, then execute CMD"""
-    global _expected_stop
-    _expected_stop = reason
-    if reason != StopKinds.PAUSE:
-        global _suppress_cont
-        _suppress_cont = True
+def exec_and_expect_stop(cmd, expected_pause=False):
+    """A wrapper for exec_and_log that sets the continue-suppression flag.
+
+    When EXPECTED_PAUSE is True, a stop that looks like a pause (e.g.,
+    a SIGINT) will be reported as "pause" instead.
+    """
+    global _expected_pause
+    _expected_pause = expected_pause
+    global _suppress_cont
+    # If we're expecting a pause, then we're definitely not
+    # continuing.
+    _suppress_cont = not expected_pause
     # FIXME if the call fails should we clear _suppress_cont?
     exec_and_log(cmd)
 
 
+# Map from gdb stop reasons to DAP stop reasons.  Some of these can't
+# be seen ordinarily in DAP -- only if the client lets the user toggle
+# some settings (e.g. stop-on-solib-events) or enter commands (e.g.,
+# 'until').
+stop_reason_map = {
+    "breakpoint-hit": "breakpoint",
+    "watchpoint-trigger": "data breakpoint",
+    "read-watchpoint-trigger": "data breakpoint",
+    "access-watchpoint-trigger": "data breakpoint",
+    "function-finished": "step",
+    "location-reached": "step",
+    "watchpoint-scope": "data breakpoint",
+    "end-stepping-range": "step",
+    "exited-signalled": "exited",
+    "exited": "exited",
+    "exited-normally": "exited",
+    "signal-received": "signal",
+    "solib-event": "solib",
+    "fork": "fork",
+    "vfork": "vfork",
+    "syscall-entry": "syscall-entry",
+    "syscall-return": "syscall-return",
+    "exec": "exec",
+    "no-history": "no-history",
+}
+
+
 @in_gdb_thread
 def _on_stop(event):
     global inferior_running
     inferior_running = False
     log("entering _on_stop: " + repr(event))
-    global _expected_stop
+    log("   details: " + repr(event.details))
     obj = {
         "threadId": gdb.selected_thread().global_num,
         "allThreadsStopped": True,
     }
     if isinstance(event, gdb.BreakpointEvent):
-        # Ignore the expected stop, we hit a breakpoint instead.
-        _expected_stop = StopKinds.BREAKPOINT
         obj["hitBreakpointIds"] = [x.number for x in event.breakpoints]
-    elif _expected_stop is None:
-        # FIXME what is even correct here
-        _expected_stop = StopKinds.EXCEPTION
-    obj["reason"] = _expected_stop.value
-    _expected_stop = None
+    global stop_reason_map
+    reason = event.details["reason"]
+    global _expected_pause
+    if (
+        _expected_pause
+        and reason == "signal-received"
+        and event.details["signal-name"] in ("SIGINT", "SIGSTOP")
+    ):
+        obj["reason"] = "pause"
+    else:
+        obj["reason"] = stop_reason_map[reason]
+    _expected_pause = False
     send_event("stopped", obj)
 
 
@@ -204,13 +232,26 @@ _infcall_was_running = False
 @in_gdb_thread
 def _on_inferior_call(event):
     global _infcall_was_running
+    global inferior_running
     if isinstance(event, gdb.InferiorCallPreEvent):
         _infcall_was_running = inferior_running
         if not _infcall_was_running:
             _cont(None)
     else:
-        if not _infcall_was_running:
-            _on_stop(None)
+        # If the inferior is already marked as stopped here, then that
+        # means that the call caused some other stop, and we don't
+        # want to double-report it.
+        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",
+            }
+            global _expected_pause
+            _expected_pause = False
+            send_event("stopped", obj)
 
 
 gdb.events.stop.connect(_on_stop)
diff --git a/gdb/python/lib/gdb/dap/launch.py b/gdb/python/lib/gdb/dap/launch.py
index 995641bd945..7014047ff51 100644
--- a/gdb/python/lib/gdb/dap/launch.py
+++ b/gdb/python/lib/gdb/dap/launch.py
@@ -80,6 +80,4 @@ def config_done(**args):
     global _program
     if _program is not None:
         expect_process("process")
-        # Suppress the continue event, but don't set any particular
-        # expected stop.
-        exec_and_expect_stop("run", None)
+        exec_and_expect_stop("run")
diff --git a/gdb/python/lib/gdb/dap/next.py b/gdb/python/lib/gdb/dap/next.py
index eedc26f28a5..c06093e74ed 100644
--- a/gdb/python/lib/gdb/dap/next.py
+++ b/gdb/python/lib/gdb/dap/next.py
@@ -15,7 +15,7 @@
 
 import gdb
 
-from .events import StopKinds, exec_and_expect_stop
+from .events import exec_and_expect_stop
 from .server import capability, request
 from .startup import in_gdb_thread, send_gdb, send_gdb_with_response
 from .state import set_thread
@@ -57,7 +57,7 @@ def next(
     cmd = "next"
     if granularity == "instruction":
         cmd += "i"
-    exec_and_expect_stop(cmd, StopKinds.STEP)
+    exec_and_expect_stop(cmd)
 
 
 @capability("supportsSteppingGranularity")
@@ -70,13 +70,13 @@ def step_in(
     cmd = "step"
     if granularity == "instruction":
         cmd += "i"
-    exec_and_expect_stop(cmd, StopKinds.STEP)
+    exec_and_expect_stop(cmd)
 
 
 @request("stepOut", response=False)
 def step_out(*, threadId: int, singleThread: bool = False, **args):
     _handle_thread_step(threadId, singleThread, True)
-    exec_and_expect_stop("finish", StopKinds.STEP)
+    exec_and_expect_stop("finish")
 
 
 # This is a server-side request because it is funny: it wants to
@@ -87,5 +87,5 @@ def step_out(*, threadId: int, singleThread: bool = False, **args):
 @request("continue", on_dap_thread=True)
 def continue_request(*, threadId: int, singleThread: bool = False, **args):
     locked = send_gdb_with_response(lambda: _handle_thread_step(threadId, singleThread))
-    send_gdb(lambda: exec_and_expect_stop("continue", None))
+    send_gdb(lambda: exec_and_expect_stop("continue"))
     return {"allThreadsContinued": not locked}
diff --git a/gdb/python/lib/gdb/dap/pause.py b/gdb/python/lib/gdb/dap/pause.py
index b7e21452d69..19ff17d511b 100644
--- a/gdb/python/lib/gdb/dap/pause.py
+++ b/gdb/python/lib/gdb/dap/pause.py
@@ -13,10 +13,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from .events import StopKinds, exec_and_expect_stop
+from .events import exec_and_expect_stop
 from .server import request
 
 
 @request("pause", response=False, expect_stopped=False)
 def pause(**args):
-    exec_and_expect_stop("interrupt -a", StopKinds.PAUSE)
+    exec_and_expect_stop("interrupt -a", True)

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-12-11 18:43 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-11 18:43 [binutils-gdb] Simplify DAP stop-reason code Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).