aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorTom Tromey <tromey@adacore.com>2023-11-03 13:59:10 -0600
committerTom Tromey <tromey@adacore.com>2023-12-11 11:35:07 -0700
commit7729e7c0bdd01027a003181a99d58aadd981896a (patch)
tree0bed041d1c9705816ddfdf82952a066ba84edc2e /gdb
parente187e7c9696fbf66cf25d5fb8113bc3bc06b9e8b (diff)
downloadgdb-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.py95
-rw-r--r--gdb/python/lib/gdb/dap/launch.py4
-rw-r--r--gdb/python/lib/gdb/dap/next.py10
-rw-r--r--gdb/python/lib/gdb/dap/pause.py4
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)