]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add returnValue scope to DAP
authorTom Tromey <tromey@adacore.com>
Tue, 2 Jul 2024 16:43:51 +0000 (10:43 -0600)
committerTom Tromey <tromey@adacore.com>
Tue, 23 Jul 2024 17:31:49 +0000 (11:31 -0600)
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>
gdb/NEWS
gdb/python/lib/gdb/dap/scopes.py
gdb/testsuite/gdb.dap/step-out.exp

index b56ba9b36ce3c77ab2262ec365970ed626c5c94e..9a5543c0443a2e28f3e5eee4cb95c256518a885d 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -8,6 +8,10 @@
   ** The "scopes" request will now return a scope holding global
      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
   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
index d0e9115c6fa217771e68427783bcfb954f2ac8ac..fb90f647a0f621f2fc3c7131c893ab4892493a29 100644 (file)
@@ -111,20 +111,19 @@ class _ScopeReference(BaseReference):
         return symbol_value(self.var_list[idx], self.frame)
 
 
-# A _ScopeReference that prepends the most recent return value.  Note
-# that this object is only created if such a value actually exists.
+# A _ScopeReference that wraps the 'finish' value.  Note that this
+# object is only created if such a value actually exists.
 class _FinishScopeReference(_ScopeReference):
-    def __init__(self, *args):
-        super().__init__(*args)
+    def __init__(self, frame):
+        super().__init__("Return", "returnValue", frame, ())
 
     def child_count(self):
-        return super().child_count() + 1
+        return 1
 
     def fetch_one_child(self, idx):
-        if idx == 0:
-            global _last_return_value
-            return ("(return)", _last_return_value)
-        return super().fetch_one_child(idx - 1)
+        assert idx == 0
+        global _last_return_value
+        return ("(return)", _last_return_value)
 
 
 class _RegisterReference(_ScopeReference):
@@ -159,11 +158,11 @@ def scopes(*, frameId: int, **extra):
         # Make sure to handle the None case as well as the empty
         # iterator case.
         locs = tuple(frame.frame_locals() or ())
-        if has_return_value:
-            scopes.append(_FinishScopeReference("Locals", "locals", frame, locs))
-        elif locs:
+        if locs:
             scopes.append(_ScopeReference("Locals", "locals", frame, locs))
         scopes.append(_RegisterReference("Registers", frame))
+        if has_return_value:
+            scopes.append(_FinishScopeReference(frame))
         frame_to_scope[frameId] = scopes
         global_scope = get_global_scope(frame)
         if global_scope is not None:
index 31c50bb81ec522b8f189cace6b795283be7b6b7a..193264fa2504238d80b430bf511ed31b989f1842 100644 (file)
@@ -59,15 +59,21 @@ set scopes [dap_check_request_and_response "get scopes" scopes \
                [format {o frameId [i %d]} $frame_id]]
 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 presentationHint] == "locals"} \
     "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" \
                      "variables" \
                      [format {o variablesReference [i %d]} $num]] \