diff options
author | Tom Tromey <tromey@adacore.com> | 2024-12-16 10:44:55 -0700 |
---|---|---|
committer | Tom Tromey <tromey@adacore.com> | 2025-01-06 07:32:11 -0700 |
commit | 8ac42dbf5001416e6b741c5361be14186afde5b0 (patch) | |
tree | a05b26736fc12b4813f00d487cba2e5b6e0796d8 /gdb/python | |
parent | 350609bb98cee92c6b4fbd334b99066683b9e5c1 (diff) | |
download | binutils-8ac42dbf5001416e6b741c5361be14186afde5b0.zip binutils-8ac42dbf5001416e6b741c5361be14186afde5b0.tar.gz binutils-8ac42dbf5001416e6b741c5361be14186afde5b0.tar.bz2 |
Handle linesStartAt1 in DAP
The DAP initialize request has a "linesStartAt1" option, where the
client can indicate that it prefers whether line numbers be 0-based or
1-based.
This patch implements this. I audited all the line-related code in
the DAP implementation.
Note that while a similar option exists for column numbers, gdb
doesn't handle these yet, so nothing is done here.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32468
Diffstat (limited to 'gdb/python')
-rw-r--r-- | gdb/python/lib/gdb/dap/breakpoint.py | 6 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/bt.py | 7 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/disassemble.py | 4 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/locations.py | 7 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/scopes.py | 4 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/server.py | 36 |
6 files changed, 50 insertions, 14 deletions
diff --git a/gdb/python/lib/gdb/dap/breakpoint.py b/gdb/python/lib/gdb/dap/breakpoint.py index 6adb826..f0fe073 100644 --- a/gdb/python/lib/gdb/dap/breakpoint.py +++ b/gdb/python/lib/gdb/dap/breakpoint.py @@ -21,7 +21,7 @@ from typing import Optional, Sequence import gdb -from .server import capability, request, send_event +from .server import capability, export_line, import_line, request, send_event from .sources import make_source from .startup import ( DAPException, @@ -128,7 +128,7 @@ def _breakpoint_descriptor(bp): result.update( { "source": make_source(filename), - "line": line, + "line": export_line(line), } ) @@ -281,7 +281,7 @@ def _rewrite_src_breakpoint( ): return { "source": source["path"], - "line": line, + "line": import_line(line), "condition": condition, "hitCondition": hitCondition, "logMessage": logMessage, diff --git a/gdb/python/lib/gdb/dap/bt.py b/gdb/python/lib/gdb/dap/bt.py index 668bcc7..a27c61a 100644 --- a/gdb/python/lib/gdb/dap/bt.py +++ b/gdb/python/lib/gdb/dap/bt.py @@ -21,7 +21,7 @@ import gdb from .frames import dap_frame_generator from .modules import module_id from .scopes import symbol_value -from .server import capability, request +from .server import capability, export_line, request from .sources import make_source from .startup import in_gdb_thread from .state import set_thread @@ -84,10 +84,13 @@ def _backtrace(thread_id, levels, startFrame, stack_format): "column": 0, "instructionPointerReference": hex(pc), } - line = current_frame.line() + line = export_line(current_frame.line()) if line is not None: newframe["line"] = line if stack_format["line"]: + # Unclear whether export_line should be called + # here, but since it's just for users we pick the + # gdb representation. name += ", line " + str(line) objfile = gdb.current_progspace().objfile_for_address(pc) if objfile is not None: diff --git a/gdb/python/lib/gdb/dap/disassemble.py b/gdb/python/lib/gdb/dap/disassemble.py index a2e27e5..5389803 100644 --- a/gdb/python/lib/gdb/dap/disassemble.py +++ b/gdb/python/lib/gdb/dap/disassemble.py @@ -15,7 +15,7 @@ import gdb -from .server import capability, request +from .server import capability, export_line, request from .sources import make_source @@ -53,7 +53,7 @@ class _BlockTracker: sal = gdb.find_pc_line(pc) if sal.symtab is not None: if sal.line != 0: - result["line"] = sal.line + result["line"] = export_line(sal.line) if sal.symtab.filename is not None: # The spec says this can be omitted in some # situations, but it's a little simpler to just always diff --git a/gdb/python/lib/gdb/dap/locations.py b/gdb/python/lib/gdb/dap/locations.py index befb7bf..1ef5a34 100644 --- a/gdb/python/lib/gdb/dap/locations.py +++ b/gdb/python/lib/gdb/dap/locations.py @@ -16,7 +16,7 @@ # This is deprecated in 3.9, but required in older versions. from typing import Optional -from .server import capability, request +from .server import capability, export_line, import_line, request from .sources import decode_source from .startup import exec_mi_and_log @@ -31,12 +31,15 @@ from .startup import exec_mi_and_log @request("breakpointLocations", expect_stopped=False) @capability("supportsBreakpointLocationsRequest") def breakpoint_locations(*, source, line: int, endLine: Optional[int] = None, **extra): + line = import_line(line) if endLine is None: endLine = line + else: + endLine = import_line(endLine) filename = decode_source(source) lines = set() for entry in exec_mi_and_log("-symbol-list-lines", filename)["lines"]: this_line = entry["line"] if this_line >= line and this_line <= endLine: - lines.add(this_line) + lines.add(export_line(this_line)) return {"breakpoints": [{"line": x} for x in sorted(lines)]} diff --git a/gdb/python/lib/gdb/dap/scopes.py b/gdb/python/lib/gdb/dap/scopes.py index 2fb3f77..221ae35 100644 --- a/gdb/python/lib/gdb/dap/scopes.py +++ b/gdb/python/lib/gdb/dap/scopes.py @@ -17,7 +17,7 @@ import gdb from .frames import frame_for_id from .globalvars import get_global_scope -from .server import request +from .server import export_line, request from .sources import make_source from .startup import in_gdb_thread from .varref import BaseReference @@ -92,7 +92,7 @@ class _ScopeReference(BaseReference): result["namedVariables"] = self.child_count() frame = frame_for_id(self.frameId) if frame.line() is not None: - result["line"] = frame.line() + result["line"] = export_line(frame.line()) filename = frame.filename() if filename is not None: result["source"] = make_source(filename) diff --git a/gdb/python/lib/gdb/dap/server.py b/gdb/python/lib/gdb/dap/server.py index 68801ef..6f3af73 100644 --- a/gdb/python/lib/gdb/dap/server.py +++ b/gdb/python/lib/gdb/dap/server.py @@ -46,6 +46,10 @@ _commands = {} # The global server. _server = None +# This is set by the initialize request and is used when rewriting +# line numbers. +_lines_start_at_1 = False + class DeferredRequest: """If a DAP request function returns a deferred request, no @@ -571,15 +575,15 @@ def capability(name, value=True): return wrap -def client_bool_capability(name): +def client_bool_capability(name, default=False): """Return the value of a boolean client capability. If the capability was not specified, or did not have boolean type, - False is returned.""" + DEFAULT is returned. DEFAULT defaults to False.""" global _server if name in _server.config and isinstance(_server.config[name], bool): return _server.config[name] - return False + return default @request("initialize", on_dap_thread=True) @@ -587,6 +591,8 @@ def initialize(**args): global _server, _capabilities _server.config = args _server.send_event_later("initialized") + global _lines_start_at_1 + _lines_start_at_1 = client_bool_capability("linesStartAt1", True) return _capabilities.copy() @@ -690,3 +696,27 @@ def send_gdb_with_response(fn): if isinstance(val, (Exception, KeyboardInterrupt)): raise val return val + + +def export_line(line): + """Rewrite LINE according to client capability. + This applies the linesStartAt1 capability as needed, + when sending a line number from gdb to the client.""" + global _lines_start_at_1 + if not _lines_start_at_1: + # In gdb, lines start at 1, so we only need to change this if + # the client starts at 0. + line = line - 1 + return line + + +def import_line(line): + """Rewrite LINE according to client capability. + This applies the linesStartAt1 capability as needed, + when the client sends a line number to gdb.""" + global _lines_start_at_1 + if not _lines_start_at_1: + # In gdb, lines start at 1, so we only need to change this if + # the client starts at 0. + line = line + 1 + return line |