from .varref import BaseReference
+# Map DAP frame IDs to scopes. This ensures that scopes are re-used.
+frame_to_scope = {}
+
+
+# When the inferior is re-started, we erase all scope references. See
+# the section "Lifetime of Objects References" in the spec.
+@in_gdb_thread
+def clear_scopes(event):
+ global frame_to_scope
+ frame_to_scope = {}
+
+
+gdb.events.cont.connect(clear_scopes)
+
+
class _ScopeReference(BaseReference):
def __init__(self, name, hint, frame, var_list):
super().__init__(name)
# Helper function to create a DAP scopes for a given frame ID.
@in_gdb_thread
def _get_scope(id):
- frame = frame_for_id(id)
- scopes = []
- 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))
+ global frame_to_scope
+ if id in frame_to_scope:
+ scopes = frame_to_scope[id]
+ else:
+ frame = frame_for_id(id)
+ scopes = []
+ 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))
+ frame_to_scope[id] = scopes
return [x.to_object() for x in scopes]
[format {o frameId [i %d]} $frame_id]]
set scopes [dict get [lindex $scopes 0] body scopes]
+# Request the scopes twice, and verify that the results are identical.
+# GDB previously had a bug where it would return new scopes each time.
+set scopes2 [dap_check_request_and_response "get scopes again" scopes \
+ [format {o frameId [i %d]} $frame_id]]
+set scopes2 [dict get [lindex $scopes2 0] body scopes]
+gdb_assert {$scopes2 == $scopes} "identical scopes requests yield same body"
+
gdb_assert {[llength $scopes] == 2} "two scopes"
lassign $scopes scope reg_scope