aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorTom Tromey <tromey@adacore.com>2023-09-27 11:48:24 -0600
committerTom Tromey <tromey@adacore.com>2023-10-16 09:06:17 -0600
commitc1edbcf2baa650f71e4fd28a6913de07f196b4d2 (patch)
treedabca4c728bf394e8b45f0485f2084055fda53fd /gdb
parentc9d954f934b64e2e3e66ed4d0652cd759eaf49f5 (diff)
downloadgdb-c1edbcf2baa650f71e4fd28a6913de07f196b4d2.zip
gdb-c1edbcf2baa650f71e4fd28a6913de07f196b4d2.tar.gz
gdb-c1edbcf2baa650f71e4fd28a6913de07f196b4d2.tar.bz2
Add DAP scope cache
Andry Ogorodnik, a co-worker, noticed that multiple "scopes" requests with the same frame would yield different variableReference values in the response. This patch adds a regression test for this, and adds a scope cache in scopes.py, ensuring that multiple identical requests will get the same response. Tested-By: Alexandra Petlanova Hajkova <ahajkova@redhat.com>
Diffstat (limited to 'gdb')
-rw-r--r--gdb/python/lib/gdb/dap/scopes.py38
-rw-r--r--gdb/testsuite/gdb.dap/scopes.exp7
2 files changed, 36 insertions, 9 deletions
diff --git a/gdb/python/lib/gdb/dap/scopes.py b/gdb/python/lib/gdb/dap/scopes.py
index 4874d00..5dde060 100644
--- a/gdb/python/lib/gdb/dap/scopes.py
+++ b/gdb/python/lib/gdb/dap/scopes.py
@@ -21,6 +21,21 @@ from .server import request
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)
@@ -83,15 +98,20 @@ class _RegisterReference(_ScopeReference):
# 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]
diff --git a/gdb/testsuite/gdb.dap/scopes.exp b/gdb/testsuite/gdb.dap/scopes.exp
index 6937bad..003557c 100644
--- a/gdb/testsuite/gdb.dap/scopes.exp
+++ b/gdb/testsuite/gdb.dap/scopes.exp
@@ -52,6 +52,13 @@ 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]
+# 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