public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Tom Tromey <tromey@adacore.com>
To: gdb-patches@sourceware.org
Subject: [PATCH 3/3] Simplify DAP stop-reason code
Date: Tue, 14 Nov 2023 11:44:05 -0700	[thread overview]
Message-ID: <20231114-py-stop-reason-v1-3-4ff440c956a9@adacore.com> (raw)
In-Reply-To: <20231114-py-stop-reason-v1-0-4ff440c956a9@adacore.com>

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.
---
 gdb/python/lib/gdb/dap/events.py | 79 +++++++++++++++++++++++++---------------
 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, 57 insertions(+), 40 deletions(-)

diff --git a/gdb/python/lib/gdb/dap/events.py b/gdb/python/lib/gdb/dap/events.py
index e9ddcab135f..bdd2a6ebadc 100644
--- a/gdb/python/lib/gdb/dap/events.py
+++ b/gdb/python/lib/gdb/dap/events.py
@@ -99,60 +99,79 @@ 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
-
-
-@in_gdb_thread
-def expect_stop(reason):
-    """Indicate that a stop is expected, for the reason given."""
-    global _expected_stop
-    _expected_stop = reason
+_expected_pause = False
 
 
 # A wrapper for Invoker that also sets the expected stop.
 class ExecutionInvoker(Invoker):
-    """A subclass of Invoker that sets the expected stop.
-    Note that this assumes that the command will restart the inferior,
-    so it will also cause ContinuedEvents to be suppressed."""
+    """A subclass of Invoker that sets the continue-suppression flag.
 
-    def __init__(self, cmd, expected):
+    When EXPECTED_PAUSE is True, a stop that looks like a pause (e.g.,
+    a SIGINT) will be reported as "pause" instead.
+    """
+
+    def __init__(self, cmd, expected_pause=False):
         super().__init__(cmd)
-        self.expected = expected
+        self.expected_pause = expected_pause
 
     @in_gdb_thread
     def __call__(self):
-        expect_stop(self.expected)
+        global _expected_pause
+        _expected_pause = self.expected_pause
         global _suppress_cont
         _suppress_cont = True
         # FIXME if the call fails should we clear _suppress_cont?
         super().__call__()
 
 
+# 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):
     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]
     send_event("stopped", obj)
 
 
diff --git a/gdb/python/lib/gdb/dap/launch.py b/gdb/python/lib/gdb/dap/launch.py
index d13037fa476..7dead0c7c35 100644
--- a/gdb/python/lib/gdb/dap/launch.py
+++ b/gdb/python/lib/gdb/dap/launch.py
@@ -88,6 +88,4 @@ def attach(*, pid: Optional[int] = None, target: Optional[str] = None, **args):
 def config_done(**args):
     global _program
     if _program is not None:
-        # Suppress the continue event, but don't set any particular
-        # expected stop.
-        send_gdb(ExecutionInvoker("run", None))
+        send_gdb(ExecutionInvoker("run"))
diff --git a/gdb/python/lib/gdb/dap/next.py b/gdb/python/lib/gdb/dap/next.py
index e5bb8d64da0..76c9360383a 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, ExecutionInvoker
+from .events import ExecutionInvoker
 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"
-    send_gdb(ExecutionInvoker(cmd, StopKinds.STEP))
+    send_gdb(ExecutionInvoker(cmd))
 
 
 @capability("supportsSteppingGranularity")
@@ -70,17 +70,17 @@ def step_in(
     cmd = "step"
     if granularity == "instruction":
         cmd += "i"
-    send_gdb(ExecutionInvoker(cmd, StopKinds.STEP))
+    send_gdb(ExecutionInvoker(cmd))
 
 
 @request("stepOut")
 def step_out(*, threadId: int, singleThread: bool = False, **args):
     send_gdb(lambda: _handle_thread_step(threadId, singleThread, True))
-    send_gdb(ExecutionInvoker("finish", StopKinds.STEP))
+    send_gdb(ExecutionInvoker("finish"))
 
 
 @request("continue")
 def continue_request(*, threadId: int, singleThread: bool = False, **args):
     locked = send_gdb_with_response(lambda: _handle_thread_step(threadId, singleThread))
-    send_gdb(ExecutionInvoker("continue", None))
+    send_gdb(ExecutionInvoker("continue"))
     return {"allThreadsContinued": not locked}
diff --git a/gdb/python/lib/gdb/dap/pause.py b/gdb/python/lib/gdb/dap/pause.py
index 1e59d630523..a89741cbf69 100644
--- a/gdb/python/lib/gdb/dap/pause.py
+++ b/gdb/python/lib/gdb/dap/pause.py
@@ -13,11 +13,11 @@
 # 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, ExecutionInvoker
+from .events import ExecutionInvoker
 from .server import request
 from .startup import send_gdb
 
 
 @request("pause")
 def pause(**args):
-    send_gdb(ExecutionInvoker("interrupt -a", StopKinds.PAUSE))
+    send_gdb(ExecutionInvoker("interrupt -a", True))

-- 
2.41.0


  parent reply	other threads:[~2023-11-14 18:44 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-14 18:44 [PATCH 0/3] Simplify DAP stop reason emission Tom Tromey
2023-11-14 18:44 ` [PATCH 1/3] Move py_ui_out to a new header Tom Tromey
2023-11-14 18:44 ` [PATCH 2/3] Emit stop reason details in Python stop events Tom Tromey
2023-11-14 19:12   ` Eli Zaretskii
2023-11-14 18:44 ` Tom Tromey [this message]
2023-12-11 18:42 ` [PATCH 0/3] Simplify DAP stop reason emission Tom Tromey

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231114-py-stop-reason-v1-3-4ff440c956a9@adacore.com \
    --to=tromey@adacore.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).