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
next prev 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).