From: Pedro Alves <pedro@palves.net>
To: gdb-patches@sourceware.org
Subject: [PATCH] Make gdb_caching_proc support namespaces
Date: Tue, 16 Sep 2025 00:57:11 +0100 [thread overview]
Message-ID: <f187f2d1-f9d3-4862-ac51-5864da35c7ae@palves.net> (raw)
In-Reply-To: <3e29d575-22c4-42b7-a8e9-2d57b7367a49@palves.net>
On 2025-09-15 22:54, Pedro Alves wrote:
> I should have mentioned something here:
>
> On 2025-09-15 22:28, Pedro Alves wrote:
>
>> --- a/gdb/testsuite/lib/cache.exp
>> +++ b/gdb/testsuite/lib/cache.exp
>> @@ -24,26 +24,9 @@ proc ignore_pass { msg } {
>>
>> # Call proc real_name and return the result, while ignoring calls to pass.
>> proc gdb_do_cache_wrap {real_name args} {
>> - if { [info procs save_pass] != "" } {
>> - return [uplevel 2 $real_name]
>> + with_override pass ignore_pass {
>> + return [$real_name {*}$args]
>> }
>
> The previous code was using "uplevel 2" here. But I'm struggling to see why that is the
> right level.
>
> When gdb_do_cache_wrap is called via gdb_caching_proc => gdb_do_cache, that takes us to the scope of
> the caller of the gdb_caching_proc, which off hand would seem right.
>
> However, when gdb_do_cache_wrap is called directly by gdb.testsuite/gdb-caching-proc-consistency.exp, it
> takes us to ... the caller of test_proc?
>
> So I'm wondering, what could we possibly want to reference from a higher level in gdb_do_cache_wrap
> that not having the uplevel in gdb_do_cache_wrap would get wrong? A caching proc IMO shouldn't be doing
> something like taking the name of a variable as argument instead of a value, as then the procedure wouldn't
> be guaranteed to be idempotent? So I dropped the uplevel, and found that that doesn't cause any
> testsuite regression. But maybe I'm missing something. If I am, it'd be nice to add a testcase for it.
Trying to find a testcase for the above, I thought to try a gdb_caching_proc defined in a namespace,
and have that proc access a namespace variable, in its own namespace.
That ran into the fact that gdb_caching_proc doesn't support namespaces today. So I fixed that, with
the patch below (on top of the previous one), which includes tests. That still didn't require any
uplevel in gdb_do_cache_wrap.
I don't have a current use for this, but I figure that eventually we will find a use, and since
I wrote it...
== 8< ===
From e9bad21e186f6024cbbecc97b4b0f593bc8ed7ea Mon Sep 17 00:00:00 2001
From: Pedro Alves <pedro@palves.net>
Date: Tue, 16 Sep 2025 00:41:30 +0100
Subject: [PATCH] Make gdb_caching_proc support namespaces
Currently, defining a gdb_caching_proc in a namespace, like:
namespace eval myns {
gdb_caching_proc nsproc {} {
return 1
}
}
Incorrectly defines the advertised procedure in the global namespace
instead of in the namespace of the procedure being wrapped.
I.e., for the example above, calling myns::nsproc would fail, and
calling "::nsproc" would succeed.
This patch fixes it, and adds tests to
gdb.testsuite/gdb-caching-proc.exp.
Change-Id: I1853f9f411406331eb44d53d028d65a3d400db7f
---
.../gdb.testsuite/gdb-caching-proc.exp | 39 ++++++++++----
gdb/testsuite/lib/cache.exp | 54 ++++++++++++-------
2 files changed, 65 insertions(+), 28 deletions(-)
diff --git a/gdb/testsuite/gdb.testsuite/gdb-caching-proc.exp b/gdb/testsuite/gdb.testsuite/gdb-caching-proc.exp
index 6b46b1c555a..8b5168e5394 100644
--- a/gdb/testsuite/gdb.testsuite/gdb-caching-proc.exp
+++ b/gdb/testsuite/gdb.testsuite/gdb-caching-proc.exp
@@ -27,27 +27,46 @@ gdb_caching_proc gdb_testsuite_gdb_caching_proc_exp_arg_nested { arg } {
return [gdb_testsuite_gdb_caching_proc_exp_arg $arg]
}
-# List of "expected $::count after running expression" and
+namespace eval myns {
+ variable ns_count 1
+
+ gdb_caching_proc nsproc {} {
+ variable ns_count
+ incr ns_count
+ return 1
+ }
+}
+
+gdb_caching_proc ::fq_proc {} {
+ incr ::count
+ return 1
+}
+
+# List of "VAR, expected value of VAR after running expression", and
# "expression".
set assertions {
- 1 { [gdb_testsuite_gdb_caching_proc_exp_noarg] == 1 }
- 1 { [gdb_testsuite_gdb_caching_proc_exp_arg 1] == 1 }
- 1 { [gdb_testsuite_gdb_caching_proc_exp_arg "foo foo"] == "foo foo" }
- 1 { [gdb_testsuite_gdb_caching_proc_exp_arg_nested "foo foo"] == "foo foo" }
- 2 { [gdb_testsuite_gdb_caching_proc_exp_arg_nested "bar bar"] == "bar bar" }
+ count 2 { [gdb_testsuite_gdb_caching_proc_exp_noarg] == 1 }
+ count 2 { [gdb_testsuite_gdb_caching_proc_exp_arg 1] == 1 }
+ count 2 { [gdb_testsuite_gdb_caching_proc_exp_arg "foo foo"] == "foo foo" }
+ count 2 { [gdb_testsuite_gdb_caching_proc_exp_arg_nested "foo foo"] == "foo foo" }
+ count 3 { [gdb_testsuite_gdb_caching_proc_exp_arg_nested "bar bar"] == "bar bar" }
+ count 2 { [fq_proc] == 1 }
+ myns::ns_count 2 { [myns::nsproc] == 1 }
}
set assertion_nr 0
-foreach {expected_count assertion} $assertions {
+foreach {var expected_var_value assertion} $assertions {
with_test_prefix $assertion_nr {
- set ::count 0
+ # Start at 1 to be sure the "incr" in the test procs isn't the
+ # one creating the variable.
+ set $var 1
gdb_assert $assertion
- gdb_assert { $::count == $expected_count }
+ gdb_assert { [set $var] == $expected_var_value }
with_test_prefix cached {
gdb_assert $assertion
- gdb_assert { $::count == $expected_count }
+ gdb_assert { [set $var] == $expected_var_value }
}
}
incr assertion_nr
diff --git a/gdb/testsuite/lib/cache.exp b/gdb/testsuite/lib/cache.exp
index b4c5fab2b98..bbe07387b21 100644
--- a/gdb/testsuite/lib/cache.exp
+++ b/gdb/testsuite/lib/cache.exp
@@ -78,31 +78,29 @@ proc gdb_cache_maybe_gdb_exit { name do_exit also_called } {
return
}
- # To track if this proc has been called for NAME we create a
- # global variable. In gdb_cleanup_globals (see gdb.exp) this
- # global will be deleted when the test has finished.
- set global_name __${name}__cached_gdb_exit_called
- if { ![info exists ::${global_name}] } {
+ # To track if this proc has been called for NAME we use a global
+ # array. In gdb_cleanup_globals (see gdb.exp) this array will be
+ # deleted when the test has finished.
+ if { ![info exists ::gdb_caching_proc_called($name)] } {
gdb_exit
verbose -log "gdb_caching_proc $name caused gdb_exit to be called"
- set ::${global_name} true
- verbose -log " gdb_caching_proc $name marked as called"
+ set ::gdb_caching_proc_called($name) true
+ verbose -log " gdb_caching_proc $name marked as called"
foreach other_name $also_called {
verbose -log " gdb_caching_proc $other_name marked as called"
- set global_name __${other_name}__cached_gdb_exit_called
- set ::${global_name} true
+ set ::gdb_caching_proc_called($other_name) true
}
}
}
# A helper for gdb_caching_proc that handles the caching.
-proc gdb_do_cache {name args} {
+proc gdb_do_cache {name real_name args} {
global gdb_data_cache objdir
global GDB_PARALLEL
- verbose -log "gdb_do_cache: $name ( $args )"
+ verbose -log "gdb_do_cache: $name $real_name ( $args )"
# Normally, if we have a cached value, we skip computation and return
# the cached value. If set to 1, instead don't skip computation and
@@ -115,11 +113,15 @@ proc gdb_do_cache {name args} {
set cache_verify 1
}
+ # NAME is always a fully qualified name here. Don't include the
+ # leading "::" in the cache file name.
+ set cache_file_name [string range $name 2 end]
+
# See if some other process wrote the cache file. Cache value per
# "board" to handle runs with multiple options
# (e.g. unix/{-m32,-64}) correctly. We use "file join" here
# because we later use this in a real filename.
- set cache_name [file join [target_info name] $name {*}$args]
+ set cache_name [file join [target_info name] $cache_file_name {*}$args]
set is_cached 0
if {[info exists gdb_data_cache(${cache_name},value)]} {
@@ -194,7 +196,6 @@ proc gdb_do_cache {name args} {
set old_gdb_nested_caching_proc_calls $::gdb_nested_caching_proc_calls
set ::gdb_nested_caching_proc_calls {}
- set real_name gdb_real__$name
set gdb_data_cache(${cache_name},value) [gdb_do_cache_wrap $real_name {*}$args]
set gdb_data_cache(${cache_name},exit) $::gdb_exit_called
set gdb_data_cache(${cache_name},also_called) \
@@ -276,15 +277,32 @@ proc gdb_do_cache {name args} {
#
proc gdb_caching_proc {name arglist body} {
- # Define the underlying proc that we'll call.
- set real_name gdb_real__$name
- proc $real_name $arglist $body
+ # Figure out the caller's namespace.
+ set ns [uplevel 1 {namespace current}]
+
+ # Normalize the advertised name.
+ if {[string match ::* $name]} {
+ set fq_name $name
+ } elseif {$ns eq "::"} {
+ set fq_name ::$name
+ } else {
+ set fq_name ${ns}::$name
+ }
+
+ set tail [namespace tail $fq_name]
+ set qual [namespace qualifiers $fq_name]
+
+ # The name of the underlying proc that we'll call.
+ set fq_real_name ${qual}::gdb_real__$tail
+
+ # Define it.
+ proc $fq_real_name $arglist $body
# Define the advertised proc.
- set caching_proc_body [list gdb_do_cache $name]
+ set caching_proc_body [list gdb_do_cache $fq_name $fq_real_name]
foreach arg $arglist {
lappend caching_proc_body $$arg
}
set caching_proc_body [join $caching_proc_body]
- proc $name $arglist $caching_proc_body
+ proc $fq_name $arglist $caching_proc_body
}
base-commit: d09eba07ca013e6b95eeafd67d79c32ebf6f28eb
prerequisite-patch-id: 7193acb0815df9f5fbc926bb2169131538e88bd5
--
2.51.0
next prev parent reply other threads:[~2025-09-15 23:57 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-15 21:28 [PATCH] Fix nested gdb_caching_proc with args; Fix gdb.rocm/ tests Pedro Alves
2025-09-15 21:54 ` Pedro Alves
2025-09-15 23:57 ` Pedro Alves [this message]
2025-09-16 3:55 ` [PATCH] Make gdb_caching_proc support namespaces Simon Marchi
2025-09-16 9:31 ` [PATCH v2] Fix nested gdb_caching_proc with args; Fix gdb.rocm/ tests Pedro Alves
2025-09-16 10:56 ` Pedro Alves
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=f187f2d1-f9d3-4862-ac51-5864da35c7ae@palves.net \
--to=pedro@palves.net \
--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