mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-09 00:53:10 +00:00
Add returnValue scope to DAP
The DAP spec recently changed to add a new scope for the return value
from a "stepOut" request. This new scope uses the "returnValue"
presentation hint. See:
https://github.com/microsoft/debug-adapter-protocol/issues/458
This patch implements this for gdb.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31945
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
This commit is contained in:
4
gdb/NEWS
4
gdb/NEWS
@@ -8,6 +8,10 @@
|
|||||||
** The "scopes" request will now return a scope holding global
|
** The "scopes" request will now return a scope holding global
|
||||||
variables from the stack frame's compilation unit.
|
variables from the stack frame's compilation unit.
|
||||||
|
|
||||||
|
** The "scopes" request will return a "returnValue" scope holding
|
||||||
|
the return value from the latest "stepOut" command, when
|
||||||
|
appropriate.
|
||||||
|
|
||||||
* For ARM targets, the offset of the pc in the jmp_buf has been fixed to match
|
* For ARM targets, the offset of the pc in the jmp_buf has been fixed to match
|
||||||
glibc 2.20 and later. This should only matter when not using libc probes.
|
glibc 2.20 and later. This should only matter when not using libc probes.
|
||||||
This may cause breakage when using an incompatible libc, like uclibc or
|
This may cause breakage when using an incompatible libc, like uclibc or
|
||||||
|
|||||||
@@ -111,20 +111,19 @@ class _ScopeReference(BaseReference):
|
|||||||
return symbol_value(self.var_list[idx], self.frame)
|
return symbol_value(self.var_list[idx], self.frame)
|
||||||
|
|
||||||
|
|
||||||
# A _ScopeReference that prepends the most recent return value. Note
|
# A _ScopeReference that wraps the 'finish' value. Note that this
|
||||||
# that this object is only created if such a value actually exists.
|
# object is only created if such a value actually exists.
|
||||||
class _FinishScopeReference(_ScopeReference):
|
class _FinishScopeReference(_ScopeReference):
|
||||||
def __init__(self, *args):
|
def __init__(self, frame):
|
||||||
super().__init__(*args)
|
super().__init__("Return", "returnValue", frame, ())
|
||||||
|
|
||||||
def child_count(self):
|
def child_count(self):
|
||||||
return super().child_count() + 1
|
return 1
|
||||||
|
|
||||||
def fetch_one_child(self, idx):
|
def fetch_one_child(self, idx):
|
||||||
if idx == 0:
|
assert idx == 0
|
||||||
global _last_return_value
|
global _last_return_value
|
||||||
return ("(return)", _last_return_value)
|
return ("(return)", _last_return_value)
|
||||||
return super().fetch_one_child(idx - 1)
|
|
||||||
|
|
||||||
|
|
||||||
class _RegisterReference(_ScopeReference):
|
class _RegisterReference(_ScopeReference):
|
||||||
@@ -159,11 +158,11 @@ def scopes(*, frameId: int, **extra):
|
|||||||
# Make sure to handle the None case as well as the empty
|
# Make sure to handle the None case as well as the empty
|
||||||
# iterator case.
|
# iterator case.
|
||||||
locs = tuple(frame.frame_locals() or ())
|
locs = tuple(frame.frame_locals() or ())
|
||||||
if has_return_value:
|
if locs:
|
||||||
scopes.append(_FinishScopeReference("Locals", "locals", frame, locs))
|
|
||||||
elif locs:
|
|
||||||
scopes.append(_ScopeReference("Locals", "locals", frame, locs))
|
scopes.append(_ScopeReference("Locals", "locals", frame, locs))
|
||||||
scopes.append(_RegisterReference("Registers", frame))
|
scopes.append(_RegisterReference("Registers", frame))
|
||||||
|
if has_return_value:
|
||||||
|
scopes.append(_FinishScopeReference(frame))
|
||||||
frame_to_scope[frameId] = scopes
|
frame_to_scope[frameId] = scopes
|
||||||
global_scope = get_global_scope(frame)
|
global_scope = get_global_scope(frame)
|
||||||
if global_scope is not None:
|
if global_scope is not None:
|
||||||
|
|||||||
@@ -59,15 +59,21 @@ set scopes [dap_check_request_and_response "get scopes" scopes \
|
|||||||
[format {o frameId [i %d]} $frame_id]]
|
[format {o frameId [i %d]} $frame_id]]
|
||||||
set scopes [dict get [lindex $scopes 0] body scopes]
|
set scopes [dict get [lindex $scopes 0] body scopes]
|
||||||
|
|
||||||
gdb_assert {[llength $scopes] == 2} "two scopes"
|
gdb_assert {[llength $scopes] == 3} "three scopes"
|
||||||
|
|
||||||
lassign $scopes scope reg_scope
|
lassign $scopes scope reg_scope return_scope
|
||||||
gdb_assert {[dict get $scope name] == "Locals"} "scope is locals"
|
gdb_assert {[dict get $scope name] == "Locals"} "scope is locals"
|
||||||
gdb_assert {[dict get $scope presentationHint] == "locals"} \
|
gdb_assert {[dict get $scope presentationHint] == "locals"} \
|
||||||
"locals presentation hint"
|
"locals presentation hint"
|
||||||
gdb_assert {[dict get $scope namedVariables] == 2} "two vars in scope"
|
gdb_assert {[dict get $scope namedVariables] == 1} "one var in scope"
|
||||||
|
|
||||||
set num [dict get $scope variablesReference]
|
gdb_assert {[dict get $return_scope name] == "Return"} "scope is return"
|
||||||
|
gdb_assert {[dict get $return_scope presentationHint] == "returnValue"} \
|
||||||
|
"returnValue presentation hint"
|
||||||
|
gdb_assert {[dict get $return_scope namedVariables] == 1} \
|
||||||
|
"one var in return scope"
|
||||||
|
|
||||||
|
set num [dict get $return_scope variablesReference]
|
||||||
set refs [lindex [dap_check_request_and_response "fetch arguments" \
|
set refs [lindex [dap_check_request_and_response "fetch arguments" \
|
||||||
"variables" \
|
"variables" \
|
||||||
[format {o variablesReference [i %d]} $num]] \
|
[format {o variablesReference [i %d]} $num]] \
|
||||||
|
|||||||
Reference in New Issue
Block a user