Files
binutils-gdb/gdb/python/lib/gdb/dap/scopes.py
T
Tom Tromey 8900a92ead Implement DAP variables, scopes, and evaluate requests
The DAP code already claimed to implement "scopes" and "evaluate", but
this wasn't done completely correctly.  This patch implements these
and also implements the "variables" request.

After this patch, variables and scopes correctly report their
sub-structure.  This also interfaces with the gdb pretty-printer API,
so the output of pretty-printers is available.
2023-03-14 09:09:23 -06:00

101 lines
2.9 KiB
Python

# Copyright 2022-2023 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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 gdb
from .frames import frame_for_id
from .startup import send_gdb_with_response, in_gdb_thread
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)
else:
locs.append(var)
if block.function is not None:
break
block = block.superblock
return (args, locs)
class ScopeReference(BaseReference):
def __init__(self, name, frame, var_list):
super().__init__(name)
self.frame = frame
self.func = frame.function()
self.var_list = var_list
def to_object(self):
result = super().to_object()
# How would we know?
result["expensive"] = False
result["namedVariables"] = len(self.var_list)
if self.func is not None:
result["line"] = self.func.line
# FIXME construct a Source object
return result
def child_count(self):
return len(self.var_list)
@in_gdb_thread
def fetch_one_child(self, idx):
sym = self.var_list[idx]
if sym.needs_frame:
val = sym.value(self.frame)
else:
val = sym.value()
return (sym.print_name, val)
# 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", frame, args))
if locs:
scopes.append(ScopeReference("Locals", frame, locs))
return [x.to_object() for x in scopes]
@request("scopes")
def scopes(*, frameId, **extra):
scopes = send_gdb_with_response(lambda: _get_scope(frameId))
return {"scopes": scopes}