From: Tom Tromey <tromey@adacore.com>
To: gdb-patches@sourceware.org
Cc: Tom Tromey <tromey@adacore.com>
Subject: [PATCH] Add evaluateName to registers returned by DAP
Date: Thu, 3 Sep 2026 12:40:41 -0600 [thread overview]
Message-ID: <20260903184042.3954699-1-tromey@adacore.com> (raw)
This patch adds the evaluateName field to register variables returned
by DAP.
This isn't truly complete, in that referring to a sub-part of a
register won't have an evaluateName. This is a larger problem,
though, and requires a solution for pretty-printers as well.
Meanwhile, this patch helps with a pretty typical case.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33407
---
gdb/python/lib/gdb/dap/bt.py | 2 +-
gdb/python/lib/gdb/dap/globalvars.py | 2 +-
gdb/python/lib/gdb/dap/scopes.py | 18 +++++++++++-------
gdb/python/lib/gdb/dap/varref.py | 17 +++++++++++------
gdb/testsuite/gdb.dap/scopes.exp | 6 ++++++
5 files changed, 30 insertions(+), 15 deletions(-)
diff --git a/gdb/python/lib/gdb/dap/bt.py b/gdb/python/lib/gdb/dap/bt.py
index b8976e54698..38eaea7759d 100644
--- a/gdb/python/lib/gdb/dap/bt.py
+++ b/gdb/python/lib/gdb/dap/bt.py
@@ -38,7 +38,7 @@ def _compute_parameters(frame, stack_format):
result = []
for arg in arg_iter:
desc = []
- name, val = symbol_value(arg, frame)
+ name, val, _ = symbol_value(arg, frame)
# We don't try to use any particular language's syntax for the
# output here.
if stack_format["parameterTypes"]:
diff --git a/gdb/python/lib/gdb/dap/globalvars.py b/gdb/python/lib/gdb/dap/globalvars.py
index c90404362c4..70b1f64e24f 100644
--- a/gdb/python/lib/gdb/dap/globalvars.py
+++ b/gdb/python/lib/gdb/dap/globalvars.py
@@ -61,7 +61,7 @@ class _Globals(BaseReference):
@in_gdb_thread
def fetch_one_child(self, idx):
sym = self._var_list[idx]
- return (sym.print_name, sym.value())
+ return (sym.print_name, sym.value(), None)
@in_gdb_thread
diff --git a/gdb/python/lib/gdb/dap/scopes.py b/gdb/python/lib/gdb/dap/scopes.py
index 98a710f2df5..2b88a2fd15b 100644
--- a/gdb/python/lib/gdb/dap/scopes.py
+++ b/gdb/python/lib/gdb/dap/scopes.py
@@ -55,8 +55,9 @@ def set_finish_value(val):
# A helper function to compute the value of a symbol. SYM is either a
# gdb.Symbol, or an object implementing the SymValueWrapper interface.
# FRAME is a frame wrapper, as produced by a frame filter. Returns a
-# tuple of the form (NAME, VALUE), where NAME is the symbol's name and
-# VALUE is a gdb.Value.
+# tuple of the form (NAME, VALUE, None), where NAME is the symbol's
+# name and VALUE is a gdb.Value. The 'None' is returned because this
+# function is called by fetch_one_child.
@in_gdb_thread
def symbol_value(sym, frame):
inf_frame = frame.inferior_frame()
@@ -72,7 +73,7 @@ def symbol_value(sym, frame):
val = sym.symbol().value(inf_frame)
elif not isinstance(val, gdb.Value):
val = gdb.Value(val)
- return (name, val)
+ return (name, val, None)
class _ScopeReference(BaseReference):
@@ -120,7 +121,9 @@ class _FinishScopeReference(_ScopeReference):
def fetch_one_child(self, idx):
assert idx == 0
- return ("(return)", _last_return_value)
+ # It might be nice to return an evaluateName here; maybe this
+ # could be done by introducing a convenience variable.
+ return ("(return)", _last_return_value, None)
class _RegisterReference(_ScopeReference):
@@ -134,12 +137,13 @@ class _RegisterReference(_ScopeReference):
@in_gdb_thread
def fetch_one_child(self, idx):
- return (
- self._var_list[idx].name,
+ name = self._var_list[idx].name
+ value = (
frame_for_id(self._frameId)
.inferior_frame()
- .read_register(self._var_list[idx]),
+ .read_register(self._var_list[idx])
)
+ return (name, value, "$" + name)
@request("scopes")
diff --git a/gdb/python/lib/gdb/dap/varref.py b/gdb/python/lib/gdb/dap/varref.py
index e2dcd03910c..cd0321a7c82 100644
--- a/gdb/python/lib/gdb/dap/varref.py
+++ b/gdb/python/lib/gdb/dap/varref.py
@@ -107,8 +107,10 @@ class BaseReference(ABC):
"""Fetch one child of this variable.
INDEX is the index of the child to fetch.
- This should return a tuple of the form (NAME, VALUE), where
- NAME is the name of the variable, and VALUE is a gdb.Value."""
+ This should return a tuple of the form (NAME, VALUE, EVAL_NAME),
+ where NAME is the name of the variable, and VALUE is a gdb.Value.
+ EVAL_NAME may either be None, or a string that is used as the
+ variable's 'evaluateName'."""
return
@abstractmethod
@@ -153,9 +155,9 @@ class BaseReference(ABC):
if idx >= len(self._children):
break
if self._children[idx] is None:
- name, value = self.fetch_one_child(idx)
+ name, value, eval_name = self.fetch_one_child(idx)
name = self._compute_name(name)
- var = VariableReference(name, value)
+ var = VariableReference(name, value, eval_name=eval_name)
self._children[idx] = var
self._by_name[name] = var
yield self._children[idx]
@@ -176,7 +178,7 @@ class BaseReference(ABC):
class VariableReference(BaseReference):
"""Concrete subclass of BaseReference that handles gdb.Value."""
- def __init__(self, name, value, result_name="value"):
+ def __init__(self, name, value, result_name="value", eval_name=None):
"""Initializer.
NAME is the name of this reference, see superclass.
@@ -186,6 +188,7 @@ class VariableReference(BaseReference):
super().__init__(name)
self._result_name = result_name
self._value = value
+ self._eval_name = eval_name
self._update_value()
# Internal method to update local data when the value changes.
@@ -261,6 +264,8 @@ class VariableReference(BaseReference):
result["memoryReference"] = hex(int(self._value))
if client_bool_capability("supportsVariableType"):
result["type"] = str(self._value.type)
+ if self._eval_name is not None:
+ result["evaluateName"] = self._eval_name
return result
@in_gdb_thread
@@ -275,7 +280,7 @@ class VariableReference(BaseReference):
# gdb.Value, but it must be convertible.
if not isinstance(val, gdb.Value):
val = gdb.Value(val)
- return (name, val)
+ return (name, val, None)
@in_gdb_thread
diff --git a/gdb/testsuite/gdb.dap/scopes.exp b/gdb/testsuite/gdb.dap/scopes.exp
index d22d39cbf8b..eb3e6a5e04f 100644
--- a/gdb/testsuite/gdb.dap/scopes.exp
+++ b/gdb/testsuite/gdb.dap/scopes.exp
@@ -153,6 +153,12 @@ lassign [dap_check_request_and_response "fetch all registers" \
# If any register has children, try to fetch those as well. This is a
# regression test for part of PR dap/33228.
foreach var [dict get $val body variables] {
+ # Check that gdb emits an evaluateName for each register.
+ set name [dict get $var name]
+ set evalName [dict get $var evaluateName]
+ gdb_assert {[string cat "$" $name] == $evalName} \
+ "evaluateName for register $name"
+
set regvar [dict get $var variablesReference]
if {$regvar > 0} {
# If variablesReference is non-zero, then there must be either
base-commit: 2986ed8ba365f7e583e2f6c9098ea5ec57ee50e1
--
2.55.0
reply other threads:[~2026-09-03 18:41 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260903184042.3954699-1-tromey@adacore.com \
--to=tromey@adacore.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox