diff options
author | Tom Tromey <tromey@adacore.com> | 2023-11-03 13:59:10 -0600 |
---|---|---|
committer | Tom Tromey <tromey@adacore.com> | 2023-12-11 11:35:07 -0700 |
commit | 7729e7c0bdd01027a003181a99d58aadd981896a (patch) | |
tree | 0bed041d1c9705816ddfdf82952a066ba84edc2e /gdb | |
parent | e187e7c9696fbf66cf25d5fb8113bc3bc06b9e8b (diff) | |
download | gdb-7729e7c0bdd01027a003181a99d58aadd981896a.zip gdb-7729e7c0bdd01027a003181a99d58aadd981896a.tar.gz gdb-7729e7c0bdd01027a003181a99d58aadd981896a.tar.bz2 |
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.
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/python/lib/gdb/dap/events.py | 95 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/launch.py | 4 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/next.py | 10 | ||||
-rw-r--r-- | 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 b759ba4..cbefe90 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 995641b..7014047 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 eedc26f..c06093e 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 b7e2145..19ff17d 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) |