diff options
-rw-r--r-- | gdb/python/lib/gdb/dap/bt.py | 81 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/evaluate.py | 11 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/frames.py | 7 | ||||
-rw-r--r-- | gdb/python/lib/gdb/dap/scopes.py | 83 | ||||
-rw-r--r-- | gdb/testsuite/gdb.dap/scopes.c | 3 |
5 files changed, 81 insertions, 104 deletions
diff --git a/gdb/python/lib/gdb/dap/bt.py b/gdb/python/lib/gdb/dap/bt.py index 4439b42..0350a3b 100644 --- a/gdb/python/lib/gdb/dap/bt.py +++ b/gdb/python/lib/gdb/dap/bt.py @@ -15,67 +15,56 @@ import gdb import os +import itertools +from gdb.frames import frame_iterator +from gdb.FrameIterator import FrameIterator +from gdb.FrameDecorator import FrameDecorator from .frames import frame_id from .server import request, capability from .startup import send_gdb_with_response, in_gdb_thread from .state import set_thread -# Helper function to safely get the name of a frame as a string. -@in_gdb_thread -def _frame_name(frame): - name = frame.name() - if name is None: - name = "???" - return name - - -# Helper function to get a frame's SAL without an error. -@in_gdb_thread -def _safe_sal(frame): - try: - return frame.find_sal() - except gdb.error: - return None - - # Helper function to compute a stack trace. @in_gdb_thread def _backtrace(thread_id, levels, startFrame): set_thread(thread_id) frames = [] - current_number = 0 + if levels == 0: + # Zero means all remaining frames. + high = -1 + else: + # frame_iterator uses an inclusive range, so subtract one. + high = startFrame + levels - 1 try: - current_frame = gdb.newest_frame() + frame_iter = frame_iterator(gdb.newest_frame(), startFrame, high) except gdb.error: - current_frame = None - while current_frame is not None and (levels == 0 or len(frames) < levels): - # This condition handles the startFrame==0 case as well. - if current_number >= startFrame: - newframe = { - "id": frame_id(current_frame), - "name": _frame_name(current_frame), - # This must always be supplied, but we will set it - # correctly later if that is possible. - "line": 0, - # GDB doesn't support columns. - "column": 0, - "instructionPointerReference": hex(current_frame.pc()), + frame_iter = () + for current_frame in frame_iter: + newframe = { + "id": frame_id(current_frame), + "name": current_frame.function(), + # This must always be supplied, but we will set it + # correctly later if that is possible. + "line": 0, + # GDB doesn't support columns. + "column": 0, + "instructionPointerReference": hex(current_frame.address()), + } + line = current_frame.line() + if line is not None: + newframe["line"] = line + filename = current_frame.filename() + if filename is not None: + newframe["source"] = { + "name": os.path.basename(filename), + "path": filename, + # We probably don't need this but it doesn't hurt + # to be explicit. + "sourceReference": 0, } - sal = _safe_sal(current_frame) - if sal is not None and sal.symtab is not None: - newframe["source"] = { - "name": os.path.basename(sal.symtab.filename), - "path": sal.symtab.filename, - # We probably don't need this but it doesn't hurt - # to be explicit. - "sourceReference": 0, - } - newframe["line"] = sal.line - frames.append(newframe) - current_number = current_number + 1 - current_frame = current_frame.older() + frames.append(newframe) # Note that we do not calculate totalFrames here. Its absence # tells the client that it may simply ask for frames until a # response yields fewer frames than requested. diff --git a/gdb/python/lib/gdb/dap/evaluate.py b/gdb/python/lib/gdb/dap/evaluate.py index 5e3ebf7..635a05f 100644 --- a/gdb/python/lib/gdb/dap/evaluate.py +++ b/gdb/python/lib/gdb/dap/evaluate.py @@ -19,7 +19,7 @@ import gdb.printing # This is deprecated in 3.9, but required in older versions. from typing import Optional -from .frames import frame_for_id +from .frames import select_frame from .server import capability, request, client_bool_capability from .startup import send_gdb_with_response, in_gdb_thread from .varref import find_variable, VariableReference @@ -35,8 +35,7 @@ class EvaluateResult(VariableReference): def _evaluate(expr, frame_id): global_context = True if frame_id is not None: - frame = frame_for_id(frame_id) - frame.select() + select_frame(frame_id) global_context = False val = gdb.parse_and_eval(expr, global_context=global_context) ref = EvaluateResult(val) @@ -70,8 +69,7 @@ class _SetResult(VariableReference): def _set_expression(expression, value, frame_id): global_context = True if frame_id is not None: - frame = frame_for_id(frame_id) - frame.select() + select_frame(frame_id) global_context = False lhs = gdb.parse_and_eval(expression, global_context=global_context) rhs = gdb.parse_and_eval(value, global_context=global_context) @@ -83,8 +81,7 @@ def _set_expression(expression, value, frame_id): @in_gdb_thread def _repl(command, frame_id): if frame_id is not None: - frame = frame_for_id(frame_id) - frame.select() + select_frame(frame_id) val = gdb.execute(command, from_tty=True, to_string=True) return { "result": val, diff --git a/gdb/python/lib/gdb/dap/frames.py b/gdb/python/lib/gdb/dap/frames.py index 08209d0..1d2d137 100644 --- a/gdb/python/lib/gdb/dap/frames.py +++ b/gdb/python/lib/gdb/dap/frames.py @@ -52,3 +52,10 @@ def frame_for_id(id): """Given a frame identifier ID, return the corresponding frame.""" global _all_frames return _all_frames[id] + + +@in_gdb_thread +def select_frame(id): + """Given a frame identifier ID, select the corresponding frame.""" + frame = frame_for_id(id) + frame.inferior_frame().select() diff --git a/gdb/python/lib/gdb/dap/scopes.py b/gdb/python/lib/gdb/dap/scopes.py index 9b80dd9..1687094 100644 --- a/gdb/python/lib/gdb/dap/scopes.py +++ b/gdb/python/lib/gdb/dap/scopes.py @@ -21,41 +21,17 @@ from .server import request from .varref import BaseReference -# Helper function to return a frame's block without error. -@in_gdb_thread -def _safe_block(frame): - try: - return frame.block() - except gdb.error: - return None - - -# Helper function to return two lists of variables of block, up to the -# enclosing function. The result is of the form (ARGS, LOCALS), where -# each element is itself a list. -@in_gdb_thread -def _block_vars(block): - args = [] - locs = [] - while True: - for var in block: - if var.is_argument: - args.append(var) - elif var.is_variable or var.is_constant: - locs.append(var) - if block.function is not None: - break - block = block.superblock - return (args, locs) - - -class ScopeReference(BaseReference): +class _ScopeReference(BaseReference): def __init__(self, name, hint, frame, var_list): super().__init__(name) self.hint = hint self.frame = frame + self.inf_frame = frame.inferior_frame() self.func = frame.function() - self.var_list = var_list + self.line = frame.line() + # VAR_LIST might be any kind of iterator, but it's convenient + # here if it is just a collection. + self.var_list = tuple(var_list) def to_object(self): result = super().to_object() @@ -63,8 +39,8 @@ class ScopeReference(BaseReference): # How would we know? result["expensive"] = False result["namedVariables"] = len(self.var_list) - if self.func is not None: - result["line"] = self.func.line + if self.line is not None: + result["line"] = self.line # FIXME construct a Source object return result @@ -73,38 +49,45 @@ class ScopeReference(BaseReference): @in_gdb_thread def fetch_one_child(self, idx): + # Here SYM will conform to the SymValueWrapper interface. sym = self.var_list[idx] - if sym.needs_frame: - val = sym.value(self.frame) - else: - val = sym.value() - return (sym.print_name, val) - - -class RegisterReference(ScopeReference): + name = str(sym.symbol()) + val = sym.value() + if val is None: + # No synthetic value, so must read the symbol value + # ourselves. + val = sym.symbol().value(self.inf_frame) + elif not isinstance(val, gdb.Value): + val = gdb.Value(val) + return (name, val) + + +class _RegisterReference(_ScopeReference): def __init__(self, name, frame): super().__init__( - name, "registers", frame, list(frame.architecture().registers()) + name, "registers", frame, frame.inferior_frame().architecture().registers() ) @in_gdb_thread def fetch_one_child(self, idx): - return (self.var_list[idx].name, self.frame.read_register(self.var_list[idx])) + return ( + self.var_list[idx].name, + self.inf_frame.read_register(self.var_list[idx]), + ) # Helper function to create a DAP scopes for a given frame ID. @in_gdb_thread def _get_scope(id): frame = frame_for_id(id) - block = _safe_block(frame) scopes = [] - if block is not None: - (args, locs) = _block_vars(block) - if args: - scopes.append(ScopeReference("Arguments", "arguments", frame, args)) - if locs: - scopes.append(ScopeReference("Locals", "locals", frame, locs)) - scopes.append(RegisterReference("Registers", frame)) + args = frame.frame_args() + if args: + scopes.append(_ScopeReference("Arguments", "arguments", frame, args)) + locs = frame.frame_locals() + if locs: + scopes.append(_ScopeReference("Locals", "locals", frame, locs)) + scopes.append(_RegisterReference("Registers", frame)) return [x.to_object() for x in scopes] diff --git a/gdb/testsuite/gdb.dap/scopes.c b/gdb/testsuite/gdb.dap/scopes.c index ce87db1..a9ad4d8 100644 --- a/gdb/testsuite/gdb.dap/scopes.c +++ b/gdb/testsuite/gdb.dap/scopes.c @@ -30,6 +30,7 @@ int main () { const char *inner = "inner block"; - return 0; /* BREAK */ + /* Make sure to use 'scalar'. */ + return scalar - 23; /* BREAK */ } } |