diff options
author | Tom Tromey <tromey@adacore.com> | 2023-09-27 11:48:24 -0600 |
---|---|---|
committer | Tom Tromey <tromey@adacore.com> | 2023-10-16 09:06:17 -0600 |
commit | c1edbcf2baa650f71e4fd28a6913de07f196b4d2 (patch) | |
tree | dabca4c728bf394e8b45f0485f2084055fda53fd | |
parent | c9d954f934b64e2e3e66ed4d0652cd759eaf49f5 (diff) | |
download | gdb-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>
-rw-r--r-- | gdb/python/lib/gdb/dap/scopes.py | 38 | ||||
-rw-r--r-- | gdb/testsuite/gdb.dap/scopes.exp | 7 |
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 |