aboutsummaryrefslogtreecommitdiff
path: root/gdb/python
diff options
context:
space:
mode:
authorTom Tromey <tromey@adacore.com>2024-12-16 10:44:55 -0700
committerTom Tromey <tromey@adacore.com>2025-01-06 07:32:11 -0700
commit8ac42dbf5001416e6b741c5361be14186afde5b0 (patch)
treea05b26736fc12b4813f00d487cba2e5b6e0796d8 /gdb/python
parent350609bb98cee92c6b4fbd334b99066683b9e5c1 (diff)
downloadbinutils-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.py6
-rw-r--r--gdb/python/lib/gdb/dap/bt.py7
-rw-r--r--gdb/python/lib/gdb/dap/disassemble.py4
-rw-r--r--gdb/python/lib/gdb/dap/locations.py7
-rw-r--r--gdb/python/lib/gdb/dap/scopes.py4
-rw-r--r--gdb/python/lib/gdb/dap/server.py36
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