* [PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols
@ 2025-10-29 12:58 Guinevere Larsen
2025-10-29 12:58 ` [PATCH v6 1/3] gdb: make lookup_minimal_symbol_linkage work with linker namespaces Guinevere Larsen
` (3 more replies)
0 siblings, 4 replies; 16+ messages in thread
From: Guinevere Larsen @ 2025-10-29 12:58 UTC (permalink / raw)
To: gdb-patches; +Cc: Guinevere Larsen
This series adds support for the syntax [[N]]::foo to find symbols that
belong to specific namespaces, while also making GDB's behavior more
consistent when a namespace is not specified. This needs one preparatory
patch and 2 patches actually implementing this feature
Patch 1 is an essential fix, updating how we calculate a variable's copy
relocation to take linker namespaces into account.
Patches 2 and 3 implement the new syntax, adding the necessary
supporting code and updating error messages when symbols can't be found
- where it made sense.
Changes for v6:
* Rebased on master
* Fixed a crash when using the [[N]]::foo syntax before starting the
inferior
Changes for v5:
* fixed crash when getting the value of a variable before the inferior
starts.
* Rebased on master
Changes for v4:
* Fixed final documentation feedback from Eli.
* Changed error message when [[N]]::foo::bar fails to find 'foo'.
* Fixed build breakage.
Changes for v3:
* Removed previous patches 1 and 2, as Simon's recently merged patches
already did those in a better way.
* parser_state now also takes the current solib_ops, since that can't be
obtained from gdbarch anymore.
Changes for v2:
* solib_supports_linker_namespaces now always expects a pointer.
* Previous patches 2 and 3 were dropped.
* lookup_minimal_symbol_linkage now takes an array_view.
* created new tokens for [[ and ]], to ensure that [[N]] looks like
that.
* Fixed formatting nits from Eli.
Guinevere Larsen (3):
gdb: make lookup_minimal_symbol_linkage work with linker namespaces
gdb: Make the parser recognize the [[N]] syntax for variables
gdb: extend the [[N]]::foo syntax for files
gdb/NEWS | 6 +
gdb/c-exp.y | 88 +++++++++---
gdb/doc/gdb.texinfo | 6 +
gdb/dwarf2/ada-imported.c | 8 +-
gdb/linespec.c | 4 +-
gdb/minsyms.c | 139 ++++++++++++-------
gdb/minsyms.h | 17 ++-
gdb/parse.c | 3 +-
gdb/parser-defs.h | 39 +++++-
gdb/rust-parse.c | 3 +-
gdb/solib-svr4.c | 20 ---
gdb/solib.c | 86 +++++++++++-
gdb/solib.h | 19 +++
gdb/symtab.c | 76 ++++++++--
gdb/symtab.h | 15 +-
gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c | 14 ++
gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c | 3 +
gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 65 +++++++++
18 files changed, 499 insertions(+), 112 deletions(-)
base-commit: 0633b78640dc892265d148f24881d544d4ddd16e
--
2.51.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v6 1/3] gdb: make lookup_minimal_symbol_linkage work with linker namespaces
2025-10-29 12:58 [PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols Guinevere Larsen
@ 2025-10-29 12:58 ` Guinevere Larsen
2026-01-28 11:22 ` Andrew Burgess
2025-10-29 12:58 ` [PATCH v6 2/3] gdb: Make the parser recognize the [[N]] syntax for variables Guinevere Larsen
` (2 subsequent siblings)
3 siblings, 1 reply; 16+ messages in thread
From: Guinevere Larsen @ 2025-10-29 12:58 UTC (permalink / raw)
To: gdb-patches; +Cc: Guinevere Larsen
When a symbol found by GDB may have copy relocation, GDB calculates the
address of the symbol by checking all the objfiles in the current
program space for another instance of the same symbol, and returns the
address of the first instance found.
This works well when linker namespaces are not involved, but fails when
a symbol is present in more than one namespace. That's because copy
relocations respect linker namespace boundaries, and so if we're trying
to find the symbol in namespace N, the symbol from a different namespace
M may be returned, if the SO containing the symbol was loaded in M
before N.
To make the search work correctly, lookup_minimal_symbol_linkage would
need to also respect linker namespace boundaries. However, to avoid
leaking solib knowledge to minsyms, and because of how little
information is passed to the function, this commit instead makes the
function take a vector of objfiles to search, in place of the program
space. This makes it so symbol::get_maybe_copied_address (and the
equivalent of minimal_symbol) need to request the objfiles for the
correct namespace, since they have enough context to figure out the
namespace. Creating the vector is left as a function in solib.c
Since minimal_symbol::get_maybe_copied_address only searches main_file
objfiles, if we can guarantee that only one is loaded for each program
space, we could avoid the work of constructing an std::vector that will
be mostly ignored. However, I couldn't convince myself that that is the
case, so I decided to keep the behavior exactly as is.
Ideally, lookup_minimal_symbol_linkage would receive an iterator instead
of a vector, but as of now it isn't possible to do forward declarations
of nested types (we'd need program_space::objfiles_range) and
progspace.h can't be included into minsyms.h, so we're stuck
constructing a vector for it.
Finally, as some minor refactoring, find_solib_for_objfile is moved to
solib.c to simplify looking for which namespace contains the objfile
where we found the symbol the user was looking for.
---
gdb/dwarf2/ada-imported.c | 8 +++-
gdb/minsyms.c | 15 ++++---
gdb/minsyms.h | 9 ++--
gdb/solib-svr4.c | 20 ---------
gdb/solib.c | 86 ++++++++++++++++++++++++++++++++++++++-
gdb/solib.h | 19 +++++++++
gdb/symtab.c | 13 +++++-
7 files changed, 136 insertions(+), 34 deletions(-)
diff --git a/gdb/dwarf2/ada-imported.c b/gdb/dwarf2/ada-imported.c
index 48e6fccdb73..15ecfdaf6ce 100644
--- a/gdb/dwarf2/ada-imported.c
+++ b/gdb/dwarf2/ada-imported.c
@@ -35,9 +35,13 @@ static struct value *
ada_imported_read_variable (struct symbol *symbol, const frame_info_ptr &frame)
{
const char *name = get_imported_name (symbol);
+
+ std::vector<objfile *> objfiles_to_search;
+ for (objfile &objf : symbol->objfile ()->pspace ()->objfiles ())
+ objfiles_to_search.push_back (&objf);
+
bound_minimal_symbol minsym
- = lookup_minimal_symbol_linkage (symbol->objfile ()->pspace (), name,
- true, false);
+ = lookup_minimal_symbol_linkage (objfiles_to_search, name, true, false);
if (minsym.minsym == nullptr)
error (_("could not find imported name %s"), name);
return value_at (symbol->type (), minsym.value_address ());
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 90a0c601c59..7e4f47b8c3f 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -54,6 +54,7 @@
#include "gdbsupport/cxx-thread.h"
#include "gdbsupport/parallel-for.h"
#include "inferior.h"
+#include "solib.h"
/* Return true if MINSYM is a cold clone symbol.
Recognize f.i. these symbols (mangled/demangled):
@@ -584,19 +585,21 @@ lookup_minimal_symbol_linkage (const char *name, struct objfile *objf,
/* See minsyms.h. */
bound_minimal_symbol
-lookup_minimal_symbol_linkage (program_space *pspace, const char *name,
- bool match_static_type, bool only_main)
+lookup_minimal_symbol_linkage (gdb::array_view<objfile *> objfiles_to_search,
+ const char *name, bool match_static_type,
+ bool only_main)
{
- for (objfile &objfile : pspace->objfiles ())
+ for (objfile *objfile : objfiles_to_search)
{
- if (objfile.separate_debug_objfile_backlink != nullptr)
+ if (objfile == nullptr
+ || objfile->separate_debug_objfile_backlink != nullptr)
continue;
- if (only_main && (objfile.flags & OBJF_MAINLINE) == 0)
+ if (only_main && (objfile->flags & OBJF_MAINLINE) == 0)
continue;
bound_minimal_symbol minsym
- = lookup_minimal_symbol_linkage (name, &objfile, match_static_type);
+ = lookup_minimal_symbol_linkage (name, objfile, match_static_type);
if (minsym.minsym != nullptr)
return minsym;
}
diff --git a/gdb/minsyms.h b/gdb/minsyms.h
index ed38044a38c..4aa8a428470 100644
--- a/gdb/minsyms.h
+++ b/gdb/minsyms.h
@@ -237,11 +237,14 @@ extern bound_minimal_symbol lookup_minimal_symbol_linkage
/* A variant of lookup_minimal_symbol_linkage that iterates over all
objfiles of PSPACE. If ONLY_MAIN is true, then only an objfile with
- OBJF_MAINLINE will be considered. */
+ OBJF_MAINLINE will be considered. This function should receive a
+ program_space::objfile_ranges instead, but we can't include progspace.h
+ here, nor can we do forward declarations of nested types, so std::vector
+ will waste a bit of memory to work around that issue. */
extern bound_minimal_symbol lookup_minimal_symbol_linkage
- (program_space *pspace, const char *name, bool match_static_type,
- bool only_main) ATTRIBUTE_NONNULL (1);
+ (gdb::array_view<objfile *> objfiles_to_search, const char *name,
+ bool match_static_type, bool only_main);
/* Look through all the current minimal symbol tables and find the
first minimal symbol that matches NAME and PC. If OBJF is non-NULL,
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index c91e0b2c37b..49d2b207c36 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -3595,26 +3595,6 @@ lp64_svr4_solib_ops::fetch_link_map_offsets () const
}
\f
-/* Return the DSO matching OBJFILE or nullptr if none can be found. */
-
-static const solib *
-find_solib_for_objfile (struct objfile *objfile)
-{
- if (objfile == nullptr)
- return nullptr;
-
- /* If OBJFILE is a separate debug object file, look for the original
- object file. */
- if (objfile->separate_debug_objfile_backlink != nullptr)
- objfile = objfile->separate_debug_objfile_backlink;
-
- for (const solib &so : current_program_space->solibs ())
- if (so.objfile == objfile)
- return &so;
-
- return nullptr;
-}
-
/* Return the address of the r_debug object for the namespace containing
SOLIB or zero if it cannot be found. This may happen when symbol files
are added manually, for example, or with the main executable.
diff --git a/gdb/solib.c b/gdb/solib.c
index dade2a76a48..34b0d6b3f9c 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -1825,8 +1825,92 @@ solib_linker_namespace_count (program_space *pspace)
return 0;
}
-/* Implementation of the linker_namespace convenience variable.
+/* See solib.h. */
+
+const solib *
+find_solib_for_objfile (struct objfile *objfile)
+{
+ if (objfile == nullptr)
+ return nullptr;
+
+ /* If OBJFILE is a separate debug object file, look for the original
+ object file. */
+ if (objfile->separate_debug_objfile_backlink != nullptr)
+ objfile = objfile->separate_debug_objfile_backlink;
+
+ for (const solib &so : objfile->pspace ()->solibs ())
+ if (so.objfile == objfile)
+ return &so;
+
+ return nullptr;
+}
+
+/* See solib.h. */
+
+std::vector<objfile *>
+get_objfiles_in_linker_namespace (int nsid, program_space *pspace)
+{
+ std::vector<objfile *> objfiles_in_ns;
+ const solib_ops *ops = pspace->solib_ops ();
+
+ gdb_assert (ops->supports_namespaces ());
+
+ /* If we're looking at the default namespace, we also need
+ to add the mainline objfiles by hand, since there is no
+ solib associated with those files. We add them first
+ because if we're searching for copy relocations, they
+ should be in the main file, so we'll find it faster. */
+ if (nsid == 0)
+ for (objfile &objf : pspace->objfiles ())
+ if ((objf.flags & OBJF_MAINLINE) != 0)
+ objfiles_in_ns.push_back (&objf);
+
+ std::vector<const solib *> solibs = ops->get_solibs_in_ns (nsid);
+ /* Reserve for efficiency. */
+ objfiles_in_ns.reserve (solibs.size () + objfiles_in_ns.size ());
+ for (const solib *so : solibs)
+ objfiles_in_ns.push_back (so->objfile);
+
+ return objfiles_in_ns;
+}
+
+/* See solib.h. */
+
+std::vector<objfile *>
+get_objfiles_in_linker_namespace (objfile *objfile)
+{
+ program_space *pspace = objfile->pspace ();
+ const solib_ops *ops = pspace->solib_ops ();
+ const solib *so = find_solib_for_objfile (objfile);
+
+ /* If the inferior hasn't started yet, the solib_ops won't be
+ set for the program space. Since namespaces only make sense
+ when the inferior has already created some, we can just skip
+ it here. */
+ if (ops != nullptr && ops->supports_namespaces ()
+ /* If we're searching for a symbol from the linker, we'll reach here
+ before having any namespaces. Return all objfiles since the
+ boundaries haven't been setup yet. */
+ && ops->num_active_namespaces () > 0
+ /* When trying to load libthread_db, we can search for a symbol in an
+ objfile with no associated solib. In that case, again, we should
+ return all objfiles. */
+ && so != nullptr)
+ {
+ return get_objfiles_in_linker_namespace (ops->find_solib_ns (*so),
+ pspace);
+ }
+
+ /* If any of the previous conditions isn't satisfied, we return
+ the full list of objfiles in the inferior. */
+ std::vector<struct objfile *> found_objfiles;
+ for (struct objfile &objf : objfile->pspace ()->objfiles ())
+ found_objfiles.push_back (&objf);
+ return found_objfiles;
+}
+
+/* Implementation of the linker_namespace convenience variable.
This returns the GDB internal identifier of the linker namespace,
for the selected frame, as an integer. If the inferior doesn't support
linker namespaces, this always returns 0. */
diff --git a/gdb/solib.h b/gdb/solib.h
index 85ea6675b79..81389da6267 100644
--- a/gdb/solib.h
+++ b/gdb/solib.h
@@ -20,6 +20,9 @@
#ifndef GDB_SOLIB_H
#define GDB_SOLIB_H
+/* Forward decl's for prototypes */
+struct objfile;
+
#include "gdb_bfd.h"
#include "gdbsupport/function-view.h"
#include "gdbsupport/intrusive_list.h"
@@ -409,4 +412,20 @@ extern void handle_solib_event (void);
extern int solib_linker_namespace_count (program_space *pspace);
+/* Return a vector with pointers of all objfiles in the namespace
+ NSID. This version assumes that the inferior supports namespaces. */
+
+std::vector<objfile *> get_objfiles_in_linker_namespace
+ (int nsid, program_space *pspace);
+
+/* Return a vector with pointers of all objfiles in the same namespace
+ as OBJFILE. If the inferior doesn't support namespaces, return all
+ objfiles in the program_space. */
+
+std::vector<objfile *> get_objfiles_in_linker_namespace (objfile *objfile);
+
+/* Return the DSO matching OBJFILE or nullptr if none can be found. */
+
+const solib *find_solib_for_objfile (struct objfile *objfile);
+
#endif /* GDB_SOLIB_H */
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 3b0687c0750..786dd9f56ba 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -74,6 +74,7 @@
#include "gdbsupport/common-utils.h"
#include <optional>
#include "gdbsupport/unordered_set.h"
+#include "solib.h"
/* Forward declarations for local functions. */
@@ -6575,8 +6576,12 @@ symbol::get_maybe_copied_address () const
gdb_assert (this->loc_class () == LOC_STATIC);
const char *linkage_name = this->linkage_name ();
+
+ std::vector<struct objfile *> objfiles_to_search
+ (get_objfiles_in_linker_namespace (this->objfile ()));
+
bound_minimal_symbol minsym
- = lookup_minimal_symbol_linkage (this->objfile ()->pspace (), linkage_name,
+ = lookup_minimal_symbol_linkage (objfiles_to_search, linkage_name,
false, false);
if (minsym.minsym != nullptr)
return minsym.value_address ();
@@ -6593,8 +6598,12 @@ minimal_symbol::get_maybe_copied_address (objfile *objf) const
gdb_assert ((objf->flags & OBJF_MAINLINE) == 0);
const char *linkage_name = this->linkage_name ();
+
+ std::vector<struct objfile *> objfiles_to_search
+ (get_objfiles_in_linker_namespace (objf));
+
bound_minimal_symbol found
- = lookup_minimal_symbol_linkage (objf->pspace (), linkage_name,
+ = lookup_minimal_symbol_linkage (objfiles_to_search, linkage_name,
false, true);
if (found.minsym != nullptr)
return found.value_address ();
--
2.51.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v6 2/3] gdb: Make the parser recognize the [[N]] syntax for variables
2025-10-29 12:58 [PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols Guinevere Larsen
2025-10-29 12:58 ` [PATCH v6 1/3] gdb: make lookup_minimal_symbol_linkage work with linker namespaces Guinevere Larsen
@ 2025-10-29 12:58 ` Guinevere Larsen
2026-04-20 13:59 ` Andrew Burgess
2025-10-29 12:58 ` [PATCH v6 3/3] gdb: extend the [[N]]::foo syntax for files Guinevere Larsen
2025-11-27 20:30 ` [PING]Re: [PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols Guinevere Larsen
3 siblings, 1 reply; 16+ messages in thread
From: Guinevere Larsen @ 2025-10-29 12:58 UTC (permalink / raw)
To: gdb-patches; +Cc: Guinevere Larsen, Eli Zaretskii
This commit adds a couple new rules to the YACC parser, that will allow
GDB to recognize expressions like [[N]]::var.
This new syntax reuses the existing rules for searching for "block"s,
because it allows, with minimal changes to the .y file as a whole, while
also allowing [[N]]::function::symbol work. Notably, [[N]]::'file.c'::var
does not work yet, as this code change is also involved and would pollute
the current commit, so will be done in a separate one in the same series.
To restrict the search to a desired namespace, a new function is
introduced, lookup_symbol_in_linker_namespace. This function will only
perform the symbol lookup in the objfiles that belong to the requested
namespace.
This commit also changes the error message when "print var" if "var" is
only present in namespaces other than the current one. Before this commit,
lookup_minimal_symbol would find them as "external" symbols with
incomplete information - outputting "<symbol> has incomplete
information, cast it to it's defined type." - which could be confusing for
the users. This commit changes the parser rule "variable: name_not_typename"
so that, if multiple namespaces are active, we'll look for minimal symbols
only in the current namespace.
Known limitations:
* When using [[N]]::foo::var, if that specific foo version is not on the
stack, the error will be unable to include the linker namespace
requested. So if a user sees "foo" in the stack this could be
confusing, but it should be mitigated when a future patch adds the
namespace ID to the backtrace where applicable.
* Completion is not supported. That's because the function used to
complete symbols expects only text in the form "file.c:symbol", so
can't handle the double colon. This isn't unique to linker
namespaces, though, since func::var will also not complete, it is just
a quirk of how :: completion work at this point.
* The expression that parses [[N]] only takes an integer. That's
because there aren't many expressions that would make sense in there,
and the work of accepting an arbitrary expression felt too much for
little gain.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
---
gdb/NEWS | 6 +
gdb/c-exp.y | 72 ++++++++---
gdb/doc/gdb.texinfo | 6 +
gdb/minsyms.c | 124 ++++++++++++-------
gdb/minsyms.h | 8 ++
gdb/parser-defs.h | 7 ++
gdb/symtab.c | 37 ++++++
gdb/symtab.h | 8 ++
gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c | 14 +++
gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c | 3 +
gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 53 ++++++++
11 files changed, 274 insertions(+), 64 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index 097d8da350b..273bd400f1b 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -227,6 +227,12 @@ info threads [-gid] [-stopped] [-running] [ID]...
These new flags can be useful to get a reduced list when there is a
large number of threads.
+print
+ The print command now accepts the following syntax to print values
+ from a specific linker namespace: `[[N]]::foo'. N is the namespace
+ identifier as understood by GDB.
+
+
* GDB-internal Thread Local Storage (TLS) support
** Linux targets for the x86_64, aarch64, ppc64, s390x, and riscv
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 9f1cb1b2e2a..cb70bf3c863 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -173,7 +173,7 @@ using namespace expr;
struct ttype tsym;
struct symtoken ssym;
int voidval;
- const struct block *bval;
+ struct bval_type bval;
enum exp_opcode opcode;
struct stoken_vector svec;
@@ -261,6 +261,7 @@ static void c_print_token (FILE *file, int type, YYSTYPE value);
%token TYPEOF
%token DECLTYPE
%token TYPEID
+%token DOUBLESQUAREOPEN DOUBLESQUARECLOSE
/* Special type cases, put in to allow the parser to distinguish different
legal basetypes. */
@@ -1056,30 +1057,42 @@ exp : FALSEKEYWORD
block : BLOCKNAME
{
- if ($1.sym.symbol)
- $$ = $1.sym.symbol->value_block ();
- else
+ if ($1.sym.symbol == nullptr)
error (_("No file or function \"%s\"."),
copy_name ($1.stoken).c_str ());
+ $$.search_namespace = false;
+ $$.b_val = $1.sym.symbol->value_block ();
}
| FILENAME
{
$$ = $1;
}
+ | DOUBLESQUAREOPEN INT DOUBLESQUARECLOSE
+ {
+ $$.search_namespace = true;
+ $$.namespace_val = $2.val;
+ }
;
block : block COLONCOLON name
{
std::string copy = copy_name ($3);
- struct symbol *tem
- = lookup_symbol (copy.c_str (), $1,
- SEARCH_FUNCTION_DOMAIN,
- nullptr).symbol;
+ struct block_symbol tem;
- if (tem == nullptr)
+ if ($1.search_namespace)
+ tem = lookup_symbol_in_linker_namespace
+ (copy.c_str (), $1.namespace_val, SEARCH_FUNCTION_DOMAIN);
+ else
+ tem = lookup_symbol (copy.c_str (), $1.b_val,
+ SEARCH_FUNCTION_DOMAIN,
+ nullptr);
+
+ if (tem.symbol == nullptr)
error (_("No function \"%s\" in specified context."),
copy.c_str ());
- $$ = tem->value_block (); }
+ $$.b_val = tem.symbol->value_block ();
+ $$.search_namespace = false;
+ }
;
variable: name_not_typename ENTRY
@@ -1098,9 +1111,15 @@ variable: name_not_typename ENTRY
variable: block COLONCOLON name
{
std::string copy = copy_name ($3);
- struct block_symbol sym
- = lookup_symbol (copy.c_str (), $1,
- SEARCH_VFT, NULL);
+ struct block_symbol sym;
+
+ if ($1.search_namespace)
+ sym = lookup_symbol_in_linker_namespace
+ (copy.c_str (), $1.namespace_val,
+ SEARCH_VFT);
+ else
+ sym = lookup_symbol (copy.c_str (), $1.b_val,
+ SEARCH_VFT, NULL);
if (sym.symbol == 0)
error (_("No symbol \"%s\" in specified context."),
@@ -1196,13 +1215,25 @@ variable: name_not_typename
{
std::string arg = copy_name ($1.stoken);
- bound_minimal_symbol msymbol
- = lookup_minimal_symbol (current_program_space, arg.c_str ());
+ int active_linker_nss
+ = solib_linker_namespace_count
+ (current_program_space);
+ bound_minimal_symbol msymbol;
+
+ if (active_linker_nss > 1)
+ msymbol = lookup_minimal_symbol_in_linker_namespace
+ (current_program_space, arg.c_str ());
+ else
+ msymbol = lookup_minimal_symbol
+ (current_program_space, arg.c_str ());
if (msymbol.minsym == NULL)
{
if (!have_full_symbols (current_program_space)
&& !have_partial_symbols (current_program_space))
error (_("No symbol table is loaded. Use the \"file\" command."));
+ else if (active_linker_nss > 1)
+ error (_("No symbol \"%s\" in the current linker namespace."),
+ arg.c_str ());
else
error (_("No symbol \"%s\" in current context."),
arg.c_str ());
@@ -2540,7 +2571,9 @@ static const struct c_token tokentab2[] =
{"!=", NOTEQUAL, OP_NULL, 0},
{"<=", LEQ, OP_NULL, 0},
{">=", GEQ, OP_NULL, 0},
- {".*", DOT_STAR, OP_NULL, FLAG_CXX}
+ {".*", DOT_STAR, OP_NULL, FLAG_CXX},
+ {"[[", DOUBLESQUAREOPEN, OP_NULL, 0},
+ {"]]", DOUBLESQUARECLOSE, OP_NULL, 0},
};
/* Identifier-like tokens. Only type-specifiers than can appear in
@@ -3143,8 +3176,9 @@ classify_name (struct parser_state *par_state, const struct block *block,
if (auto symtab = lookup_symtab (current_program_space, copy.c_str ());
symtab != nullptr)
{
- yylval.bval
+ yylval.bval.b_val
= symtab->compunit ()->blockvector ()->static_block ();
+ yylval.bval.search_namespace = false;
return FILENAME;
}
@@ -3394,7 +3428,7 @@ yylex (void)
name_obstack.clear ();
checkpoint = 0;
if (current.token == FILENAME)
- search_block = current.value.bval;
+ search_block = current.value.bval.b_val;
else if (current.token == COLONCOLON)
search_block = NULL;
else
@@ -3577,7 +3611,7 @@ c_print_token (FILE *file, int type, YYSTYPE value)
break;
case FILENAME:
- parser_fprintf (file, "bval<%s>", host_address_to_string (value.bval));
+ parser_fprintf (file, "bval<%s>", host_address_to_string (value.bval.b_val));
break;
}
}
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 821f3ed4b05..b48f70d2250 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -10686,6 +10686,12 @@ you can choose a different format by specifying @samp{/@var{f}}, where
@var{f} is a letter specifying the format; see @ref{Output Formats,,Output
Formats}.
+Additionally, if the inferior supports linker namespaces, @value{GDBN}
+has implemented the following syntax to allow users to resolve symbols
+to a specific namespace: @code{[[@var{n}]]::@var{symbol}}. Here @var{n}
+is @value{GDBN}'s namespace identifier, which may be different from the
+inferior's identifier.
+
@anchor{print options}
The @code{print} command supports a number of options that allow
overriding relevant global print settings as set by @code{set print}
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 7e4f47b8c3f..a73d4f21858 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -335,7 +335,10 @@ lookup_minimal_symbol_demangled (const lookup_name_info &lookup_name,
}
}
-/* Look through all the current minimal symbol tables and find the
+/* Main implementation for the lookup_minimal_symbol function.
+ Receives a list of objfiles in which to look for the symbol.
+
+ Look through all the current minimal symbol tables and find the
first minimal symbol that matches NAME. If OBJF is non-NULL, limit
the search to that objfile. If SFILE is non-NULL, the only file-scope
symbols considered will be from that source file (global symbols are
@@ -355,9 +358,9 @@ lookup_minimal_symbol_demangled (const lookup_name_info &lookup_name,
Obviously, there must be distinct mangled names for each of these,
but the demangled names are all the same: S::S or S::~S. */
-bound_minimal_symbol
-lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf,
- const char *sfile)
+static bound_minimal_symbol
+lookup_minimal_symbol_in_objfiles (std::vector<objfile *> objfile_list,
+ const char *name, const char *sfile)
{
found_minimal_symbols found;
@@ -373,53 +376,48 @@ lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf,
lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
- for (objfile &objfile : pspace->objfiles ())
+ for (objfile *objfile : objfile_list)
{
if (found.external_symbol.minsym != NULL)
break;
- if (objf == NULL || objf == &objfile
- || objf == objfile.separate_debug_objfile_backlink)
+ symbol_lookup_debug_printf ("lookup_minimal_symbol (%s, %s, %s)",
+ name, sfile != NULL ? sfile : "NULL",
+ objfile_debug_name (objfile));
+
+ /* Do two passes: the first over the ordinary hash table,
+ and the second over the demangled hash table. */
+ lookup_minimal_symbol_mangled (name, sfile, objfile,
+ objfile->per_bfd->msymbol_hash,
+ mangled_hash, mangled_cmp, found);
+
+ /* If not found, try the demangled hash table. */
+ if (found.external_symbol.minsym == NULL)
{
- symbol_lookup_debug_printf ("lookup_minimal_symbol (%s, %s, %s, %s)",
- host_address_to_string (pspace),
- name, sfile != NULL ? sfile : "NULL",
- objfile_debug_name (&objfile));
-
- /* Do two passes: the first over the ordinary hash table,
- and the second over the demangled hash table. */
- lookup_minimal_symbol_mangled (name, sfile, &objfile,
- objfile.per_bfd->msymbol_hash,
- mangled_hash, mangled_cmp, found);
-
- /* If not found, try the demangled hash table. */
- if (found.external_symbol.minsym == NULL)
+ /* Once for each language in the demangled hash names
+ table (usually just zero or one languages). */
+ for (unsigned iter = 0; iter < nr_languages; ++iter)
{
- /* Once for each language in the demangled hash names
- table (usually just zero or one languages). */
- for (unsigned iter = 0; iter < nr_languages; ++iter)
- {
- if (!objfile.per_bfd->demangled_hash_languages.test (iter))
- continue;
- enum language lang = (enum language) iter;
-
- unsigned int hash
- = (lookup_name.search_name_hash (lang)
- % MINIMAL_SYMBOL_HASH_SIZE);
-
- symbol_name_matcher_ftype *match
- = language_def (lang)->get_symbol_name_matcher
- (lookup_name);
- struct minimal_symbol **msymbol_demangled_hash
- = objfile.per_bfd->msymbol_demangled_hash;
-
- lookup_minimal_symbol_demangled (lookup_name, sfile, &objfile,
- msymbol_demangled_hash,
- hash, match, found);
-
- if (found.external_symbol.minsym != NULL)
- break;
- }
+ if (!objfile->per_bfd->demangled_hash_languages.test (iter))
+ continue;
+ enum language lang = (enum language) iter;
+
+ unsigned int hash
+ = (lookup_name.search_name_hash (lang)
+ % MINIMAL_SYMBOL_HASH_SIZE);
+
+ symbol_name_matcher_ftype *match
+ = language_def (lang)->get_symbol_name_matcher
+ (lookup_name);
+ struct minimal_symbol **msymbol_demangled_hash
+ = objfile->per_bfd->msymbol_demangled_hash;
+
+ lookup_minimal_symbol_demangled (lookup_name, sfile, objfile,
+ msymbol_demangled_hash,
+ hash, match, found);
+
+ if (found.external_symbol.minsym != NULL)
+ break;
}
}
}
@@ -472,6 +470,42 @@ lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf,
return {};
}
+/* See minsyms.h. */
+
+bound_minimal_symbol
+lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf,
+ const char *sfile)
+{
+ std::vector<objfile *> search_objfiles;
+ if (objf != nullptr)
+ {
+ search_objfiles.push_back (objf);
+ if (objf->separate_debug_objfile_backlink != nullptr)
+ search_objfiles.push_back (objf->separate_debug_objfile_backlink);
+ }
+ else
+ {
+ for (objfile &objfile : pspace->objfiles ())
+ search_objfiles.push_back (&objfile);
+ }
+
+ return lookup_minimal_symbol_in_objfiles (search_objfiles, name, sfile);
+}
+
+/* See minsyms.h. */
+
+bound_minimal_symbol
+lookup_minimal_symbol_in_linker_namespace (program_space *pspace,
+ const char *name)
+{
+ LONGEST curr_namespace;
+ get_internalvar_integer (lookup_internalvar ("_linker_namespace"),
+ &curr_namespace);
+ return lookup_minimal_symbol_in_objfiles
+ (get_objfiles_in_linker_namespace (curr_namespace, pspace),
+ name, nullptr);
+}
+
/* See gdbsupport/symbol.h. */
int
diff --git a/gdb/minsyms.h b/gdb/minsyms.h
index 4aa8a428470..f2ba15d9318 100644
--- a/gdb/minsyms.h
+++ b/gdb/minsyms.h
@@ -211,6 +211,14 @@ bound_minimal_symbol lookup_minimal_symbol (program_space *pspace,
objfile *obj = nullptr,
const char *sfile = nullptr);
+/* Same as above, but only look for a minimal symbol in the objfiles that
+ belong to the current linker namespace. This function is only meant to
+ be called when attempting to resolve a symbol from a user command, and
+ there are multiple linker namespaces available to resolve it in. */
+
+bound_minimal_symbol lookup_minimal_symbol_in_linker_namespace
+ (program_space *pspace, const char *name);
+
/* Look through all the minimal symbol tables in PSPACE and find the
first minimal symbol that matches NAME and has text type. If OBJF
is non-NULL, limit the search to that objfile. Returns a bound
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index f5618f3a9ce..ff4ab6a09de 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -358,6 +358,13 @@ struct ttype
struct type *type;
};
+struct bval_type
+ {
+ bool search_namespace;
+ const struct block *b_val;
+ LONGEST namespace_val;
+ };
+
struct symtoken
{
struct stoken stoken;
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 786dd9f56ba..d237a5cc5d2 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -2558,6 +2558,43 @@ lookup_static_symbol (const char *name, const domain_search_flags domain)
/* See symtab.h. */
+struct block_symbol
+lookup_symbol_in_linker_namespace (const char *name, int nsid,
+ const domain_search_flags domain)
+{
+ if (!current_program_space->solib_ops ()->supports_namespaces ())
+ error (_("Linker namespaces are not supported by the inferior."));
+
+ std::vector<objfile *> objfiles_in_namespace
+ = get_objfiles_in_linker_namespace (nsid, current_program_space);
+
+ if (objfiles_in_namespace.size() == 0)
+ error (_("Namespace [[%d]] is inactive"), nsid);
+
+ symbol_lookup_debug_printf ("lookup_symbol_in_linker_namespace (%d, %s, %s)",
+ nsid, name, domain_name (domain).c_str ());
+
+ /* We look for both global and static symbols in here. There is no reason
+ to pick one over the other to my knowledge, so we go alphabetical. */
+ for (objfile *objf : objfiles_in_namespace)
+ {
+ struct block_symbol bsym
+ = lookup_global_symbol_from_objfile (objf, GLOBAL_BLOCK,
+ name, domain);
+ if (bsym.symbol != nullptr)
+ return bsym;
+
+ bsym = lookup_global_symbol_from_objfile (objf, STATIC_BLOCK,
+ name, domain);
+ if (bsym.symbol != nullptr)
+ return bsym;
+ }
+
+ return {};
+}
+
+/* See symtab.h. */
+
struct block_symbol
lookup_global_symbol (const char *name,
const struct block *block,
diff --git a/gdb/symtab.h b/gdb/symtab.h
index e47033efd01..fe2304acb4f 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2737,6 +2737,14 @@ extern struct block_symbol
const char *name,
const domain_search_flags domain);
+/* Lookup symbol NAME from DOMAIN in the linker namespace NSID.
+ This generates a list of all objfiles in NSID, then searches
+ those objfiles for the given symbol. Searches for both global or
+ static symbols. */
+extern struct block_symbol
+ lookup_symbol_in_linker_namespace (const char *name, int nsid,
+ const domain_search_flags domain);
+
extern unsigned int symtab_create_debug;
/* Print a "symtab-create" debug statement. */
diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c
index 86cbb0f4e38..cc35ce0080e 100644
--- a/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c
+++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c
@@ -26,3 +26,17 @@ inc (int n)
int amount = gdb_dlmopen_glob;
return n + amount; /* bp.inc. */
}
+
+static int
+change_global (int n)
+{
+ gdb_dlmopen_glob += n;
+ return n;
+}
+
+__attribute__((visibility ("default")))
+int
+func_with_other_call (int n)
+{
+ return change_global (n + 1);
+}
diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c
index c7c038a08d1..459ae547842 100644
--- a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c
+++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c
@@ -47,6 +47,9 @@ main (void)
fun (dl);
}
+ fun = dlsym (handle[0], "func_with_other_call");
+ fun (0);
+
dlclose (handle[0]); /* TAG: first dlclose */
dlclose (handle[1]); /* TAG: second dlclose */
dlclose (handle[2]); /* TAG: third dlclose */
diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
index f3bdfb054d9..fec7adb5317 100644
--- a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
+++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
@@ -123,6 +123,10 @@ proc get_first_so_ns {} {
return $ns
}
+proc ns_id_for_command {ns} {
+ return "\[\[$ns\]\]"
+}
+
# Run the tests relating to the command "info sharedlibrary", to
# verify that the namespace ID is consistent.
proc test_info_shared {} {
@@ -315,6 +319,55 @@ proc test_info_linker_namespaces {} {
".*" ] "print namespaces with no argument"
}
+# Test that we can use the [[N]]::symbol syntax, and it's variations
+# like [[N]]::func::symbol.
+proc_with_prefix test_print_namespace_symbol {} {
+ clean_restart
+ gdb_load $::binfile
+
+ set ns1 [ns_id_for_command 1]
+ set ns2 [ns_id_for_command 2]
+
+ if { ![runto_main] } {
+ return
+ }
+
+ gdb_breakpoint [gdb_get_line_number "TAG: first dlclose"]
+ gdb_breakpoint "change_global" allow-pending
+
+ # Test printing variables for non-existent namespace.
+ gdb_test "print ${ns1}::gdb_dlmopen_glob" "Namespace ..1.. is inactive" \
+ "Before loading namespaces"
+
+ gdb_continue_to_breakpoint "change_global"
+
+ # Test finding location of variables.
+ gdb_test "print ${ns1}::gdb_dlmopen_glob" ".* = 0" "before changing"
+ gdb_test_no_output "set ${ns1}::gdb_dlmopen_glob = 1"
+ gdb_test "print ${ns1}::gdb_dlmopen_glob" ".* = 1" "after changing"
+ gdb_test "print ${ns2}::gdb_dlmopen_glob" ".* = 0" "other namespace"
+
+ gdb_test "print gdb_dlmopen_glob" ".* = 1" "changed the right variable"
+
+ # Test finding functions in specific namespaces.
+ gdb_test "print ${ns1}::inc (2)" ".* = 3"
+ gdb_test "print ${ns2}::inc (2)" ".* = 2"
+
+ # Test finding a specific block in the backtrace.
+ gdb_test "print n" ".* = 1"
+ gdb_test "print ${ns1}::func_with_other_call::n" ".* = 0"
+ gdb_test "print ${ns2}::func_with_other_call::n" \
+ "No frame is currently executing in block func_with_other_call."
+
+ # Leave to default namespace.
+ gdb_continue_to_breakpoint "TAG: first dlclose"
+ # This global doesn't exist in the default namespace. Rather than
+ # returning a random one, we just say we didn't find one.
+ gdb_test "print gdb_dlmopen_glob" \
+ "No symbol .gdb_dlmopen_glob. in the current linker namespace."
+}
+
test_info_shared
test_conv_vars
test_info_linker_namespaces
+test_print_namespace_symbol
--
2.51.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v6 3/3] gdb: extend the [[N]]::foo syntax for files
2025-10-29 12:58 [PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols Guinevere Larsen
2025-10-29 12:58 ` [PATCH v6 1/3] gdb: make lookup_minimal_symbol_linkage work with linker namespaces Guinevere Larsen
2025-10-29 12:58 ` [PATCH v6 2/3] gdb: Make the parser recognize the [[N]] syntax for variables Guinevere Larsen
@ 2025-10-29 12:58 ` Guinevere Larsen
2026-04-20 15:13 ` Andrew Burgess
2025-11-27 20:30 ` [PING]Re: [PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols Guinevere Larsen
3 siblings, 1 reply; 16+ messages in thread
From: Guinevere Larsen @ 2025-10-29 12:58 UTC (permalink / raw)
To: gdb-patches; +Cc: Guinevere Larsen
This commit implements the missing support for [[N]]::'file.c'::var
syntax that was skipped on the previous commit.
This is done by adding a new value to the global parser_state, so that
the classify_name function can restrict its search for file names to the
specified linker namespace. It had to be done this way because if the
logic was contained on the newly added "block: block COLONCOLON
FILENAME" rule, we would not have the name to rerun the search. Because
of that, the new rule only exists to make sure this is only used in the
intended syntax. This commit also adds a link to the solib_ops relevant
to the expression being parsed, as a way to identify if linker
namespaces are supported; this could be achieved by guarding the search
functions instead, but I think that this is more reliable.
The new rule uses "block" rather than a linker namespace specific token,
because if we allowed that token to also reduce into block, the new rule
would never be triggered as the simple reduction would be preferred. If
we didn't allow the linker namespace to reduce into block, the rest of
the syntaxes for [[N]]::foo would be more involved, so the option in
this commit seemed like the simplest solution.
The rule "block: block COLONCOLON name" also had to be updated because,
if a user tried to search for a file not present in the linker
namespace, GDB would miscategorize it to 'name' instead of 'filename',
and if no function of the same name was found, the error would only say
"No function \"foo\" (...)" which could confuse a user. The new error
says "Nothing named \"foo\" (...)" instead since it is impossible for us
to disambiguate between filename or function name, and both would be
valid in this code path.
The parser_state changes were not used for the previous commit because
the lookup_symbol calls would lead to an even more intrusive change for
no real gain, since the search would be rerun any way. There is an
argument to be made that the results could be different if only
namespace had a type and another had a variable, but a situation where
that significantly changes the result is quite unlikely, I think.
---
gdb/c-exp.y | 18 +++++++++++--
gdb/linespec.c | 4 +--
gdb/parse.c | 3 ++-
gdb/parser-defs.h | 32 +++++++++++++++++++++--
gdb/rust-parse.c | 3 ++-
gdb/symtab.c | 26 +++++++++++++-----
gdb/symtab.h | 7 ++++-
gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 12 +++++++++
8 files changed, 90 insertions(+), 15 deletions(-)
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index cb70bf3c863..f59aca327ed 100644
--- a/gdb/c-exp.y
+++ b/gdb/c-exp.y
@@ -1071,6 +1071,7 @@ block : BLOCKNAME
{
$$.search_namespace = true;
$$.namespace_val = $2.val;
+ pstate->set_linker_namespace ($2.val);
}
;
@@ -1087,12 +1088,24 @@ block : block COLONCOLON name
SEARCH_FUNCTION_DOMAIN,
nullptr);
- if (tem.symbol == nullptr)
+ if (tem.symbol == nullptr && !$$.search_namespace)
error (_("No function \"%s\" in specified context."),
copy.c_str ());
+ else if (tem.symbol == nullptr && $$.search_namespace)
+ /* COPY can be a function or a file. There is no way
+ to identify which the user intended, so emit a
+ generic warning instead. */
+ error (_("Nothing named \"%s\" in specified context."),
+ copy.c_str ());
$$.b_val = tem.symbol->value_block ();
$$.search_namespace = false;
}
+ | block COLONCOLON FILENAME
+ {
+ if (!$1.search_namespace)
+ error (_("Filename must be the first part of the expression"));
+ $$ = $3;
+ }
;
variable: name_not_typename ENTRY
@@ -3173,7 +3186,8 @@ classify_name (struct parser_state *par_state, const struct block *block,
|| is_quoted_name)
{
/* See if it's a file name. */
- if (auto symtab = lookup_symtab (current_program_space, copy.c_str ());
+ if (auto symtab = lookup_symtab (current_program_space, copy.c_str (),
+ par_state->get_linker_namespace ());
symtab != nullptr)
{
yylval.bval.b_val
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 08f7fdd0daa..ec90ad4826a 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -3633,11 +3633,11 @@ collect_symtabs_from_filename (const char *file,
if (pspace->executing_startup)
continue;
- iterate_over_symtabs (pspace, file, collector);
+ iterate_over_symtabs (pspace, file, -1, collector);
}
}
else
- iterate_over_symtabs (search_pspace, file, collector);
+ iterate_over_symtabs (search_pspace, file, -1, collector);
/* It is tempting to use the unordered_dense 'extract' method here,
and remove the separate vector -- but it's unclear if ordering
diff --git a/gdb/parse.c b/gdb/parse.c
index d76768f41d7..7358c369d52 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -420,7 +420,8 @@ parse_exp_in_context (const char **stringptr, CORE_ADDR pc,
parser_state ps (lang, get_current_arch (), expression_context_block,
expression_context_pc, flags, *stringptr,
- completer != nullptr, tracker);
+ completer != nullptr, tracker,
+ current_program_space->solib_ops ());
scoped_restore_current_language lang_saver (lang->la_language);
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index ff4ab6a09de..c0be1083f66 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -26,6 +26,7 @@
#include "expression.h"
#include "symtab.h"
#include "expop.h"
+#include "solib.h"
struct block;
struct language_defn;
@@ -147,7 +148,8 @@ struct parser_state : public expr_builder
parser_flags flags,
const char *input,
bool completion,
- innermost_block_tracker *tracker)
+ innermost_block_tracker *tracker,
+ const solib_ops *ops)
: expr_builder (lang, gdbarch),
expression_context_block (context_block),
expression_context_pc (context_pc),
@@ -157,7 +159,8 @@ struct parser_state : public expr_builder
comma_terminates ((flags & PARSER_COMMA_TERMINATES) != 0),
parse_completion (completion),
void_context_p ((flags & PARSER_VOID_CONTEXT) != 0),
- debug ((flags & PARSER_DEBUG) != 0)
+ debug ((flags & PARSER_DEBUG) != 0),
+ m_solib_ops (ops)
{
}
@@ -263,6 +266,21 @@ struct parser_state : public expr_builder
push (expr::make_operation<T> (std::move (lhs), std::move (rhs)));
}
+ void set_linker_namespace (LONGEST ns_id)
+ {
+ if (m_solib_ops == nullptr)
+ error (_("Linker namespaces require an active inferior"));
+ if (m_solib_ops->supports_namespaces ())
+ linker_namespace = ns_id;
+ else
+ error (_("Linker namespaces are not supported"));
+ }
+
+ LONGEST get_linker_namespace ()
+ {
+ return linker_namespace;
+ }
+
/* Function called from the various parsers' yyerror functions to throw
an error. The error will include a message identifying the location
of the error within the current expression. */
@@ -323,6 +341,16 @@ struct parser_state : public expr_builder
/* Stack of operations. */
std::vector<expr::operation_up> m_operations;
+
+ /* If the expression is being restricted to a specific namespace, this is
+ where that information is stored for the block lookup. It should be
+ accessed through setter/getters to ensure that the linker namespace is
+ only set when the gdbarch supports it. */
+ LONGEST linker_namespace = -1;
+
+ /* Used to figure out if an inferior is capable of handling linker
+ namespaces at all. */
+ const solib_ops *m_solib_ops;
};
/* A string token, either a char-string or bit-string. Char-strings are
diff --git a/gdb/rust-parse.c b/gdb/rust-parse.c
index b740d5a7b16..27f03b23e6a 100644
--- a/gdb/rust-parse.c
+++ b/gdb/rust-parse.c
@@ -2315,7 +2315,8 @@ rust_lex_tests (void)
{
/* Set up dummy "parser", so that rust_type works. */
parser_state ps (language_def (language_rust), current_inferior ()->arch (),
- nullptr, 0, 0, nullptr, 0, nullptr);
+ nullptr, 0, 0, nullptr, 0, nullptr,
+ current_program_space->solib_ops ());
rust_parser parser (&ps);
rust_lex_test_one (&parser, "", 0);
diff --git a/gdb/symtab.c b/gdb/symtab.c
index d237a5cc5d2..bbaf94e51d0 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -618,6 +618,7 @@ compare_filenames_for_search (const char *filename, const char *search_name)
void
iterate_over_symtabs (program_space *pspace, const char *name,
+ LONGEST linker_ns,
gdb::function_view<bool (symtab *)> callback)
{
gdb::unique_xmalloc_ptr<char> real_path;
@@ -630,20 +631,33 @@ iterate_over_symtabs (program_space *pspace, const char *name,
gdb_assert (IS_ABSOLUTE_PATH (real_path.get ()));
}
- for (objfile &objfile : pspace->objfiles ())
- if (objfile.map_symtabs_matching_filename (name, real_path.get (),
- callback))
+ std::vector<objfile *> objfiles_to_search;
+ if (linker_ns >= 0)
+ {
+ gdb_assert (pspace->solib_ops ()->supports_namespaces ());
+ objfiles_to_search
+ = get_objfiles_in_linker_namespace (linker_ns, pspace);
+ }
+ else
+ {
+ for (objfile &objf : pspace->objfiles ())
+ objfiles_to_search.push_back (&objf);
+ }
+
+ for (objfile *objfile : objfiles_to_search)
+ if (objfile->map_symtabs_matching_filename (name, real_path.get (),
+ callback))
return;
}
/* See symtab.h. */
symtab *
-lookup_symtab (program_space *pspace, const char *name)
+lookup_symtab (program_space *pspace, const char *name, LONGEST linker_ns)
{
struct symtab *result = NULL;
- iterate_over_symtabs (pspace, name, [&] (symtab *symtab)
+ iterate_over_symtabs (pspace, name, linker_ns, [&] (symtab *symtab)
{
result = symtab;
return true;
@@ -6158,7 +6172,7 @@ collect_file_symbol_completion_matches (completion_tracker &tracker,
/* Go through symtabs for SRCFILE and check the externs and statics
for symbols which match. */
- iterate_over_symtabs (current_program_space, srcfile, [&] (symtab *s)
+ iterate_over_symtabs (current_program_space, srcfile, -1, [&] (symtab *s)
{
add_symtab_completions (s->compunit (),
tracker, mode, lookup_name,
diff --git a/gdb/symtab.h b/gdb/symtab.h
index fe2304acb4f..bda6e82da02 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2079,7 +2079,8 @@ const char *multiple_symbols_select_mode (void);
/* Lookup a symbol table in PSPACE by source file name. */
-extern symtab *lookup_symtab (program_space *pspace, const char *name);
+extern symtab *lookup_symtab (program_space *pspace, const char *name,
+ LONGEST linker_ns = -1);
/* An object of this type is passed as the 'is_a_field_of_this'
argument to lookup_symbol and lookup_symbol_in_language. */
@@ -2805,10 +2806,14 @@ bool compare_glob_filenames_for_search (const char *filename,
psymtabs. *If* there is no '/' in the name, a match after a '/' in the
symtab filename will also work.
+ If LINKER_NS is 0 or greater, only the objfiles in the provided linker
+ namespace will be iterated over.
+
Call CALLBACK with each symtab that is found. If CALLBACK returns
true, the search stops. */
void iterate_over_symtabs (program_space *pspace, const char *name,
+ LONGEST linker_ns,
gdb::function_view<bool (symtab *)> callback);
std::vector<const linetable_entry *> find_linetable_entries_for_symtab_line
diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
index fec7adb5317..a1e18fc39d3 100644
--- a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
+++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
@@ -325,9 +325,15 @@ proc_with_prefix test_print_namespace_symbol {} {
clean_restart
gdb_load $::binfile
+ set ns0 [ns_id_for_command 0]
set ns1 [ns_id_for_command 1]
set ns2 [ns_id_for_command 2]
+ # Test printing variables before starting the inferior
+ gdb_test "print ${ns1}::gdb_dlmopen_glob" \
+ "Linker namespaces require an active inferior" \
+ "Before starting inferior"
+
if { ![runto_main] } {
return
}
@@ -365,6 +371,12 @@ proc_with_prefix test_print_namespace_symbol {} {
# returning a random one, we just say we didn't find one.
gdb_test "print gdb_dlmopen_glob" \
"No symbol .gdb_dlmopen_glob. in the current linker namespace."
+
+ # Minimal testing for finding files in namespaces.
+ gdb_test "print ${ns1}::'${::srcfile_lib}'::gdb_dlmopen_glob" \
+ ".* = 2"
+ gdb_test "print ${ns0}::'${::srcfile_lib}'::gdb_dlmopen_glob" \
+ "Nothing named .${::srcfile_lib}. in specified context."
}
test_info_shared
--
2.51.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PING]Re: [PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols
2025-10-29 12:58 [PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols Guinevere Larsen
` (2 preceding siblings ...)
2025-10-29 12:58 ` [PATCH v6 3/3] gdb: extend the [[N]]::foo syntax for files Guinevere Larsen
@ 2025-11-27 20:30 ` Guinevere Larsen
2025-12-12 17:20 ` [PINGv2][PATCH " Guinevere Larsen
2026-01-06 17:17 ` Guinevere Larsen
3 siblings, 2 replies; 16+ messages in thread
From: Guinevere Larsen @ 2025-11-27 20:30 UTC (permalink / raw)
To: gdb-patches, guinevere
Ping :)
On 10/29/25 9:58 AM, Guinevere Larsen wrote:
> This series adds support for the syntax [[N]]::foo to find symbols that
> belong to specific namespaces, while also making GDB's behavior more
> consistent when a namespace is not specified. This needs one preparatory
> patch and 2 patches actually implementing this feature
>
> Patch 1 is an essential fix, updating how we calculate a variable's copy
> relocation to take linker namespaces into account.
>
> Patches 2 and 3 implement the new syntax, adding the necessary
> supporting code and updating error messages when symbols can't be found
> - where it made sense.
>
> Changes for v6:
> * Rebased on master
> * Fixed a crash when using the [[N]]::foo syntax before starting the
> inferior
>
> Changes for v5:
> * fixed crash when getting the value of a variable before the inferior
> starts.
> * Rebased on master
>
> Changes for v4:
> * Fixed final documentation feedback from Eli.
> * Changed error message when [[N]]::foo::bar fails to find 'foo'.
> * Fixed build breakage.
>
> Changes for v3:
> * Removed previous patches 1 and 2, as Simon's recently merged patches
> already did those in a better way.
> * parser_state now also takes the current solib_ops, since that can't be
> obtained from gdbarch anymore.
>
> Changes for v2:
> * solib_supports_linker_namespaces now always expects a pointer.
> * Previous patches 2 and 3 were dropped.
> * lookup_minimal_symbol_linkage now takes an array_view.
> * created new tokens for [[ and ]], to ensure that [[N]] looks like
> that.
> * Fixed formatting nits from Eli.
>
> Guinevere Larsen (3):
> gdb: make lookup_minimal_symbol_linkage work with linker namespaces
> gdb: Make the parser recognize the [[N]] syntax for variables
> gdb: extend the [[N]]::foo syntax for files
>
> gdb/NEWS | 6 +
> gdb/c-exp.y | 88 +++++++++---
> gdb/doc/gdb.texinfo | 6 +
> gdb/dwarf2/ada-imported.c | 8 +-
> gdb/linespec.c | 4 +-
> gdb/minsyms.c | 139 ++++++++++++-------
> gdb/minsyms.h | 17 ++-
> gdb/parse.c | 3 +-
> gdb/parser-defs.h | 39 +++++-
> gdb/rust-parse.c | 3 +-
> gdb/solib-svr4.c | 20 ---
> gdb/solib.c | 86 +++++++++++-
> gdb/solib.h | 19 +++
> gdb/symtab.c | 76 ++++++++--
> gdb/symtab.h | 15 +-
> gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c | 14 ++
> gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c | 3 +
> gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 65 +++++++++
> 18 files changed, 499 insertions(+), 112 deletions(-)
>
>
> base-commit: 0633b78640dc892265d148f24881d544d4ddd16e
--
Cheers,
Guinevere Larsen
It/she
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PINGv2][PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols
2025-11-27 20:30 ` [PING]Re: [PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols Guinevere Larsen
@ 2025-12-12 17:20 ` Guinevere Larsen
2026-01-06 17:17 ` Guinevere Larsen
1 sibling, 0 replies; 16+ messages in thread
From: Guinevere Larsen @ 2025-12-12 17:20 UTC (permalink / raw)
To: gdb-patches, Guinevere Larsen
Ping!
On 11/27/25 5:30 PM, Guinevere Larsen wrote:
> Ping :)
>
> On 10/29/25 9:58 AM, Guinevere Larsen wrote:
>> This series adds support for the syntax [[N]]::foo to find symbols that
>> belong to specific namespaces, while also making GDB's behavior more
>> consistent when a namespace is not specified. This needs one preparatory
>> patch and 2 patches actually implementing this feature
>>
>> Patch 1 is an essential fix, updating how we calculate a variable's copy
>> relocation to take linker namespaces into account.
>>
>> Patches 2 and 3 implement the new syntax, adding the necessary
>> supporting code and updating error messages when symbols can't be found
>> - where it made sense.
>>
>> Changes for v6:
>> * Rebased on master
>> * Fixed a crash when using the [[N]]::foo syntax before starting the
>> inferior
>>
>> Changes for v5:
>> * fixed crash when getting the value of a variable before the inferior
>> starts.
>> * Rebased on master
>>
>> Changes for v4:
>> * Fixed final documentation feedback from Eli.
>> * Changed error message when [[N]]::foo::bar fails to find 'foo'.
>> * Fixed build breakage.
>>
>> Changes for v3:
>> * Removed previous patches 1 and 2, as Simon's recently merged patches
>> already did those in a better way.
>> * parser_state now also takes the current solib_ops, since that can't be
>> obtained from gdbarch anymore.
>>
>> Changes for v2:
>> * solib_supports_linker_namespaces now always expects a pointer.
>> * Previous patches 2 and 3 were dropped.
>> * lookup_minimal_symbol_linkage now takes an array_view.
>> * created new tokens for [[ and ]], to ensure that [[N]] looks like
>> that.
>> * Fixed formatting nits from Eli.
>>
>> Guinevere Larsen (3):
>> gdb: make lookup_minimal_symbol_linkage work with linker namespaces
>> gdb: Make the parser recognize the [[N]] syntax for variables
>> gdb: extend the [[N]]::foo syntax for files
>>
>> gdb/NEWS | 6 +
>> gdb/c-exp.y | 88 +++++++++---
>> gdb/doc/gdb.texinfo | 6 +
>> gdb/dwarf2/ada-imported.c | 8 +-
>> gdb/linespec.c | 4 +-
>> gdb/minsyms.c | 139 ++++++++++++-------
>> gdb/minsyms.h | 17 ++-
>> gdb/parse.c | 3 +-
>> gdb/parser-defs.h | 39 +++++-
>> gdb/rust-parse.c | 3 +-
>> gdb/solib-svr4.c | 20 ---
>> gdb/solib.c | 86 +++++++++++-
>> gdb/solib.h | 19 +++
>> gdb/symtab.c | 76 ++++++++--
>> gdb/symtab.h | 15 +-
>> gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c | 14 ++
>> gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c | 3 +
>> gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 65 +++++++++
>> 18 files changed, 499 insertions(+), 112 deletions(-)
>>
>>
>> base-commit: 0633b78640dc892265d148f24881d544d4ddd16e
>
>
--
Cheers,
Guinevere Larsen
It/she
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PINGv2][PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols
2025-11-27 20:30 ` [PING]Re: [PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols Guinevere Larsen
2025-12-12 17:20 ` [PINGv2][PATCH " Guinevere Larsen
@ 2026-01-06 17:17 ` Guinevere Larsen
2026-01-14 14:11 ` Guinevere Larsen
1 sibling, 1 reply; 16+ messages in thread
From: Guinevere Larsen @ 2026-01-06 17:17 UTC (permalink / raw)
To: gdb-patches, Guinevere Larsen
Ping!
On 11/27/25 5:30 PM, Guinevere Larsen wrote:
> Ping :)
>
> On 10/29/25 9:58 AM, Guinevere Larsen wrote:
>> This series adds support for the syntax [[N]]::foo to find symbols that
>> belong to specific namespaces, while also making GDB's behavior more
>> consistent when a namespace is not specified. This needs one preparatory
>> patch and 2 patches actually implementing this feature
>>
>> Patch 1 is an essential fix, updating how we calculate a variable's copy
>> relocation to take linker namespaces into account.
>>
>> Patches 2 and 3 implement the new syntax, adding the necessary
>> supporting code and updating error messages when symbols can't be found
>> - where it made sense.
>>
>> Changes for v6:
>> * Rebased on master
>> * Fixed a crash when using the [[N]]::foo syntax before starting the
>> inferior
>>
>> Changes for v5:
>> * fixed crash when getting the value of a variable before the inferior
>> starts.
>> * Rebased on master
>>
>> Changes for v4:
>> * Fixed final documentation feedback from Eli.
>> * Changed error message when [[N]]::foo::bar fails to find 'foo'.
>> * Fixed build breakage.
>>
>> Changes for v3:
>> * Removed previous patches 1 and 2, as Simon's recently merged patches
>> already did those in a better way.
>> * parser_state now also takes the current solib_ops, since that can't be
>> obtained from gdbarch anymore.
>>
>> Changes for v2:
>> * solib_supports_linker_namespaces now always expects a pointer.
>> * Previous patches 2 and 3 were dropped.
>> * lookup_minimal_symbol_linkage now takes an array_view.
>> * created new tokens for [[ and ]], to ensure that [[N]] looks like
>> that.
>> * Fixed formatting nits from Eli.
>>
>> Guinevere Larsen (3):
>> gdb: make lookup_minimal_symbol_linkage work with linker namespaces
>> gdb: Make the parser recognize the [[N]] syntax for variables
>> gdb: extend the [[N]]::foo syntax for files
>>
>> gdb/NEWS | 6 +
>> gdb/c-exp.y | 88 +++++++++---
>> gdb/doc/gdb.texinfo | 6 +
>> gdb/dwarf2/ada-imported.c | 8 +-
>> gdb/linespec.c | 4 +-
>> gdb/minsyms.c | 139 ++++++++++++-------
>> gdb/minsyms.h | 17 ++-
>> gdb/parse.c | 3 +-
>> gdb/parser-defs.h | 39 +++++-
>> gdb/rust-parse.c | 3 +-
>> gdb/solib-svr4.c | 20 ---
>> gdb/solib.c | 86 +++++++++++-
>> gdb/solib.h | 19 +++
>> gdb/symtab.c | 76 ++++++++--
>> gdb/symtab.h | 15 +-
>> gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c | 14 ++
>> gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c | 3 +
>> gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 65 +++++++++
>> 18 files changed, 499 insertions(+), 112 deletions(-)
>>
>>
>> base-commit: 0633b78640dc892265d148f24881d544d4ddd16e
>
>
--
Cheers,
Guinevere Larsen
It/she
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PINGv2][PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols
2026-01-06 17:17 ` Guinevere Larsen
@ 2026-01-14 14:11 ` Guinevere Larsen
2026-03-05 12:20 ` [PINGv3][PATCH " Guinevere Larsen
2026-03-05 12:21 ` Guinevere Larsen
0 siblings, 2 replies; 16+ messages in thread
From: Guinevere Larsen @ 2026-01-14 14:11 UTC (permalink / raw)
To: gdb-patches, Guinevere Larsen
Ping :)
On 1/6/26 2:17 PM, Guinevere Larsen wrote:
> Ping!
> On 11/27/25 5:30 PM, Guinevere Larsen wrote:
>> Ping :)
>>
>> On 10/29/25 9:58 AM, Guinevere Larsen wrote:
>>> This series adds support for the syntax [[N]]::foo to find symbols that
>>> belong to specific namespaces, while also making GDB's behavior more
>>> consistent when a namespace is not specified. This needs one
>>> preparatory
>>> patch and 2 patches actually implementing this feature
>>>
>>> Patch 1 is an essential fix, updating how we calculate a variable's
>>> copy
>>> relocation to take linker namespaces into account.
>>>
>>> Patches 2 and 3 implement the new syntax, adding the necessary
>>> supporting code and updating error messages when symbols can't be found
>>> - where it made sense.
>>>
>>> Changes for v6:
>>> * Rebased on master
>>> * Fixed a crash when using the [[N]]::foo syntax before starting the
>>> inferior
>>>
>>> Changes for v5:
>>> * fixed crash when getting the value of a variable before the inferior
>>> starts.
>>> * Rebased on master
>>>
>>> Changes for v4:
>>> * Fixed final documentation feedback from Eli.
>>> * Changed error message when [[N]]::foo::bar fails to find 'foo'.
>>> * Fixed build breakage.
>>>
>>> Changes for v3:
>>> * Removed previous patches 1 and 2, as Simon's recently merged patches
>>> already did those in a better way.
>>> * parser_state now also takes the current solib_ops, since that
>>> can't be
>>> obtained from gdbarch anymore.
>>>
>>> Changes for v2:
>>> * solib_supports_linker_namespaces now always expects a pointer.
>>> * Previous patches 2 and 3 were dropped.
>>> * lookup_minimal_symbol_linkage now takes an array_view.
>>> * created new tokens for [[ and ]], to ensure that [[N]] looks like
>>> that.
>>> * Fixed formatting nits from Eli.
>>>
>>> Guinevere Larsen (3):
>>> gdb: make lookup_minimal_symbol_linkage work with linker namespaces
>>> gdb: Make the parser recognize the [[N]] syntax for variables
>>> gdb: extend the [[N]]::foo syntax for files
>>>
>>> gdb/NEWS | 6 +
>>> gdb/c-exp.y | 88 +++++++++---
>>> gdb/doc/gdb.texinfo | 6 +
>>> gdb/dwarf2/ada-imported.c | 8 +-
>>> gdb/linespec.c | 4 +-
>>> gdb/minsyms.c | 139
>>> ++++++++++++-------
>>> gdb/minsyms.h | 17 ++-
>>> gdb/parse.c | 3 +-
>>> gdb/parser-defs.h | 39 +++++-
>>> gdb/rust-parse.c | 3 +-
>>> gdb/solib-svr4.c | 20 ---
>>> gdb/solib.c | 86 +++++++++++-
>>> gdb/solib.h | 19 +++
>>> gdb/symtab.c | 76 ++++++++--
>>> gdb/symtab.h | 15 +-
>>> gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c | 14 ++
>>> gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c | 3 +
>>> gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 65 +++++++++
>>> 18 files changed, 499 insertions(+), 112 deletions(-)
>>>
>>>
>>> base-commit: 0633b78640dc892265d148f24881d544d4ddd16e
>>
>>
>
--
Cheers,
Guinevere Larsen
It/she
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v6 1/3] gdb: make lookup_minimal_symbol_linkage work with linker namespaces
2025-10-29 12:58 ` [PATCH v6 1/3] gdb: make lookup_minimal_symbol_linkage work with linker namespaces Guinevere Larsen
@ 2026-01-28 11:22 ` Andrew Burgess
0 siblings, 0 replies; 16+ messages in thread
From: Andrew Burgess @ 2026-01-28 11:22 UTC (permalink / raw)
To: Guinevere Larsen, gdb-patches; +Cc: Guinevere Larsen
Guinevere Larsen <guinevere@redhat.com> writes:
> When a symbol found by GDB may have copy relocation, GDB calculates the
> address of the symbol by checking all the objfiles in the current
> program space for another instance of the same symbol, and returns the
> address of the first instance found.
>
> This works well when linker namespaces are not involved, but fails when
> a symbol is present in more than one namespace. That's because copy
> relocations respect linker namespace boundaries, and so if we're trying
> to find the symbol in namespace N, the symbol from a different namespace
> M may be returned, if the SO containing the symbol was loaded in M
> before N.
>
> To make the search work correctly, lookup_minimal_symbol_linkage would
> need to also respect linker namespace boundaries. However, to avoid
> leaking solib knowledge to minsyms, and because of how little
> information is passed to the function, this commit instead makes the
> function take a vector of objfiles to search, in place of the program
> space. This makes it so symbol::get_maybe_copied_address (and the
> equivalent of minimal_symbol) need to request the objfiles for the
> correct namespace, since they have enough context to figure out the
> namespace. Creating the vector is left as a function in solib.c
>
> Since minimal_symbol::get_maybe_copied_address only searches main_file
> objfiles, if we can guarantee that only one is loaded for each program
> space, we could avoid the work of constructing an std::vector that will
> be mostly ignored. However, I couldn't convince myself that that is the
> case, so I decided to keep the behavior exactly as is.
>
> Ideally, lookup_minimal_symbol_linkage would receive an iterator instead
> of a vector, but as of now it isn't possible to do forward declarations
> of nested types (we'd need program_space::objfiles_range) and
> progspace.h can't be included into minsyms.h, so we're stuck
> constructing a vector for it.
I think the wording of this paragraph is unchanged since v5. You're
saying: I'd like to do <stuff> but the current GDB code prevents me.
Based on this, I asked, my not rework GDB. You then explained that
there's a deeper reason for why you cannot do what you want. I would
suggest you update the commit message in cases like this as future
readers might have the same questions I had...
... except in this case, I have some deeper thoughts on this patch.
>
> Finally, as some minor refactoring, find_solib_for_objfile is moved to
> solib.c to simplify looking for which namespace contains the objfile
> where we found the symbol the user was looking for.
I'll not leave this comment inline with the diff, as it's a more general
observation. But I'm not super keen on find_solib_for_objfile moving
out of solib-svr4.c, at least not in its current form.
The reason: the function is broken and really shouldn't be used at all.
The relationship between objfiles and solibs is 1 to many. The obvious
example here is the runtime linker, this will be mapped multiple times,
but only appear in memory once. There will be many solibs, but only a
single objfile.
Prior to this patch, find_solib_for_objfile was used in one place, in
svr4_solib_ops::iterate_over_objfiles_in_search_order. If we look at
how it is used, the function takes a CURRENT_OBJFILE and limits symbols
searches to objfiles in the same namespace. But what if the dynamic
linker is the CURRENT_OBJFILE? Right now we'll just search the first
namespace that we find, when we probably should be searching all
namespaces.
I got thinking about this because, I'm really keen on the build a
vector prior to calling lookup_minimal_symbol_linkage approach. I
cannot really put my finger on why I don't like this, but it just
doesn't feel great.
I think my problem is that we already have a list of objfiles, and all
we really want to do is ask for each one; is this in the right linker
namespace? The whole pre-build a vector business is necessitated
because, given an objfile, we cannot easily answer the question; is this
in the same namespace as some other objfile. If we could ask that
question easily, then the change here would be simple, right? In
minsyms.c, in lookup_minimal_symbol_linkage, we'd do this:
const solib_ops *ops = pspace->solib_ops ();
for (objfile &objfile : pspace->objfiles ())
if (ops->in_same_linker_namespace (objfile, original_objfile))
{
... existing code ...
}
I did some hacking, and gives the same answer as the current approach,
but it isn't efficient as (currently) this requires looping over all
solib within the in_same_linker_namespace method. And we need that loop
because find_solib_for_objfile is broken.
I wonder if we should first try to fix find_solib_for_objfile? If this
could both return all solib in some way (more below), and maybe not
require a loop over all solib to search for the objfile, then this would
make what you want to do really straight forward.
On returning all solib, in order to avoid building a vector, I wondered
if we should consider linking all "sibling" solib into some kind of
linked list (sibling solib being solib that reference the same objfile),
then find_solib_for_objfile would return a single solib*, but users
would then need to iterate over all sibling solib.
> ---
> gdb/dwarf2/ada-imported.c | 8 +++-
> gdb/minsyms.c | 15 ++++---
> gdb/minsyms.h | 9 ++--
> gdb/solib-svr4.c | 20 ---------
> gdb/solib.c | 86 ++++++++++++++++++++++++++++++++++++++-
> gdb/solib.h | 19 +++++++++
> gdb/symtab.c | 13 +++++-
> 7 files changed, 136 insertions(+), 34 deletions(-)
>
> diff --git a/gdb/dwarf2/ada-imported.c b/gdb/dwarf2/ada-imported.c
> index 48e6fccdb73..15ecfdaf6ce 100644
> --- a/gdb/dwarf2/ada-imported.c
> +++ b/gdb/dwarf2/ada-imported.c
> @@ -35,9 +35,13 @@ static struct value *
> ada_imported_read_variable (struct symbol *symbol, const frame_info_ptr &frame)
> {
> const char *name = get_imported_name (symbol);
> +
> + std::vector<objfile *> objfiles_to_search;
> + for (objfile &objf : symbol->objfile ()->pspace ()->objfiles ())
> + objfiles_to_search.push_back (&objf);
> +
> bound_minimal_symbol minsym
> - = lookup_minimal_symbol_linkage (symbol->objfile ()->pspace (), name,
> - true, false);
> + = lookup_minimal_symbol_linkage (objfiles_to_search, name, true, false);
I would have expected some discussion in the commit message about why
this use of lookup_minimal_symbol_linkage doesn't require the same
namespace handling. I haven't looked at the code to try and figure it
out, so maybe it is obvious. But still, I think it's worth mentioning.
> if (minsym.minsym == nullptr)
> error (_("could not find imported name %s"), name);
> return value_at (symbol->type (), minsym.value_address ());
> diff --git a/gdb/minsyms.c b/gdb/minsyms.c
> index 90a0c601c59..7e4f47b8c3f 100644
> --- a/gdb/minsyms.c
> +++ b/gdb/minsyms.c
> @@ -54,6 +54,7 @@
> #include "gdbsupport/cxx-thread.h"
> #include "gdbsupport/parallel-for.h"
> #include "inferior.h"
> +#include "solib.h"
>
> /* Return true if MINSYM is a cold clone symbol.
> Recognize f.i. these symbols (mangled/demangled):
> @@ -584,19 +585,21 @@ lookup_minimal_symbol_linkage (const char *name, struct objfile *objf,
> /* See minsyms.h. */
>
> bound_minimal_symbol
> -lookup_minimal_symbol_linkage (program_space *pspace, const char *name,
> - bool match_static_type, bool only_main)
> +lookup_minimal_symbol_linkage (gdb::array_view<objfile *> objfiles_to_search,
> + const char *name, bool match_static_type,
> + bool only_main)
> {
> - for (objfile &objfile : pspace->objfiles ())
> + for (objfile *objfile : objfiles_to_search)
> {
> - if (objfile.separate_debug_objfile_backlink != nullptr)
> + if (objfile == nullptr
> + || objfile->separate_debug_objfile_backlink != nullptr)
> continue;
>
> - if (only_main && (objfile.flags & OBJF_MAINLINE) == 0)
> + if (only_main && (objfile->flags & OBJF_MAINLINE) == 0)
> continue;
>
> bound_minimal_symbol minsym
> - = lookup_minimal_symbol_linkage (name, &objfile, match_static_type);
> + = lookup_minimal_symbol_linkage (name, objfile, match_static_type);
> if (minsym.minsym != nullptr)
> return minsym;
> }
> diff --git a/gdb/minsyms.h b/gdb/minsyms.h
> index ed38044a38c..4aa8a428470 100644
> --- a/gdb/minsyms.h
> +++ b/gdb/minsyms.h
> @@ -237,11 +237,14 @@ extern bound_minimal_symbol lookup_minimal_symbol_linkage
>
> /* A variant of lookup_minimal_symbol_linkage that iterates over all
> objfiles of PSPACE. If ONLY_MAIN is true, then only an objfile with
> - OBJF_MAINLINE will be considered. */
> + OBJF_MAINLINE will be considered. This function should receive a
> + program_space::objfile_ranges instead, but we can't include progspace.h
> + here, nor can we do forward declarations of nested types, so std::vector
> + will waste a bit of memory to work around that issue. */
The reference to PSPACE here is now out of date.
Thanks,
Andrew
>
> extern bound_minimal_symbol lookup_minimal_symbol_linkage
> - (program_space *pspace, const char *name, bool match_static_type,
> - bool only_main) ATTRIBUTE_NONNULL (1);
> + (gdb::array_view<objfile *> objfiles_to_search, const char *name,
> + bool match_static_type, bool only_main);
>
> /* Look through all the current minimal symbol tables and find the
> first minimal symbol that matches NAME and PC. If OBJF is non-NULL,
> diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
> index c91e0b2c37b..49d2b207c36 100644
> --- a/gdb/solib-svr4.c
> +++ b/gdb/solib-svr4.c
> @@ -3595,26 +3595,6 @@ lp64_svr4_solib_ops::fetch_link_map_offsets () const
> }
> \f
>
> -/* Return the DSO matching OBJFILE or nullptr if none can be found. */
> -
> -static const solib *
> -find_solib_for_objfile (struct objfile *objfile)
> -{
> - if (objfile == nullptr)
> - return nullptr;
> -
> - /* If OBJFILE is a separate debug object file, look for the original
> - object file. */
> - if (objfile->separate_debug_objfile_backlink != nullptr)
> - objfile = objfile->separate_debug_objfile_backlink;
> -
> - for (const solib &so : current_program_space->solibs ())
> - if (so.objfile == objfile)
> - return &so;
> -
> - return nullptr;
> -}
> -
> /* Return the address of the r_debug object for the namespace containing
> SOLIB or zero if it cannot be found. This may happen when symbol files
> are added manually, for example, or with the main executable.
> diff --git a/gdb/solib.c b/gdb/solib.c
> index dade2a76a48..34b0d6b3f9c 100644
> --- a/gdb/solib.c
> +++ b/gdb/solib.c
> @@ -1825,8 +1825,92 @@ solib_linker_namespace_count (program_space *pspace)
> return 0;
> }
>
> -/* Implementation of the linker_namespace convenience variable.
> +/* See solib.h. */
> +
> +const solib *
> +find_solib_for_objfile (struct objfile *objfile)
> +{
> + if (objfile == nullptr)
> + return nullptr;
> +
> + /* If OBJFILE is a separate debug object file, look for the original
> + object file. */
> + if (objfile->separate_debug_objfile_backlink != nullptr)
> + objfile = objfile->separate_debug_objfile_backlink;
> +
> + for (const solib &so : objfile->pspace ()->solibs ())
> + if (so.objfile == objfile)
> + return &so;
> +
> + return nullptr;
> +}
> +
> +/* See solib.h. */
> +
> +std::vector<objfile *>
> +get_objfiles_in_linker_namespace (int nsid, program_space *pspace)
> +{
> + std::vector<objfile *> objfiles_in_ns;
> + const solib_ops *ops = pspace->solib_ops ();
> +
> + gdb_assert (ops->supports_namespaces ());
> +
> + /* If we're looking at the default namespace, we also need
> + to add the mainline objfiles by hand, since there is no
> + solib associated with those files. We add them first
> + because if we're searching for copy relocations, they
> + should be in the main file, so we'll find it faster. */
> + if (nsid == 0)
> + for (objfile &objf : pspace->objfiles ())
> + if ((objf.flags & OBJF_MAINLINE) != 0)
> + objfiles_in_ns.push_back (&objf);
> +
> + std::vector<const solib *> solibs = ops->get_solibs_in_ns (nsid);
> + /* Reserve for efficiency. */
> + objfiles_in_ns.reserve (solibs.size () + objfiles_in_ns.size ());
> + for (const solib *so : solibs)
> + objfiles_in_ns.push_back (so->objfile);
> +
> + return objfiles_in_ns;
> +}
> +
> +/* See solib.h. */
> +
> +std::vector<objfile *>
> +get_objfiles_in_linker_namespace (objfile *objfile)
> +{
> + program_space *pspace = objfile->pspace ();
> + const solib_ops *ops = pspace->solib_ops ();
> + const solib *so = find_solib_for_objfile (objfile);
> +
> + /* If the inferior hasn't started yet, the solib_ops won't be
> + set for the program space. Since namespaces only make sense
> + when the inferior has already created some, we can just skip
> + it here. */
> + if (ops != nullptr && ops->supports_namespaces ()
> + /* If we're searching for a symbol from the linker, we'll reach here
> + before having any namespaces. Return all objfiles since the
> + boundaries haven't been setup yet. */
> + && ops->num_active_namespaces () > 0
> + /* When trying to load libthread_db, we can search for a symbol in an
> + objfile with no associated solib. In that case, again, we should
> + return all objfiles. */
> + && so != nullptr)
> + {
> + return get_objfiles_in_linker_namespace (ops->find_solib_ns (*so),
> + pspace);
> + }
> +
> + /* If any of the previous conditions isn't satisfied, we return
> + the full list of objfiles in the inferior. */
> + std::vector<struct objfile *> found_objfiles;
> + for (struct objfile &objf : objfile->pspace ()->objfiles ())
> + found_objfiles.push_back (&objf);
>
> + return found_objfiles;
> +}
> +
> +/* Implementation of the linker_namespace convenience variable.
> This returns the GDB internal identifier of the linker namespace,
> for the selected frame, as an integer. If the inferior doesn't support
> linker namespaces, this always returns 0. */
> diff --git a/gdb/solib.h b/gdb/solib.h
> index 85ea6675b79..81389da6267 100644
> --- a/gdb/solib.h
> +++ b/gdb/solib.h
> @@ -20,6 +20,9 @@
> #ifndef GDB_SOLIB_H
> #define GDB_SOLIB_H
>
> +/* Forward decl's for prototypes */
> +struct objfile;
> +
> #include "gdb_bfd.h"
> #include "gdbsupport/function-view.h"
> #include "gdbsupport/intrusive_list.h"
> @@ -409,4 +412,20 @@ extern void handle_solib_event (void);
>
> extern int solib_linker_namespace_count (program_space *pspace);
>
> +/* Return a vector with pointers of all objfiles in the namespace
> + NSID. This version assumes that the inferior supports namespaces. */
> +
> +std::vector<objfile *> get_objfiles_in_linker_namespace
> + (int nsid, program_space *pspace);
> +
> +/* Return a vector with pointers of all objfiles in the same namespace
> + as OBJFILE. If the inferior doesn't support namespaces, return all
> + objfiles in the program_space. */
> +
> +std::vector<objfile *> get_objfiles_in_linker_namespace (objfile *objfile);
> +
> +/* Return the DSO matching OBJFILE or nullptr if none can be found. */
> +
> +const solib *find_solib_for_objfile (struct objfile *objfile);
> +
> #endif /* GDB_SOLIB_H */
> diff --git a/gdb/symtab.c b/gdb/symtab.c
> index 3b0687c0750..786dd9f56ba 100644
> --- a/gdb/symtab.c
> +++ b/gdb/symtab.c
> @@ -74,6 +74,7 @@
> #include "gdbsupport/common-utils.h"
> #include <optional>
> #include "gdbsupport/unordered_set.h"
> +#include "solib.h"
>
> /* Forward declarations for local functions. */
>
> @@ -6575,8 +6576,12 @@ symbol::get_maybe_copied_address () const
> gdb_assert (this->loc_class () == LOC_STATIC);
>
> const char *linkage_name = this->linkage_name ();
> +
> + std::vector<struct objfile *> objfiles_to_search
> + (get_objfiles_in_linker_namespace (this->objfile ()));
> +
> bound_minimal_symbol minsym
> - = lookup_minimal_symbol_linkage (this->objfile ()->pspace (), linkage_name,
> + = lookup_minimal_symbol_linkage (objfiles_to_search, linkage_name,
> false, false);
> if (minsym.minsym != nullptr)
> return minsym.value_address ();
> @@ -6593,8 +6598,12 @@ minimal_symbol::get_maybe_copied_address (objfile *objf) const
> gdb_assert ((objf->flags & OBJF_MAINLINE) == 0);
>
> const char *linkage_name = this->linkage_name ();
> +
> + std::vector<struct objfile *> objfiles_to_search
> + (get_objfiles_in_linker_namespace (objf));
> +
> bound_minimal_symbol found
> - = lookup_minimal_symbol_linkage (objf->pspace (), linkage_name,
> + = lookup_minimal_symbol_linkage (objfiles_to_search, linkage_name,
> false, true);
> if (found.minsym != nullptr)
> return found.value_address ();
> --
> 2.51.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PINGv3][PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols
2026-01-14 14:11 ` Guinevere Larsen
@ 2026-03-05 12:20 ` Guinevere Larsen
2026-03-05 12:21 ` Guinevere Larsen
1 sibling, 0 replies; 16+ messages in thread
From: Guinevere Larsen @ 2026-03-05 12:20 UTC (permalink / raw)
To: gdb-patches
Ping :)
On 1/14/26 11:11 AM, Guinevere Larsen wrote:
> Ping :)
> On 1/6/26 2:17 PM, Guinevere Larsen wrote:
>> Ping!
>> On 11/27/25 5:30 PM, Guinevere Larsen wrote:
>>> Ping :)
>>>
>>> On 10/29/25 9:58 AM, Guinevere Larsen wrote:
>>>> This series adds support for the syntax [[N]]::foo to find symbols
>>>> that
>>>> belong to specific namespaces, while also making GDB's behavior more
>>>> consistent when a namespace is not specified. This needs one
>>>> preparatory
>>>> patch and 2 patches actually implementing this feature
>>>>
>>>> Patch 1 is an essential fix, updating how we calculate a variable's
>>>> copy
>>>> relocation to take linker namespaces into account.
>>>>
>>>> Patches 2 and 3 implement the new syntax, adding the necessary
>>>> supporting code and updating error messages when symbols can't be
>>>> found
>>>> - where it made sense.
>>>>
>>>> Changes for v6:
>>>> * Rebased on master
>>>> * Fixed a crash when using the [[N]]::foo syntax before starting the
>>>> inferior
>>>>
>>>> Changes for v5:
>>>> * fixed crash when getting the value of a variable before the inferior
>>>> starts.
>>>> * Rebased on master
>>>>
>>>> Changes for v4:
>>>> * Fixed final documentation feedback from Eli.
>>>> * Changed error message when [[N]]::foo::bar fails to find 'foo'.
>>>> * Fixed build breakage.
>>>>
>>>> Changes for v3:
>>>> * Removed previous patches 1 and 2, as Simon's recently merged patches
>>>> already did those in a better way.
>>>> * parser_state now also takes the current solib_ops, since that
>>>> can't be
>>>> obtained from gdbarch anymore.
>>>>
>>>> Changes for v2:
>>>> * solib_supports_linker_namespaces now always expects a pointer.
>>>> * Previous patches 2 and 3 were dropped.
>>>> * lookup_minimal_symbol_linkage now takes an array_view.
>>>> * created new tokens for [[ and ]], to ensure that [[N]] looks like
>>>> that.
>>>> * Fixed formatting nits from Eli.
>>>>
>>>> Guinevere Larsen (3):
>>>> gdb: make lookup_minimal_symbol_linkage work with linker namespaces
>>>> gdb: Make the parser recognize the [[N]] syntax for variables
>>>> gdb: extend the [[N]]::foo syntax for files
>>>>
>>>> gdb/NEWS | 6 +
>>>> gdb/c-exp.y | 88 +++++++++---
>>>> gdb/doc/gdb.texinfo | 6 +
>>>> gdb/dwarf2/ada-imported.c | 8 +-
>>>> gdb/linespec.c | 4 +-
>>>> gdb/minsyms.c | 139
>>>> ++++++++++++-------
>>>> gdb/minsyms.h | 17 ++-
>>>> gdb/parse.c | 3 +-
>>>> gdb/parser-defs.h | 39 +++++-
>>>> gdb/rust-parse.c | 3 +-
>>>> gdb/solib-svr4.c | 20 ---
>>>> gdb/solib.c | 86 +++++++++++-
>>>> gdb/solib.h | 19 +++
>>>> gdb/symtab.c | 76 ++++++++--
>>>> gdb/symtab.h | 15 +-
>>>> gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c | 14 ++
>>>> gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c | 3 +
>>>> gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 65 +++++++++
>>>> 18 files changed, 499 insertions(+), 112 deletions(-)
>>>>
>>>>
>>>> base-commit: 0633b78640dc892265d148f24881d544d4ddd16e
>>>
>>>
>>
>
--
Cheers,
Guinevere Larsen
It/she
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PINGv3][PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols
2026-01-14 14:11 ` Guinevere Larsen
2026-03-05 12:20 ` [PINGv3][PATCH " Guinevere Larsen
@ 2026-03-05 12:21 ` Guinevere Larsen
1 sibling, 0 replies; 16+ messages in thread
From: Guinevere Larsen @ 2026-03-05 12:21 UTC (permalink / raw)
To: gdb-patches, Guinevere Larsen
Ping :)
On 1/14/26 11:11 AM, Guinevere Larsen wrote:
> Ping :)
> On 1/6/26 2:17 PM, Guinevere Larsen wrote:
>> Ping!
>> On 11/27/25 5:30 PM, Guinevere Larsen wrote:
>>> Ping :)
>>>
>>> On 10/29/25 9:58 AM, Guinevere Larsen wrote:
>>>> This series adds support for the syntax [[N]]::foo to find symbols
>>>> that
>>>> belong to specific namespaces, while also making GDB's behavior more
>>>> consistent when a namespace is not specified. This needs one
>>>> preparatory
>>>> patch and 2 patches actually implementing this feature
>>>>
>>>> Patch 1 is an essential fix, updating how we calculate a variable's
>>>> copy
>>>> relocation to take linker namespaces into account.
>>>>
>>>> Patches 2 and 3 implement the new syntax, adding the necessary
>>>> supporting code and updating error messages when symbols can't be
>>>> found
>>>> - where it made sense.
>>>>
>>>> Changes for v6:
>>>> * Rebased on master
>>>> * Fixed a crash when using the [[N]]::foo syntax before starting the
>>>> inferior
>>>>
>>>> Changes for v5:
>>>> * fixed crash when getting the value of a variable before the inferior
>>>> starts.
>>>> * Rebased on master
>>>>
>>>> Changes for v4:
>>>> * Fixed final documentation feedback from Eli.
>>>> * Changed error message when [[N]]::foo::bar fails to find 'foo'.
>>>> * Fixed build breakage.
>>>>
>>>> Changes for v3:
>>>> * Removed previous patches 1 and 2, as Simon's recently merged patches
>>>> already did those in a better way.
>>>> * parser_state now also takes the current solib_ops, since that
>>>> can't be
>>>> obtained from gdbarch anymore.
>>>>
>>>> Changes for v2:
>>>> * solib_supports_linker_namespaces now always expects a pointer.
>>>> * Previous patches 2 and 3 were dropped.
>>>> * lookup_minimal_symbol_linkage now takes an array_view.
>>>> * created new tokens for [[ and ]], to ensure that [[N]] looks like
>>>> that.
>>>> * Fixed formatting nits from Eli.
>>>>
>>>> Guinevere Larsen (3):
>>>> gdb: make lookup_minimal_symbol_linkage work with linker namespaces
>>>> gdb: Make the parser recognize the [[N]] syntax for variables
>>>> gdb: extend the [[N]]::foo syntax for files
>>>>
>>>> gdb/NEWS | 6 +
>>>> gdb/c-exp.y | 88 +++++++++---
>>>> gdb/doc/gdb.texinfo | 6 +
>>>> gdb/dwarf2/ada-imported.c | 8 +-
>>>> gdb/linespec.c | 4 +-
>>>> gdb/minsyms.c | 139
>>>> ++++++++++++-------
>>>> gdb/minsyms.h | 17 ++-
>>>> gdb/parse.c | 3 +-
>>>> gdb/parser-defs.h | 39 +++++-
>>>> gdb/rust-parse.c | 3 +-
>>>> gdb/solib-svr4.c | 20 ---
>>>> gdb/solib.c | 86 +++++++++++-
>>>> gdb/solib.h | 19 +++
>>>> gdb/symtab.c | 76 ++++++++--
>>>> gdb/symtab.h | 15 +-
>>>> gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c | 14 ++
>>>> gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c | 3 +
>>>> gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 65 +++++++++
>>>> 18 files changed, 499 insertions(+), 112 deletions(-)
>>>>
>>>>
>>>> base-commit: 0633b78640dc892265d148f24881d544d4ddd16e
>>>
>>>
>>
>
--
Cheers,
Guinevere Larsen
It/she
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v6 2/3] gdb: Make the parser recognize the [[N]] syntax for variables
2025-10-29 12:58 ` [PATCH v6 2/3] gdb: Make the parser recognize the [[N]] syntax for variables Guinevere Larsen
@ 2026-04-20 13:59 ` Andrew Burgess
2026-04-28 19:32 ` Guinevere Larsen
0 siblings, 1 reply; 16+ messages in thread
From: Andrew Burgess @ 2026-04-20 13:59 UTC (permalink / raw)
To: Guinevere Larsen, gdb-patches; +Cc: Guinevere Larsen, Eli Zaretskii
Guinevere Larsen <guinevere@redhat.com> writes:
> This commit adds a couple new rules to the YACC parser, that will allow
> GDB to recognize expressions like [[N]]::var.
>
> This new syntax reuses the existing rules for searching for "block"s,
> because it allows, with minimal changes to the .y file as a whole, while
> also allowing [[N]]::function::symbol work. Notably, [[N]]::'file.c'::var
> does not work yet, as this code change is also involved and would pollute
> the current commit, so will be done in a separate one in the same series.
>
> To restrict the search to a desired namespace, a new function is
> introduced, lookup_symbol_in_linker_namespace. This function will only
> perform the symbol lookup in the objfiles that belong to the requested
> namespace.
>
> This commit also changes the error message when "print var" if "var" is
> only present in namespaces other than the current one. Before this commit,
> lookup_minimal_symbol would find them as "external" symbols with
> incomplete information - outputting "<symbol> has incomplete
> information, cast it to it's defined type." - which could be confusing for
typo: "cast it to its defined type".
I went to check if the original error message contained the same error.
It doesn't, but not does it match what you quote. I think this is the
error you are referencing, from typeprint.c:
void
error_unknown_type (const char *sym_print_name)
{
error (_("'%s' has unknown type; cast it to its declared type"),
sym_print_name);
}
> the users. This commit changes the parser rule "variable: name_not_typename"
> so that, if multiple namespaces are active, we'll look for minimal symbols
> only in the current namespace.
>
> Known limitations:
> * When using [[N]]::foo::var, if that specific foo version is not on the
> stack, the error will be unable to include the linker namespace
> requested. So if a user sees "foo" in the stack this could be
> confusing, but it should be mitigated when a future patch adds the
> namespace ID to the backtrace where applicable.
> * Completion is not supported. That's because the function used to
> complete symbols expects only text in the form "file.c:symbol", so
> can't handle the double colon. This isn't unique to linker
> namespaces, though, since func::var will also not complete, it is just
> a quirk of how :: completion work at this point.
> * The expression that parses [[N]] only takes an integer. That's
> because there aren't many expressions that would make sense in there,
> and the work of accepting an arbitrary expression felt too much for
> little gain.
>
> Reviewed-By: Eli Zaretskii <eliz@gnu.org>
> ---
> gdb/NEWS | 6 +
> gdb/c-exp.y | 72 ++++++++---
> gdb/doc/gdb.texinfo | 6 +
> gdb/minsyms.c | 124 ++++++++++++-------
> gdb/minsyms.h | 8 ++
> gdb/parser-defs.h | 7 ++
> gdb/symtab.c | 37 ++++++
> gdb/symtab.h | 8 ++
> gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c | 14 +++
> gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c | 3 +
> gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 53 ++++++++
> 11 files changed, 274 insertions(+), 64 deletions(-)
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 097d8da350b..273bd400f1b 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -227,6 +227,12 @@ info threads [-gid] [-stopped] [-running] [ID]...
> These new flags can be useful to get a reduced list when there is a
> large number of threads.
>
> +print
> + The print command now accepts the following syntax to print values
> + from a specific linker namespace: `[[N]]::foo'. N is the namespace
> + identifier as understood by GDB.
> +
> +
Double blank line.
> * GDB-internal Thread Local Storage (TLS) support
>
> ** Linux targets for the x86_64, aarch64, ppc64, s390x, and riscv
> diff --git a/gdb/c-exp.y b/gdb/c-exp.y
> index 9f1cb1b2e2a..cb70bf3c863 100644
> --- a/gdb/c-exp.y
> +++ b/gdb/c-exp.y
> @@ -173,7 +173,7 @@ using namespace expr;
> struct ttype tsym;
> struct symtoken ssym;
> int voidval;
> - const struct block *bval;
> + struct bval_type bval;
> enum exp_opcode opcode;
>
> struct stoken_vector svec;
> @@ -261,6 +261,7 @@ static void c_print_token (FILE *file, int type, YYSTYPE value);
> %token TYPEOF
> %token DECLTYPE
> %token TYPEID
> +%token DOUBLESQUAREOPEN DOUBLESQUARECLOSE
>
> /* Special type cases, put in to allow the parser to distinguish different
> legal basetypes. */
> @@ -1056,30 +1057,42 @@ exp : FALSEKEYWORD
>
> block : BLOCKNAME
> {
> - if ($1.sym.symbol)
> - $$ = $1.sym.symbol->value_block ();
> - else
> + if ($1.sym.symbol == nullptr)
> error (_("No file or function \"%s\"."),
> copy_name ($1.stoken).c_str ());
> + $$.search_namespace = false;
> + $$.b_val = $1.sym.symbol->value_block ();
> }
> | FILENAME
> {
> $$ = $1;
> }
> + | DOUBLESQUAREOPEN INT DOUBLESQUARECLOSE
> + {
> + $$.search_namespace = true;
> + $$.namespace_val = $2.val;
Totally trivial issue, but the indentation here is different to at least
everything in this 'block' rule, you use TABS + 4 whitespace, while
everything else uses TABS + 2 whitespace. Would be nice to be
consistent.
> + }
> ;
>
> block : block COLONCOLON name
> {
> std::string copy = copy_name ($3);
> - struct symbol *tem
> - = lookup_symbol (copy.c_str (), $1,
> - SEARCH_FUNCTION_DOMAIN,
> - nullptr).symbol;
> + struct block_symbol tem;
>
> - if (tem == nullptr)
> + if ($1.search_namespace)
> + tem = lookup_symbol_in_linker_namespace
> + (copy.c_str (), $1.namespace_val, SEARCH_FUNCTION_DOMAIN);
lookup_symbol_in_linker_namespace takes an 'int' for the namespace-id,
but namespace_val is LONGEST. I suspect namespace_val needs to be
LONGEST as it gets it value from an INT token, whose value is a LONGEST.
But we should really have a check prior to the
lookup_symbol_in_linker_namespace call that we're not narrowing the
value in a meaningful way.
Or just change the namespace-id argument to LONGEST throughout maybe?
Either will work.
> + else
> + tem = lookup_symbol (copy.c_str (), $1.b_val,
> + SEARCH_FUNCTION_DOMAIN,
> + nullptr);
> +
> + if (tem.symbol == nullptr)
> error (_("No function \"%s\" in specified context."),
> copy.c_str ());
> - $$ = tem->value_block (); }
> + $$.b_val = tem.symbol->value_block ();
> + $$.search_namespace = false;
> + }
> ;
>
> variable: name_not_typename ENTRY
> @@ -1098,9 +1111,15 @@ variable: name_not_typename ENTRY
> variable: block COLONCOLON name
> {
> std::string copy = copy_name ($3);
> - struct block_symbol sym
> - = lookup_symbol (copy.c_str (), $1,
> - SEARCH_VFT, NULL);
> + struct block_symbol sym;
> +
> + if ($1.search_namespace)
> + sym = lookup_symbol_in_linker_namespace
> + (copy.c_str (), $1.namespace_val,
> + SEARCH_VFT);
> + else
> + sym = lookup_symbol (copy.c_str (), $1.b_val,
> + SEARCH_VFT, NULL);
>
> if (sym.symbol == 0)
> error (_("No symbol \"%s\" in specified context."),
> @@ -1196,13 +1215,25 @@ variable: name_not_typename
> {
> std::string arg = copy_name ($1.stoken);
>
> - bound_minimal_symbol msymbol
> - = lookup_minimal_symbol (current_program_space, arg.c_str ());
> + int active_linker_nss
> + = solib_linker_namespace_count
> + (current_program_space);
> + bound_minimal_symbol msymbol;
> +
> + if (active_linker_nss > 1)
> + msymbol = lookup_minimal_symbol_in_linker_namespace
> + (current_program_space, arg.c_str ());
> + else
> + msymbol = lookup_minimal_symbol
> + (current_program_space, arg.c_str ());
> if (msymbol.minsym == NULL)
> {
> if (!have_full_symbols (current_program_space)
> && !have_partial_symbols (current_program_space))
> error (_("No symbol table is loaded. Use the \"file\" command."));
> + else if (active_linker_nss > 1)
> + error (_("No symbol \"%s\" in the current linker namespace."),
> + arg.c_str ());
> else
> error (_("No symbol \"%s\" in current context."),
> arg.c_str ());
> @@ -2540,7 +2571,9 @@ static const struct c_token tokentab2[] =
> {"!=", NOTEQUAL, OP_NULL, 0},
> {"<=", LEQ, OP_NULL, 0},
> {">=", GEQ, OP_NULL, 0},
> - {".*", DOT_STAR, OP_NULL, FLAG_CXX}
> + {".*", DOT_STAR, OP_NULL, FLAG_CXX},
> + {"[[", DOUBLESQUAREOPEN, OP_NULL, 0},
> + {"]]", DOUBLESQUARECLOSE, OP_NULL, 0},
> };
>
> /* Identifier-like tokens. Only type-specifiers than can appear in
> @@ -3143,8 +3176,9 @@ classify_name (struct parser_state *par_state, const struct block *block,
> if (auto symtab = lookup_symtab (current_program_space, copy.c_str ());
> symtab != nullptr)
> {
> - yylval.bval
> + yylval.bval.b_val
> = symtab->compunit ()->blockvector ()->static_block ();
> + yylval.bval.search_namespace = false;
>
> return FILENAME;
> }
> @@ -3394,7 +3428,7 @@ yylex (void)
> name_obstack.clear ();
> checkpoint = 0;
> if (current.token == FILENAME)
> - search_block = current.value.bval;
> + search_block = current.value.bval.b_val;
> else if (current.token == COLONCOLON)
> search_block = NULL;
> else
> @@ -3577,7 +3611,7 @@ c_print_token (FILE *file, int type, YYSTYPE value)
> break;
>
> case FILENAME:
> - parser_fprintf (file, "bval<%s>", host_address_to_string (value.bval));
> + parser_fprintf (file, "bval<%s>", host_address_to_string (value.bval.b_val));
> break;
> }
> }
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 821f3ed4b05..b48f70d2250 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -10686,6 +10686,12 @@ you can choose a different format by specifying @samp{/@var{f}}, where
> @var{f} is a letter specifying the format; see @ref{Output Formats,,Output
> Formats}.
>
> +Additionally, if the inferior supports linker namespaces, @value{GDBN}
> +has implemented the following syntax to allow users to resolve symbols
> +to a specific namespace: @code{[[@var{n}]]::@var{symbol}}. Here @var{n}
> +is @value{GDBN}'s namespace identifier, which may be different from the
> +inferior's identifier.
Instead of @code{...} I think a better choice would be @samp{...} here.
My understanding is that @code would be for actual programming language
code.
> +
> @anchor{print options}
> The @code{print} command supports a number of options that allow
> overriding relevant global print settings as set by @code{set print}
> diff --git a/gdb/minsyms.c b/gdb/minsyms.c
> index 7e4f47b8c3f..a73d4f21858 100644
> --- a/gdb/minsyms.c
> +++ b/gdb/minsyms.c
> @@ -335,7 +335,10 @@ lookup_minimal_symbol_demangled (const lookup_name_info &lookup_name,
> }
> }
>
> -/* Look through all the current minimal symbol tables and find the
> +/* Main implementation for the lookup_minimal_symbol function.
> + Receives a list of objfiles in which to look for the symbol.
> +
> + Look through all the current minimal symbol tables and find the
> first minimal symbol that matches NAME. If OBJF is non-NULL, limit
> the search to that objfile. If SFILE is non-NULL, the only file-scope
> symbols considered will be from that source file (global symbols are
> @@ -355,9 +358,9 @@ lookup_minimal_symbol_demangled (const lookup_name_info &lookup_name,
> Obviously, there must be distinct mangled names for each of these,
> but the demangled names are all the same: S::S or S::~S. */
>
> -bound_minimal_symbol
> -lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf,
> - const char *sfile)
> +static bound_minimal_symbol
> +lookup_minimal_symbol_in_objfiles (std::vector<objfile *> objfile_list,
> + const char *name, const char *sfile)
> {
> found_minimal_symbols found;
>
> @@ -373,53 +376,48 @@ lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf,
>
> lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
>
> - for (objfile &objfile : pspace->objfiles ())
> + for (objfile *objfile : objfile_list)
> {
> if (found.external_symbol.minsym != NULL)
> break;
>
> - if (objf == NULL || objf == &objfile
> - || objf == objfile.separate_debug_objfile_backlink)
> + symbol_lookup_debug_printf ("lookup_minimal_symbol (%s, %s, %s)",
> + name, sfile != NULL ? sfile : "NULL",
> + objfile_debug_name (objfile));
> +
> + /* Do two passes: the first over the ordinary hash table,
> + and the second over the demangled hash table. */
> + lookup_minimal_symbol_mangled (name, sfile, objfile,
> + objfile->per_bfd->msymbol_hash,
> + mangled_hash, mangled_cmp, found);
> +
> + /* If not found, try the demangled hash table. */
> + if (found.external_symbol.minsym == NULL)
> {
> - symbol_lookup_debug_printf ("lookup_minimal_symbol (%s, %s, %s, %s)",
> - host_address_to_string (pspace),
> - name, sfile != NULL ? sfile : "NULL",
> - objfile_debug_name (&objfile));
> -
> - /* Do two passes: the first over the ordinary hash table,
> - and the second over the demangled hash table. */
> - lookup_minimal_symbol_mangled (name, sfile, &objfile,
> - objfile.per_bfd->msymbol_hash,
> - mangled_hash, mangled_cmp, found);
> -
> - /* If not found, try the demangled hash table. */
> - if (found.external_symbol.minsym == NULL)
> + /* Once for each language in the demangled hash names
> + table (usually just zero or one languages). */
> + for (unsigned iter = 0; iter < nr_languages; ++iter)
> {
> - /* Once for each language in the demangled hash names
> - table (usually just zero or one languages). */
> - for (unsigned iter = 0; iter < nr_languages; ++iter)
> - {
> - if (!objfile.per_bfd->demangled_hash_languages.test (iter))
> - continue;
> - enum language lang = (enum language) iter;
> -
> - unsigned int hash
> - = (lookup_name.search_name_hash (lang)
> - % MINIMAL_SYMBOL_HASH_SIZE);
> -
> - symbol_name_matcher_ftype *match
> - = language_def (lang)->get_symbol_name_matcher
> - (lookup_name);
> - struct minimal_symbol **msymbol_demangled_hash
> - = objfile.per_bfd->msymbol_demangled_hash;
> -
> - lookup_minimal_symbol_demangled (lookup_name, sfile, &objfile,
> - msymbol_demangled_hash,
> - hash, match, found);
> -
> - if (found.external_symbol.minsym != NULL)
> - break;
> - }
> + if (!objfile->per_bfd->demangled_hash_languages.test (iter))
> + continue;
> + enum language lang = (enum language) iter;
> +
> + unsigned int hash
> + = (lookup_name.search_name_hash (lang)
> + % MINIMAL_SYMBOL_HASH_SIZE);
> +
> + symbol_name_matcher_ftype *match
> + = language_def (lang)->get_symbol_name_matcher
> + (lookup_name);
> + struct minimal_symbol **msymbol_demangled_hash
> + = objfile->per_bfd->msymbol_demangled_hash;
> +
> + lookup_minimal_symbol_demangled (lookup_name, sfile, objfile,
> + msymbol_demangled_hash,
> + hash, match, found);
> +
> + if (found.external_symbol.minsym != NULL)
> + break;
> }
> }
> }
> @@ -472,6 +470,42 @@ lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf,
> return {};
> }
>
> +/* See minsyms.h. */
> +
> +bound_minimal_symbol
> +lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf,
> + const char *sfile)
> +{
> + std::vector<objfile *> search_objfiles;
> + if (objf != nullptr)
> + {
> + search_objfiles.push_back (objf);
> + if (objf->separate_debug_objfile_backlink != nullptr)
> + search_objfiles.push_back (objf->separate_debug_objfile_backlink);
There's a change in behaviour here. If we imagine that objfile A has a
separate_debug_objfile of B. The previous code looped over every
objfile and did:
if (objf == NULL || objf == &objfile
|| objf == objfile.separate_debug_objfile_backlink)
// Include this objfile.
If OBJF was 'A' then we would include both 'A' and 'B' as B's backlink
points at 'A'.
However, the new code does:
search_objfiles.push_back (objf);
if (objf->separate_debug_objfile_backlink != nullptr)
search_objfiles.push_back (objf->separate_debug_objfile_backlink);
So if we pass 'A' then we include 'A', but A's backlink will be NULL, so
we'll not search 'B'.
Due to this flipping of the logic, then if we pass 'B' then under the
old scheme we'd only include 'B', but under the new scheme we include
both 'A' and 'B'.
This change of behaviour wasn't called out in the commit message, so I'm
assuming this might be a mistake.
> + }
> + else
> + {
> + for (objfile &objfile : pspace->objfiles ())
> + search_objfiles.push_back (&objfile);
> + }
> +
> + return lookup_minimal_symbol_in_objfiles (search_objfiles, name, sfile);
> +}
> +
> +/* See minsyms.h. */
> +
> +bound_minimal_symbol
> +lookup_minimal_symbol_in_linker_namespace (program_space *pspace,
> + const char *name)
> +{
> + LONGEST curr_namespace;
> + get_internalvar_integer (lookup_internalvar ("_linker_namespace"),
> + &curr_namespace);
Rather than reading the internal variable, would it not be better to
have a helper function in solib.{c,h} which returns the current
namespace-id, then have the internal variable and this code just call
that?
> + return lookup_minimal_symbol_in_objfiles
> + (get_objfiles_in_linker_namespace (curr_namespace, pspace),
> + name, nullptr);
> +}
> +
> /* See gdbsupport/symbol.h. */
>
> int
> diff --git a/gdb/minsyms.h b/gdb/minsyms.h
> index 4aa8a428470..f2ba15d9318 100644
> --- a/gdb/minsyms.h
> +++ b/gdb/minsyms.h
> @@ -211,6 +211,14 @@ bound_minimal_symbol lookup_minimal_symbol (program_space *pspace,
> objfile *obj = nullptr,
> const char *sfile = nullptr);
>
> +/* Same as above, but only look for a minimal symbol in the objfiles that
> + belong to the current linker namespace. This function is only meant to
> + be called when attempting to resolve a symbol from a user command, and
> + there are multiple linker namespaces available to resolve it in. */
> +
> +bound_minimal_symbol lookup_minimal_symbol_in_linker_namespace
> + (program_space *pspace, const char *name);
> +
> /* Look through all the minimal symbol tables in PSPACE and find the
> first minimal symbol that matches NAME and has text type. If OBJF
> is non-NULL, limit the search to that objfile. Returns a bound
> diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
> index f5618f3a9ce..ff4ab6a09de 100644
> --- a/gdb/parser-defs.h
> +++ b/gdb/parser-defs.h
> @@ -358,6 +358,13 @@ struct ttype
> struct type *type;
> };
>
> +struct bval_type
> + {
> + bool search_namespace;
> + const struct block *b_val;
> + LONGEST namespace_val;
> + };
I know there are plenty of (older) structures in here that are missing
comments, but there are also some, e.g. stoken, typed_stoken, that do
have comments. I think it would be better if new code did comment the
structures that are added.
> +
> struct symtoken
> {
> struct stoken stoken;
> diff --git a/gdb/symtab.c b/gdb/symtab.c
> index 786dd9f56ba..d237a5cc5d2 100644
> --- a/gdb/symtab.c
> +++ b/gdb/symtab.c
> @@ -2558,6 +2558,43 @@ lookup_static_symbol (const char *name, const domain_search_flags domain)
>
> /* See symtab.h. */
>
> +struct block_symbol
> +lookup_symbol_in_linker_namespace (const char *name, int nsid,
> + const domain_search_flags domain)
> +{
> + if (!current_program_space->solib_ops ()->supports_namespaces ())
> + error (_("Linker namespaces are not supported by the inferior."));
> +
> + std::vector<objfile *> objfiles_in_namespace
> + = get_objfiles_in_linker_namespace (nsid, current_program_space);
> +
> + if (objfiles_in_namespace.size() == 0)
Missing space before '()'.
> + error (_("Namespace [[%d]] is inactive"), nsid);
> +
> + symbol_lookup_debug_printf ("lookup_symbol_in_linker_namespace (%d, %s, %s)",
> + nsid, name, domain_name (domain).c_str ());
> +
> + /* We look for both global and static symbols in here. There is no reason
> + to pick one over the other to my knowledge, so we go alphabetical. */
I find the whole alphabetical thing a bit weird. I'd just say:
/* We look for both global and static symbols in here, the order is
arbitrary. */
But if you prefer your wording then that's fine too I guess.
> + for (objfile *objf : objfiles_in_namespace)
> + {
> + struct block_symbol bsym
> + = lookup_global_symbol_from_objfile (objf, GLOBAL_BLOCK,
> + name, domain);
> + if (bsym.symbol != nullptr)
> + return bsym;
> +
> + bsym = lookup_global_symbol_from_objfile (objf, STATIC_BLOCK,
> + name, domain);
> + if (bsym.symbol != nullptr)
> + return bsym;
> + }
When looking at this function, I started looking in c-exp.y, and in here
we see that the two paths are lookup_symbol_in_linker_namespace or
lookup_symbol, so when I reviewed this function I was comparing against
lookup_symbol.
lookup_symbol calls lookup_symbol_in_language, which uses
demangle_for_lookup to demangle and canonicalize the string being
searched for. But lookup_symbol_in_linker_namespace doesn't call this
function. Isn't that going to be a problem?
After demangle_for_lookup lookup_symbol_in_language calls
lookup_symbol_aux to do the actual lookup. This function does a bunch
of local symbol lookup, which we probably don't need for the namespace
searching path, but then does:
/* Now do whatever is appropriate for LANGUAGE to look
up static and global variables. */
result = langdef->lookup_symbol_nonlocal (name, block, domain);
to lookup the global/static symbols, this does a bunch of language
specific stuff, especially for e.g. C++. Yet
lookup_symbol_in_linker_namespace doesn't call this, it just goes direct
to the global/static block and looks for an exact match.
Are there issues here? Or is there something that I'm missing. If this
is a limitation then maybe this should be documented somewhere?
> +
> + return {};
> +}
> +
> +/* See symtab.h. */
> +
> struct block_symbol
> lookup_global_symbol (const char *name,
> const struct block *block,
> diff --git a/gdb/symtab.h b/gdb/symtab.h
> index e47033efd01..fe2304acb4f 100644
> --- a/gdb/symtab.h
> +++ b/gdb/symtab.h
> @@ -2737,6 +2737,14 @@ extern struct block_symbol
> const char *name,
> const domain_search_flags domain);
>
> +/* Lookup symbol NAME from DOMAIN in the linker namespace NSID.
> + This generates a list of all objfiles in NSID, then searches
> + those objfiles for the given symbol. Searches for both global or
> + static symbols. */
> +extern struct block_symbol
> + lookup_symbol_in_linker_namespace (const char *name, int nsid,
> + const domain_search_flags domain);
> +
> extern unsigned int symtab_create_debug;
>
> /* Print a "symtab-create" debug statement. */
> diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c
> index 86cbb0f4e38..cc35ce0080e 100644
> --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c
> +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c
> @@ -26,3 +26,17 @@ inc (int n)
> int amount = gdb_dlmopen_glob;
> return n + amount; /* bp.inc. */
> }
> +
> +static int
> +change_global (int n)
> +{
> + gdb_dlmopen_glob += n;
> + return n;
> +}
> +
> +__attribute__((visibility ("default")))
> +int
> +func_with_other_call (int n)
> +{
> + return change_global (n + 1);
> +}
> diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c
> index c7c038a08d1..459ae547842 100644
> --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c
> +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c
> @@ -47,6 +47,9 @@ main (void)
> fun (dl);
> }
>
> + fun = dlsym (handle[0], "func_with_other_call");
> + fun (0);
> +
> dlclose (handle[0]); /* TAG: first dlclose */
> dlclose (handle[1]); /* TAG: second dlclose */
> dlclose (handle[2]); /* TAG: third dlclose */
> diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
> index f3bdfb054d9..fec7adb5317 100644
> --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
> +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
> @@ -123,6 +123,10 @@ proc get_first_so_ns {} {
> return $ns
> }
>
> +proc ns_id_for_command {ns} {
> + return "\[\[$ns\]\]"
> +}
> +
> # Run the tests relating to the command "info sharedlibrary", to
> # verify that the namespace ID is consistent.
> proc test_info_shared {} {
> @@ -315,6 +319,55 @@ proc test_info_linker_namespaces {} {
> ".*" ] "print namespaces with no argument"
> }
>
> +# Test that we can use the [[N]]::symbol syntax, and it's variations
> +# like [[N]]::func::symbol.
typo: "and its variations like..."
Thanks,
Andrew
> +proc_with_prefix test_print_namespace_symbol {} {
> + clean_restart
> + gdb_load $::binfile
> +
> + set ns1 [ns_id_for_command 1]
> + set ns2 [ns_id_for_command 2]
> +
> + if { ![runto_main] } {
> + return
> + }
> +
> + gdb_breakpoint [gdb_get_line_number "TAG: first dlclose"]
> + gdb_breakpoint "change_global" allow-pending
> +
> + # Test printing variables for non-existent namespace.
> + gdb_test "print ${ns1}::gdb_dlmopen_glob" "Namespace ..1.. is inactive" \
> + "Before loading namespaces"
> +
> + gdb_continue_to_breakpoint "change_global"
> +
> + # Test finding location of variables.
> + gdb_test "print ${ns1}::gdb_dlmopen_glob" ".* = 0" "before changing"
> + gdb_test_no_output "set ${ns1}::gdb_dlmopen_glob = 1"
> + gdb_test "print ${ns1}::gdb_dlmopen_glob" ".* = 1" "after changing"
> + gdb_test "print ${ns2}::gdb_dlmopen_glob" ".* = 0" "other namespace"
> +
> + gdb_test "print gdb_dlmopen_glob" ".* = 1" "changed the right variable"
> +
> + # Test finding functions in specific namespaces.
> + gdb_test "print ${ns1}::inc (2)" ".* = 3"
> + gdb_test "print ${ns2}::inc (2)" ".* = 2"
> +
> + # Test finding a specific block in the backtrace.
> + gdb_test "print n" ".* = 1"
> + gdb_test "print ${ns1}::func_with_other_call::n" ".* = 0"
> + gdb_test "print ${ns2}::func_with_other_call::n" \
> + "No frame is currently executing in block func_with_other_call."
> +
> + # Leave to default namespace.
> + gdb_continue_to_breakpoint "TAG: first dlclose"
> + # This global doesn't exist in the default namespace. Rather than
> + # returning a random one, we just say we didn't find one.
> + gdb_test "print gdb_dlmopen_glob" \
> + "No symbol .gdb_dlmopen_glob. in the current linker namespace."
> +}
> +
> test_info_shared
> test_conv_vars
> test_info_linker_namespaces
> +test_print_namespace_symbol
> --
> 2.51.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v6 3/3] gdb: extend the [[N]]::foo syntax for files
2025-10-29 12:58 ` [PATCH v6 3/3] gdb: extend the [[N]]::foo syntax for files Guinevere Larsen
@ 2026-04-20 15:13 ` Andrew Burgess
2026-04-28 20:20 ` Guinevere Larsen
2026-05-13 17:08 ` Guinevere Larsen
0 siblings, 2 replies; 16+ messages in thread
From: Andrew Burgess @ 2026-04-20 15:13 UTC (permalink / raw)
To: Guinevere Larsen, gdb-patches; +Cc: Guinevere Larsen
Guinevere Larsen <guinevere@redhat.com> writes:
> This commit implements the missing support for [[N]]::'file.c'::var
> syntax that was skipped on the previous commit.
>
> This is done by adding a new value to the global parser_state, so that
> the classify_name function can restrict its search for file names to the
> specified linker namespace. It had to be done this way because if the
> logic was contained on the newly added "block: block COLONCOLON
> FILENAME" rule, we would not have the name to rerun the search.
Did you consider adding the filename to the <whatever> type such that it
was available within the rule to allow for the filename to be re-looked
up?
I'd be interested to know if this was tried, why this was worse than
pushing parser state back to the lexer, which I always thought was not a
great design.
> Because
> of that, the new rule only exists to make sure this is only used in the
> intended syntax. This commit also adds a link to the solib_ops relevant
> to the expression being parsed, as a way to identify if linker
> namespaces are supported; this could be achieved by guarding the search
> functions instead, but I think that this is more reliable.
>
> The new rule uses "block" rather than a linker namespace specific token,
> because if we allowed that token to also reduce into block, the new rule
> would never be triggered as the simple reduction would be preferred. If
> we didn't allow the linker namespace to reduce into block, the rest of
> the syntaxes for [[N]]::foo would be more involved, so the option in
> this commit seemed like the simplest solution.
>
> The rule "block: block COLONCOLON name" also had to be updated because,
> if a user tried to search for a file not present in the linker
> namespace, GDB would miscategorize it to 'name' instead of 'filename',
> and if no function of the same name was found, the error would only say
> "No function \"foo\" (...)" which could confuse a user. The new error
> says "Nothing named \"foo\" (...)" instead since it is impossible for us
> to disambiguate between filename or function name, and both would be
> valid in this code path.
>
> The parser_state changes were not used for the previous commit because
> the lookup_symbol calls would lead to an even more intrusive change for
> no real gain, since the search would be rerun any way. There is an
> argument to be made that the results could be different if only
> namespace had a type and another had a variable, but a situation where
> that significantly changes the result is quite unlikely, I think.
> ---
> gdb/c-exp.y | 18 +++++++++++--
> gdb/linespec.c | 4 +--
> gdb/parse.c | 3 ++-
> gdb/parser-defs.h | 32 +++++++++++++++++++++--
> gdb/rust-parse.c | 3 ++-
> gdb/symtab.c | 26 +++++++++++++-----
> gdb/symtab.h | 7 ++++-
> gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 12 +++++++++
> 8 files changed, 90 insertions(+), 15 deletions(-)
>
> diff --git a/gdb/c-exp.y b/gdb/c-exp.y
> index cb70bf3c863..f59aca327ed 100644
> --- a/gdb/c-exp.y
> +++ b/gdb/c-exp.y
> @@ -1071,6 +1071,7 @@ block : BLOCKNAME
> {
> $$.search_namespace = true;
> $$.namespace_val = $2.val;
> + pstate->set_linker_namespace ($2.val);
> }
> ;
>
> @@ -1087,12 +1088,24 @@ block : block COLONCOLON name
> SEARCH_FUNCTION_DOMAIN,
> nullptr);
>
> - if (tem.symbol == nullptr)
> + if (tem.symbol == nullptr && !$$.search_namespace)
> error (_("No function \"%s\" in specified context."),
> copy.c_str ());
> + else if (tem.symbol == nullptr && $$.search_namespace)
My yacc foo is weak, but isn't '$$' the rule's output? Which is only
being set below. Shouldn't this be $1 maybe? If there's not some
reason why search_namespace is being set to the correct value (that I'm
missing) then this would seem to indicate that there's a gap in the
testing here.
> + /* COPY can be a function or a file. There is no way
> + to identify which the user intended, so emit a
> + generic warning instead. */
> + error (_("Nothing named \"%s\" in specified context."),
> + copy.c_str ());
> $$.b_val = tem.symbol->value_block ();
> $$.search_namespace = false;
> }
> + | block COLONCOLON FILENAME
> + {
> + if (!$1.search_namespace)
> + error (_("Filename must be the first part of the expression"));
> + $$ = $3;
> + }
> ;
>
> variable: name_not_typename ENTRY
> @@ -3173,7 +3186,8 @@ classify_name (struct parser_state *par_state, const struct block *block,
> || is_quoted_name)
> {
> /* See if it's a file name. */
> - if (auto symtab = lookup_symtab (current_program_space, copy.c_str ());
> + if (auto symtab = lookup_symtab (current_program_space, copy.c_str (),
> + par_state->get_linker_namespace ());
> symtab != nullptr)
> {
> yylval.bval.b_val
> diff --git a/gdb/linespec.c b/gdb/linespec.c
> index 08f7fdd0daa..ec90ad4826a 100644
> --- a/gdb/linespec.c
> +++ b/gdb/linespec.c
> @@ -3633,11 +3633,11 @@ collect_symtabs_from_filename (const char *file,
> if (pspace->executing_startup)
> continue;
>
> - iterate_over_symtabs (pspace, file, collector);
> + iterate_over_symtabs (pspace, file, -1, collector);
> }
> }
> else
> - iterate_over_symtabs (search_pspace, file, collector);
> + iterate_over_symtabs (search_pspace, file, -1, collector);
>
> /* It is tempting to use the unordered_dense 'extract' method here,
> and remove the separate vector -- but it's unclear if ordering
> diff --git a/gdb/parse.c b/gdb/parse.c
> index d76768f41d7..7358c369d52 100644
> --- a/gdb/parse.c
> +++ b/gdb/parse.c
> @@ -420,7 +420,8 @@ parse_exp_in_context (const char **stringptr, CORE_ADDR pc,
>
> parser_state ps (lang, get_current_arch (), expression_context_block,
> expression_context_pc, flags, *stringptr,
> - completer != nullptr, tracker);
> + completer != nullptr, tracker,
> + current_program_space->solib_ops ());
>
> scoped_restore_current_language lang_saver (lang->la_language);
>
> diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
> index ff4ab6a09de..c0be1083f66 100644
> --- a/gdb/parser-defs.h
> +++ b/gdb/parser-defs.h
> @@ -26,6 +26,7 @@
> #include "expression.h"
> #include "symtab.h"
> #include "expop.h"
> +#include "solib.h"
>
> struct block;
> struct language_defn;
> @@ -147,7 +148,8 @@ struct parser_state : public expr_builder
> parser_flags flags,
> const char *input,
> bool completion,
> - innermost_block_tracker *tracker)
> + innermost_block_tracker *tracker,
> + const solib_ops *ops)
> : expr_builder (lang, gdbarch),
> expression_context_block (context_block),
> expression_context_pc (context_pc),
> @@ -157,7 +159,8 @@ struct parser_state : public expr_builder
> comma_terminates ((flags & PARSER_COMMA_TERMINATES) != 0),
> parse_completion (completion),
> void_context_p ((flags & PARSER_VOID_CONTEXT) != 0),
> - debug ((flags & PARSER_DEBUG) != 0)
> + debug ((flags & PARSER_DEBUG) != 0),
> + m_solib_ops (ops)
> {
> }
>
> @@ -263,6 +266,21 @@ struct parser_state : public expr_builder
> push (expr::make_operation<T> (std::move (lhs), std::move (rhs)));
> }
>
> + void set_linker_namespace (LONGEST ns_id)
> + {
> + if (m_solib_ops == nullptr)
> + error (_("Linker namespaces require an active inferior"));
> + if (m_solib_ops->supports_namespaces ())
> + linker_namespace = ns_id;
> + else
> + error (_("Linker namespaces are not supported"));
> + }
> +
> + LONGEST get_linker_namespace ()
This can be const.
> + {
> + return linker_namespace;
> + }
> +
> /* Function called from the various parsers' yyerror functions to throw
> an error. The error will include a message identifying the location
> of the error within the current expression. */
> @@ -323,6 +341,16 @@ struct parser_state : public expr_builder
>
> /* Stack of operations. */
> std::vector<expr::operation_up> m_operations;
> +
> + /* If the expression is being restricted to a specific namespace, this is
> + where that information is stored for the block lookup. It should be
> + accessed through setter/getters to ensure that the linker namespace is
> + only set when the gdbarch supports it. */
> + LONGEST linker_namespace = -1;
This should be renamed m_linker_namespace as it is private.
Also, I couldn't find anything that would reset the linker namepsace
back to -1 when parsing a complex expression. For example, something
like:
print [[1]]::'foo.c'::var_a + 'bar.c'::var_b
After parsing the [[1]] linker_namespace will be set to '1', but is it
ever reset? Will we not end up parsing the "'bar.c'::var_b" as if the
lookup had to be in namespace 1?
Thanks,
Andrew
> +
> + /* Used to figure out if an inferior is capable of handling linker
> + namespaces at all. */
> + const solib_ops *m_solib_ops;
> };
>
> /* A string token, either a char-string or bit-string. Char-strings are
> diff --git a/gdb/rust-parse.c b/gdb/rust-parse.c
> index b740d5a7b16..27f03b23e6a 100644
> --- a/gdb/rust-parse.c
> +++ b/gdb/rust-parse.c
> @@ -2315,7 +2315,8 @@ rust_lex_tests (void)
> {
> /* Set up dummy "parser", so that rust_type works. */
> parser_state ps (language_def (language_rust), current_inferior ()->arch (),
> - nullptr, 0, 0, nullptr, 0, nullptr);
> + nullptr, 0, 0, nullptr, 0, nullptr,
> + current_program_space->solib_ops ());
> rust_parser parser (&ps);
>
> rust_lex_test_one (&parser, "", 0);
> diff --git a/gdb/symtab.c b/gdb/symtab.c
> index d237a5cc5d2..bbaf94e51d0 100644
> --- a/gdb/symtab.c
> +++ b/gdb/symtab.c
> @@ -618,6 +618,7 @@ compare_filenames_for_search (const char *filename, const char *search_name)
>
> void
> iterate_over_symtabs (program_space *pspace, const char *name,
> + LONGEST linker_ns,
> gdb::function_view<bool (symtab *)> callback)
> {
> gdb::unique_xmalloc_ptr<char> real_path;
> @@ -630,20 +631,33 @@ iterate_over_symtabs (program_space *pspace, const char *name,
> gdb_assert (IS_ABSOLUTE_PATH (real_path.get ()));
> }
>
> - for (objfile &objfile : pspace->objfiles ())
> - if (objfile.map_symtabs_matching_filename (name, real_path.get (),
> - callback))
> + std::vector<objfile *> objfiles_to_search;
> + if (linker_ns >= 0)
> + {
> + gdb_assert (pspace->solib_ops ()->supports_namespaces ());
> + objfiles_to_search
> + = get_objfiles_in_linker_namespace (linker_ns, pspace);
> + }
> + else
> + {
> + for (objfile &objf : pspace->objfiles ())
> + objfiles_to_search.push_back (&objf);
> + }
> +
> + for (objfile *objfile : objfiles_to_search)
> + if (objfile->map_symtabs_matching_filename (name, real_path.get (),
> + callback))
> return;
> }
>
> /* See symtab.h. */
>
> symtab *
> -lookup_symtab (program_space *pspace, const char *name)
> +lookup_symtab (program_space *pspace, const char *name, LONGEST linker_ns)
> {
> struct symtab *result = NULL;
>
> - iterate_over_symtabs (pspace, name, [&] (symtab *symtab)
> + iterate_over_symtabs (pspace, name, linker_ns, [&] (symtab *symtab)
> {
> result = symtab;
> return true;
> @@ -6158,7 +6172,7 @@ collect_file_symbol_completion_matches (completion_tracker &tracker,
>
> /* Go through symtabs for SRCFILE and check the externs and statics
> for symbols which match. */
> - iterate_over_symtabs (current_program_space, srcfile, [&] (symtab *s)
> + iterate_over_symtabs (current_program_space, srcfile, -1, [&] (symtab *s)
> {
> add_symtab_completions (s->compunit (),
> tracker, mode, lookup_name,
> diff --git a/gdb/symtab.h b/gdb/symtab.h
> index fe2304acb4f..bda6e82da02 100644
> --- a/gdb/symtab.h
> +++ b/gdb/symtab.h
> @@ -2079,7 +2079,8 @@ const char *multiple_symbols_select_mode (void);
>
> /* Lookup a symbol table in PSPACE by source file name. */
>
> -extern symtab *lookup_symtab (program_space *pspace, const char *name);
> +extern symtab *lookup_symtab (program_space *pspace, const char *name,
> + LONGEST linker_ns = -1);
>
> /* An object of this type is passed as the 'is_a_field_of_this'
> argument to lookup_symbol and lookup_symbol_in_language. */
> @@ -2805,10 +2806,14 @@ bool compare_glob_filenames_for_search (const char *filename,
> psymtabs. *If* there is no '/' in the name, a match after a '/' in the
> symtab filename will also work.
>
> + If LINKER_NS is 0 or greater, only the objfiles in the provided linker
> + namespace will be iterated over.
> +
> Call CALLBACK with each symtab that is found. If CALLBACK returns
> true, the search stops. */
>
> void iterate_over_symtabs (program_space *pspace, const char *name,
> + LONGEST linker_ns,
> gdb::function_view<bool (symtab *)> callback);
>
> std::vector<const linetable_entry *> find_linetable_entries_for_symtab_line
> diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
> index fec7adb5317..a1e18fc39d3 100644
> --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
> +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
> @@ -325,9 +325,15 @@ proc_with_prefix test_print_namespace_symbol {} {
> clean_restart
> gdb_load $::binfile
>
> + set ns0 [ns_id_for_command 0]
> set ns1 [ns_id_for_command 1]
> set ns2 [ns_id_for_command 2]
>
> + # Test printing variables before starting the inferior
> + gdb_test "print ${ns1}::gdb_dlmopen_glob" \
> + "Linker namespaces require an active inferior" \
> + "Before starting inferior"
> +
> if { ![runto_main] } {
> return
> }
> @@ -365,6 +371,12 @@ proc_with_prefix test_print_namespace_symbol {} {
> # returning a random one, we just say we didn't find one.
> gdb_test "print gdb_dlmopen_glob" \
> "No symbol .gdb_dlmopen_glob. in the current linker namespace."
> +
> + # Minimal testing for finding files in namespaces.
> + gdb_test "print ${ns1}::'${::srcfile_lib}'::gdb_dlmopen_glob" \
> + ".* = 2"
> + gdb_test "print ${ns0}::'${::srcfile_lib}'::gdb_dlmopen_glob" \
> + "Nothing named .${::srcfile_lib}. in specified context."
> }
>
> test_info_shared
> --
> 2.51.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v6 2/3] gdb: Make the parser recognize the [[N]] syntax for variables
2026-04-20 13:59 ` Andrew Burgess
@ 2026-04-28 19:32 ` Guinevere Larsen
0 siblings, 0 replies; 16+ messages in thread
From: Guinevere Larsen @ 2026-04-28 19:32 UTC (permalink / raw)
To: Andrew Burgess, gdb-patches; +Cc: Eli Zaretskii
On 4/20/26 10:59 AM, Andrew Burgess wrote:
> Guinevere Larsen <guinevere@redhat.com> writes:
>
>> This commit adds a couple new rules to the YACC parser, that will allow
>> GDB to recognize expressions like [[N]]::var.
>>
>> This new syntax reuses the existing rules for searching for "block"s,
>> because it allows, with minimal changes to the .y file as a whole, while
>> also allowing [[N]]::function::symbol work. Notably, [[N]]::'file.c'::var
>> does not work yet, as this code change is also involved and would pollute
>> the current commit, so will be done in a separate one in the same series.
>>
>> To restrict the search to a desired namespace, a new function is
>> introduced, lookup_symbol_in_linker_namespace. This function will only
>> perform the symbol lookup in the objfiles that belong to the requested
>> namespace.
>>
>> This commit also changes the error message when "print var" if "var" is
>> only present in namespaces other than the current one. Before this commit,
>> lookup_minimal_symbol would find them as "external" symbols with
>> incomplete information - outputting "<symbol> has incomplete
>> information, cast it to it's defined type." - which could be confusing for
> typo: "cast it to its defined type".
>
> I went to check if the original error message contained the same error.
> It doesn't, but not does it match what you quote. I think this is the
> error you are referencing, from typeprint.c:
>
> void
> error_unknown_type (const char *sym_print_name)
> {
> error (_("'%s' has unknown type; cast it to its declared type"),
> sym_print_name);
> }
Fixed.
>> the users. This commit changes the parser rule "variable: name_not_typename"
>> so that, if multiple namespaces are active, we'll look for minimal symbols
>> only in the current namespace.
>>
>> Known limitations:
>> * When using [[N]]::foo::var, if that specific foo version is not on the
>> stack, the error will be unable to include the linker namespace
>> requested. So if a user sees "foo" in the stack this could be
>> confusing, but it should be mitigated when a future patch adds the
>> namespace ID to the backtrace where applicable.
>> * Completion is not supported. That's because the function used to
>> complete symbols expects only text in the form "file.c:symbol", so
>> can't handle the double colon. This isn't unique to linker
>> namespaces, though, since func::var will also not complete, it is just
>> a quirk of how :: completion work at this point.
>> * The expression that parses [[N]] only takes an integer. That's
>> because there aren't many expressions that would make sense in there,
>> and the work of accepting an arbitrary expression felt too much for
>> little gain.
>>
>> Reviewed-By: Eli Zaretskii <eliz@gnu.org>
>> ---
>> gdb/NEWS | 6 +
>> gdb/c-exp.y | 72 ++++++++---
>> gdb/doc/gdb.texinfo | 6 +
>> gdb/minsyms.c | 124 ++++++++++++-------
>> gdb/minsyms.h | 8 ++
>> gdb/parser-defs.h | 7 ++
>> gdb/symtab.c | 37 ++++++
>> gdb/symtab.h | 8 ++
>> gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c | 14 +++
>> gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c | 3 +
>> gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 53 ++++++++
>> 11 files changed, 274 insertions(+), 64 deletions(-)
>>
>> diff --git a/gdb/NEWS b/gdb/NEWS
>> index 097d8da350b..273bd400f1b 100644
>> --- a/gdb/NEWS
>> +++ b/gdb/NEWS
>> @@ -227,6 +227,12 @@ info threads [-gid] [-stopped] [-running] [ID]...
>> These new flags can be useful to get a reduced list when there is a
>> large number of threads.
>>
>> +print
>> + The print command now accepts the following syntax to print values
>> + from a specific linker namespace: `[[N]]::foo'. N is the namespace
>> + identifier as understood by GDB.
>> +
>> +
> Double blank line.
fixed
>
>> * GDB-internal Thread Local Storage (TLS) support
>>
>> ** Linux targets for the x86_64, aarch64, ppc64, s390x, and riscv
>> diff --git a/gdb/c-exp.y b/gdb/c-exp.y
>> index 9f1cb1b2e2a..cb70bf3c863 100644
>> --- a/gdb/c-exp.y
>> +++ b/gdb/c-exp.y
>> @@ -173,7 +173,7 @@ using namespace expr;
>> struct ttype tsym;
>> struct symtoken ssym;
>> int voidval;
>> - const struct block *bval;
>> + struct bval_type bval;
>> enum exp_opcode opcode;
>>
>> struct stoken_vector svec;
>> @@ -261,6 +261,7 @@ static void c_print_token (FILE *file, int type, YYSTYPE value);
>> %token TYPEOF
>> %token DECLTYPE
>> %token TYPEID
>> +%token DOUBLESQUAREOPEN DOUBLESQUARECLOSE
>>
>> /* Special type cases, put in to allow the parser to distinguish different
>> legal basetypes. */
>> @@ -1056,30 +1057,42 @@ exp : FALSEKEYWORD
>>
>> block : BLOCKNAME
>> {
>> - if ($1.sym.symbol)
>> - $$ = $1.sym.symbol->value_block ();
>> - else
>> + if ($1.sym.symbol == nullptr)
>> error (_("No file or function \"%s\"."),
>> copy_name ($1.stoken).c_str ());
>> + $$.search_namespace = false;
>> + $$.b_val = $1.sym.symbol->value_block ();
>> }
>> | FILENAME
>> {
>> $$ = $1;
>> }
>> + | DOUBLESQUAREOPEN INT DOUBLESQUARECLOSE
>> + {
>> + $$.search_namespace = true;
>> + $$.namespace_val = $2.val;
> Totally trivial issue, but the indentation here is different to at least
> everything in this 'block' rule, you use TABS + 4 whitespace, while
> everything else uses TABS + 2 whitespace. Would be nice to be
> consistent.
fixed
>
>> + }
>> ;
>>
>> block : block COLONCOLON name
>> {
>> std::string copy = copy_name ($3);
>> - struct symbol *tem
>> - = lookup_symbol (copy.c_str (), $1,
>> - SEARCH_FUNCTION_DOMAIN,
>> - nullptr).symbol;
>> + struct block_symbol tem;
>>
>> - if (tem == nullptr)
>> + if ($1.search_namespace)
>> + tem = lookup_symbol_in_linker_namespace
>> + (copy.c_str (), $1.namespace_val, SEARCH_FUNCTION_DOMAIN);
> lookup_symbol_in_linker_namespace takes an 'int' for the namespace-id,
> but namespace_val is LONGEST. I suspect namespace_val needs to be
> LONGEST as it gets it value from an INT token, whose value is a LONGEST.
>
> But we should really have a check prior to the
> lookup_symbol_in_linker_namespace call that we're not narrowing the
> value in a meaningful way.
>
> Or just change the namespace-id argument to LONGEST throughout maybe?
>
> Either will work.
I changed the argument to be LONGEST instead, I don't have a good reason
to keep it as an int anyway.
>
>
>> + else
>> + tem = lookup_symbol (copy.c_str (), $1.b_val,
>> + SEARCH_FUNCTION_DOMAIN,
>> + nullptr);
>> +
>> + if (tem.symbol == nullptr)
>> error (_("No function \"%s\" in specified context."),
>> copy.c_str ());
>> - $$ = tem->value_block (); }
>> + $$.b_val = tem.symbol->value_block ();
>> + $$.search_namespace = false;
>> + }
>> ;
>>
>> variable: name_not_typename ENTRY
>> @@ -1098,9 +1111,15 @@ variable: name_not_typename ENTRY
>> variable: block COLONCOLON name
>> {
>> std::string copy = copy_name ($3);
>> - struct block_symbol sym
>> - = lookup_symbol (copy.c_str (), $1,
>> - SEARCH_VFT, NULL);
>> + struct block_symbol sym;
>> +
>> + if ($1.search_namespace)
>> + sym = lookup_symbol_in_linker_namespace
>> + (copy.c_str (), $1.namespace_val,
>> + SEARCH_VFT);
>> + else
>> + sym = lookup_symbol (copy.c_str (), $1.b_val,
>> + SEARCH_VFT, NULL);
>>
>> if (sym.symbol == 0)
>> error (_("No symbol \"%s\" in specified context."),
>> @@ -1196,13 +1215,25 @@ variable: name_not_typename
>> {
>> std::string arg = copy_name ($1.stoken);
>>
>> - bound_minimal_symbol msymbol
>> - = lookup_minimal_symbol (current_program_space, arg.c_str ());
>> + int active_linker_nss
>> + = solib_linker_namespace_count
>> + (current_program_space);
>> + bound_minimal_symbol msymbol;
>> +
>> + if (active_linker_nss > 1)
>> + msymbol = lookup_minimal_symbol_in_linker_namespace
>> + (current_program_space, arg.c_str ());
>> + else
>> + msymbol = lookup_minimal_symbol
>> + (current_program_space, arg.c_str ());
>> if (msymbol.minsym == NULL)
>> {
>> if (!have_full_symbols (current_program_space)
>> && !have_partial_symbols (current_program_space))
>> error (_("No symbol table is loaded. Use the \"file\" command."));
>> + else if (active_linker_nss > 1)
>> + error (_("No symbol \"%s\" in the current linker namespace."),
>> + arg.c_str ());
>> else
>> error (_("No symbol \"%s\" in current context."),
>> arg.c_str ());
>> @@ -2540,7 +2571,9 @@ static const struct c_token tokentab2[] =
>> {"!=", NOTEQUAL, OP_NULL, 0},
>> {"<=", LEQ, OP_NULL, 0},
>> {">=", GEQ, OP_NULL, 0},
>> - {".*", DOT_STAR, OP_NULL, FLAG_CXX}
>> + {".*", DOT_STAR, OP_NULL, FLAG_CXX},
>> + {"[[", DOUBLESQUAREOPEN, OP_NULL, 0},
>> + {"]]", DOUBLESQUARECLOSE, OP_NULL, 0},
>> };
>>
>> /* Identifier-like tokens. Only type-specifiers than can appear in
>> @@ -3143,8 +3176,9 @@ classify_name (struct parser_state *par_state, const struct block *block,
>> if (auto symtab = lookup_symtab (current_program_space, copy.c_str ());
>> symtab != nullptr)
>> {
>> - yylval.bval
>> + yylval.bval.b_val
>> = symtab->compunit ()->blockvector ()->static_block ();
>> + yylval.bval.search_namespace = false;
>>
>> return FILENAME;
>> }
>> @@ -3394,7 +3428,7 @@ yylex (void)
>> name_obstack.clear ();
>> checkpoint = 0;
>> if (current.token == FILENAME)
>> - search_block = current.value.bval;
>> + search_block = current.value.bval.b_val;
>> else if (current.token == COLONCOLON)
>> search_block = NULL;
>> else
>> @@ -3577,7 +3611,7 @@ c_print_token (FILE *file, int type, YYSTYPE value)
>> break;
>>
>> case FILENAME:
>> - parser_fprintf (file, "bval<%s>", host_address_to_string (value.bval));
>> + parser_fprintf (file, "bval<%s>", host_address_to_string (value.bval.b_val));
>> break;
>> }
>> }
>> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
>> index 821f3ed4b05..b48f70d2250 100644
>> --- a/gdb/doc/gdb.texinfo
>> +++ b/gdb/doc/gdb.texinfo
>> @@ -10686,6 +10686,12 @@ you can choose a different format by specifying @samp{/@var{f}}, where
>> @var{f} is a letter specifying the format; see @ref{Output Formats,,Output
>> Formats}.
>>
>> +Additionally, if the inferior supports linker namespaces, @value{GDBN}
>> +has implemented the following syntax to allow users to resolve symbols
>> +to a specific namespace: @code{[[@var{n}]]::@var{symbol}}. Here @var{n}
>> +is @value{GDBN}'s namespace identifier, which may be different from the
>> +inferior's identifier.
> Instead of @code{...} I think a better choice would be @samp{...} here.
> My understanding is that @code would be for actual programming language
> code.
Fixed.
>> +
>> @anchor{print options}
>> The @code{print} command supports a number of options that allow
>> overriding relevant global print settings as set by @code{set print}
>> diff --git a/gdb/minsyms.c b/gdb/minsyms.c
>> index 7e4f47b8c3f..a73d4f21858 100644
>> --- a/gdb/minsyms.c
>> +++ b/gdb/minsyms.c
>> @@ -335,7 +335,10 @@ lookup_minimal_symbol_demangled (const lookup_name_info &lookup_name,
>> }
>> }
>>
>> -/* Look through all the current minimal symbol tables and find the
>> +/* Main implementation for the lookup_minimal_symbol function.
>> + Receives a list of objfiles in which to look for the symbol.
>> +
>> + Look through all the current minimal symbol tables and find the
>> first minimal symbol that matches NAME. If OBJF is non-NULL, limit
>> the search to that objfile. If SFILE is non-NULL, the only file-scope
>> symbols considered will be from that source file (global symbols are
>> @@ -355,9 +358,9 @@ lookup_minimal_symbol_demangled (const lookup_name_info &lookup_name,
>> Obviously, there must be distinct mangled names for each of these,
>> but the demangled names are all the same: S::S or S::~S. */
>>
>> -bound_minimal_symbol
>> -lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf,
>> - const char *sfile)
>> +static bound_minimal_symbol
>> +lookup_minimal_symbol_in_objfiles (std::vector<objfile *> objfile_list,
>> + const char *name, const char *sfile)
>> {
>> found_minimal_symbols found;
>>
>> @@ -373,53 +376,48 @@ lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf,
>>
>> lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
>>
>> - for (objfile &objfile : pspace->objfiles ())
>> + for (objfile *objfile : objfile_list)
>> {
>> if (found.external_symbol.minsym != NULL)
>> break;
>>
>> - if (objf == NULL || objf == &objfile
>> - || objf == objfile.separate_debug_objfile_backlink)
>> + symbol_lookup_debug_printf ("lookup_minimal_symbol (%s, %s, %s)",
>> + name, sfile != NULL ? sfile : "NULL",
>> + objfile_debug_name (objfile));
>> +
>> + /* Do two passes: the first over the ordinary hash table,
>> + and the second over the demangled hash table. */
>> + lookup_minimal_symbol_mangled (name, sfile, objfile,
>> + objfile->per_bfd->msymbol_hash,
>> + mangled_hash, mangled_cmp, found);
>> +
>> + /* If not found, try the demangled hash table. */
>> + if (found.external_symbol.minsym == NULL)
>> {
>> - symbol_lookup_debug_printf ("lookup_minimal_symbol (%s, %s, %s, %s)",
>> - host_address_to_string (pspace),
>> - name, sfile != NULL ? sfile : "NULL",
>> - objfile_debug_name (&objfile));
>> -
>> - /* Do two passes: the first over the ordinary hash table,
>> - and the second over the demangled hash table. */
>> - lookup_minimal_symbol_mangled (name, sfile, &objfile,
>> - objfile.per_bfd->msymbol_hash,
>> - mangled_hash, mangled_cmp, found);
>> -
>> - /* If not found, try the demangled hash table. */
>> - if (found.external_symbol.minsym == NULL)
>> + /* Once for each language in the demangled hash names
>> + table (usually just zero or one languages). */
>> + for (unsigned iter = 0; iter < nr_languages; ++iter)
>> {
>> - /* Once for each language in the demangled hash names
>> - table (usually just zero or one languages). */
>> - for (unsigned iter = 0; iter < nr_languages; ++iter)
>> - {
>> - if (!objfile.per_bfd->demangled_hash_languages.test (iter))
>> - continue;
>> - enum language lang = (enum language) iter;
>> -
>> - unsigned int hash
>> - = (lookup_name.search_name_hash (lang)
>> - % MINIMAL_SYMBOL_HASH_SIZE);
>> -
>> - symbol_name_matcher_ftype *match
>> - = language_def (lang)->get_symbol_name_matcher
>> - (lookup_name);
>> - struct minimal_symbol **msymbol_demangled_hash
>> - = objfile.per_bfd->msymbol_demangled_hash;
>> -
>> - lookup_minimal_symbol_demangled (lookup_name, sfile, &objfile,
>> - msymbol_demangled_hash,
>> - hash, match, found);
>> -
>> - if (found.external_symbol.minsym != NULL)
>> - break;
>> - }
>> + if (!objfile->per_bfd->demangled_hash_languages.test (iter))
>> + continue;
>> + enum language lang = (enum language) iter;
>> +
>> + unsigned int hash
>> + = (lookup_name.search_name_hash (lang)
>> + % MINIMAL_SYMBOL_HASH_SIZE);
>> +
>> + symbol_name_matcher_ftype *match
>> + = language_def (lang)->get_symbol_name_matcher
>> + (lookup_name);
>> + struct minimal_symbol **msymbol_demangled_hash
>> + = objfile->per_bfd->msymbol_demangled_hash;
>> +
>> + lookup_minimal_symbol_demangled (lookup_name, sfile, objfile,
>> + msymbol_demangled_hash,
>> + hash, match, found);
>> +
>> + if (found.external_symbol.minsym != NULL)
>> + break;
>> }
>> }
>> }
>> @@ -472,6 +470,42 @@ lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf,
>> return {};
>> }
>>
>> +/* See minsyms.h. */
>> +
>> +bound_minimal_symbol
>> +lookup_minimal_symbol (program_space *pspace, const char *name, objfile *objf,
>> + const char *sfile)
>> +{
>> + std::vector<objfile *> search_objfiles;
>> + if (objf != nullptr)
>> + {
>> + search_objfiles.push_back (objf);
>> + if (objf->separate_debug_objfile_backlink != nullptr)
>> + search_objfiles.push_back (objf->separate_debug_objfile_backlink);
> There's a change in behaviour here. If we imagine that objfile A has a
> separate_debug_objfile of B. The previous code looped over every
> objfile and did:
>
> if (objf == NULL || objf == &objfile
> || objf == objfile.separate_debug_objfile_backlink)
> // Include this objfile.
>
> If OBJF was 'A' then we would include both 'A' and 'B' as B's backlink
> points at 'A'.
>
> However, the new code does:
>
> search_objfiles.push_back (objf);
> if (objf->separate_debug_objfile_backlink != nullptr)
> search_objfiles.push_back (objf->separate_debug_objfile_backlink);
>
> So if we pass 'A' then we include 'A', but A's backlink will be NULL, so
> we'll not search 'B'.
>
> Due to this flipping of the logic, then if we pass 'B' then under the
> old scheme we'd only include 'B', but under the new scheme we include
> both 'A' and 'B'.
>
> This change of behaviour wasn't called out in the commit message, so I'm
> assuming this might be a mistake.
So, the thinking here might be incorrect, but the idea was: My
understanding was that this function is mostly called when GDB is
iterating over many objfiles, and most likely we'll call this with both
A and B anyway, so it wouldn't make much of a difference, and then this
change make the code more readable in my opinion. So while there is a
behavior change in the function itself, I didn't think there would be an
actual change in the macro scale.
If my understanding is mistaken, please let me know and I'll revert to
the previous behavior.
>
>> + }
>> + else
>> + {
>> + for (objfile &objfile : pspace->objfiles ())
>> + search_objfiles.push_back (&objfile);
>> + }
>> +
>> + return lookup_minimal_symbol_in_objfiles (search_objfiles, name, sfile);
>> +}
>> +
>> +/* See minsyms.h. */
>> +
>> +bound_minimal_symbol
>> +lookup_minimal_symbol_in_linker_namespace (program_space *pspace,
>> + const char *name)
>> +{
>> + LONGEST curr_namespace;
>> + get_internalvar_integer (lookup_internalvar ("_linker_namespace"),
>> + &curr_namespace);
> Rather than reading the internal variable, would it not be better to
> have a helper function in solib.{c,h} which returns the current
> namespace-id, then have the internal variable and this code just call
> that?
I didn't think it was too much worse, but now that you mention it, it
would be much more readable for future maintainers, I'll do that, but in
a separate commit so it's easier to bisect stuff :)
>
>> + return lookup_minimal_symbol_in_objfiles
>> + (get_objfiles_in_linker_namespace (curr_namespace, pspace),
>> + name, nullptr);
>> +}
>> +
>> /* See gdbsupport/symbol.h. */
>>
>> int
>> diff --git a/gdb/minsyms.h b/gdb/minsyms.h
>> index 4aa8a428470..f2ba15d9318 100644
>> --- a/gdb/minsyms.h
>> +++ b/gdb/minsyms.h
>> @@ -211,6 +211,14 @@ bound_minimal_symbol lookup_minimal_symbol (program_space *pspace,
>> objfile *obj = nullptr,
>> const char *sfile = nullptr);
>>
>> +/* Same as above, but only look for a minimal symbol in the objfiles that
>> + belong to the current linker namespace. This function is only meant to
>> + be called when attempting to resolve a symbol from a user command, and
>> + there are multiple linker namespaces available to resolve it in. */
>> +
>> +bound_minimal_symbol lookup_minimal_symbol_in_linker_namespace
>> + (program_space *pspace, const char *name);
>> +
>> /* Look through all the minimal symbol tables in PSPACE and find the
>> first minimal symbol that matches NAME and has text type. If OBJF
>> is non-NULL, limit the search to that objfile. Returns a bound
>> diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
>> index f5618f3a9ce..ff4ab6a09de 100644
>> --- a/gdb/parser-defs.h
>> +++ b/gdb/parser-defs.h
>> @@ -358,6 +358,13 @@ struct ttype
>> struct type *type;
>> };
>>
>> +struct bval_type
>> + {
>> + bool search_namespace;
>> + const struct block *b_val;
>> + LONGEST namespace_val;
>> + };
> I know there are plenty of (older) structures in here that are missing
> comments, but there are also some, e.g. stoken, typed_stoken, that do
> have comments. I think it would be better if new code did comment the
> structures that are added.
Added comments to the structure and fields.
>
>> +
>> struct symtoken
>> {
>> struct stoken stoken;
>> diff --git a/gdb/symtab.c b/gdb/symtab.c
>> index 786dd9f56ba..d237a5cc5d2 100644
>> --- a/gdb/symtab.c
>> +++ b/gdb/symtab.c
>> @@ -2558,6 +2558,43 @@ lookup_static_symbol (const char *name, const domain_search_flags domain)
>>
>> /* See symtab.h. */
>>
>> +struct block_symbol
>> +lookup_symbol_in_linker_namespace (const char *name, int nsid,
>> + const domain_search_flags domain)
>> +{
>> + if (!current_program_space->solib_ops ()->supports_namespaces ())
>> + error (_("Linker namespaces are not supported by the inferior."));
>> +
>> + std::vector<objfile *> objfiles_in_namespace
>> + = get_objfiles_in_linker_namespace (nsid, current_program_space);
>> +
>> + if (objfiles_in_namespace.size() == 0)
> Missing space before '()'.
Fixed.
>
>> + error (_("Namespace [[%d]] is inactive"), nsid);
>> +
>> + symbol_lookup_debug_printf ("lookup_symbol_in_linker_namespace (%d, %s, %s)",
>> + nsid, name, domain_name (domain).c_str ());
>> +
>> + /* We look for both global and static symbols in here. There is no reason
>> + to pick one over the other to my knowledge, so we go alphabetical. */
> I find the whole alphabetical thing a bit weird. I'd just say:
>
> /* We look for both global and static symbols in here, the order is
> arbitrary. */
>
> But if you prefer your wording then that's fine too I guess.
Changed to use your wording.
>> + for (objfile *objf : objfiles_in_namespace)
>> + {
>> + struct block_symbol bsym
>> + = lookup_global_symbol_from_objfile (objf, GLOBAL_BLOCK,
>> + name, domain);
>> + if (bsym.symbol != nullptr)
>> + return bsym;
>> +
>> + bsym = lookup_global_symbol_from_objfile (objf, STATIC_BLOCK,
>> + name, domain);
>> + if (bsym.symbol != nullptr)
>> + return bsym;
>> + }
> When looking at this function, I started looking in c-exp.y, and in here
> we see that the two paths are lookup_symbol_in_linker_namespace or
> lookup_symbol, so when I reviewed this function I was comparing against
> lookup_symbol.
>
> lookup_symbol calls lookup_symbol_in_language, which uses
> demangle_for_lookup to demangle and canonicalize the string being
> searched for. But lookup_symbol_in_linker_namespace doesn't call this
> function. Isn't that going to be a problem?
Probably would be a problem, if the user used a mangled name. I'll add a
call to it, it wasn't omitted on purpose.
> After demangle_for_lookup lookup_symbol_in_language calls
> lookup_symbol_aux to do the actual lookup. This function does a bunch
> of local symbol lookup, which we probably don't need for the namespace
> searching path, but then does:
>
> /* Now do whatever is appropriate for LANGUAGE to look
> up static and global variables. */
>
> result = langdef->lookup_symbol_nonlocal (name, block, domain);
>
> to lookup the global/static symbols, this does a bunch of language
> specific stuff, especially for e.g. C++. Yet
> lookup_symbol_in_linker_namespace doesn't call this, it just goes direct
> to the global/static block and looks for an exact match.
>
> Are there issues here? Or is there something that I'm missing. If this
> is a limitation then maybe this should be documented somewhere?
I thought that the language-specific stuff was to look for built-in
types and other kinds of things that wouldn't be necessary if we are
looking at something that is specific to a namespace.
I don't know if this will cause a problem or not, I can add it if I'm
mistaken in what the langdef search does, just let me know.
>
>> +
>> + return {};
>> +}
>> +
>> +/* See symtab.h. */
>> +
>> struct block_symbol
>> lookup_global_symbol (const char *name,
>> const struct block *block,
>> diff --git a/gdb/symtab.h b/gdb/symtab.h
>> index e47033efd01..fe2304acb4f 100644
>> --- a/gdb/symtab.h
>> +++ b/gdb/symtab.h
>> @@ -2737,6 +2737,14 @@ extern struct block_symbol
>> const char *name,
>> const domain_search_flags domain);
>>
>> +/* Lookup symbol NAME from DOMAIN in the linker namespace NSID.
>> + This generates a list of all objfiles in NSID, then searches
>> + those objfiles for the given symbol. Searches for both global or
>> + static symbols. */
>> +extern struct block_symbol
>> + lookup_symbol_in_linker_namespace (const char *name, int nsid,
>> + const domain_search_flags domain);
>> +
>> extern unsigned int symtab_create_debug;
>>
>> /* Print a "symtab-create" debug statement. */
>> diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c
>> index 86cbb0f4e38..cc35ce0080e 100644
>> --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c
>> +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c
>> @@ -26,3 +26,17 @@ inc (int n)
>> int amount = gdb_dlmopen_glob;
>> return n + amount; /* bp.inc. */
>> }
>> +
>> +static int
>> +change_global (int n)
>> +{
>> + gdb_dlmopen_glob += n;
>> + return n;
>> +}
>> +
>> +__attribute__((visibility ("default")))
>> +int
>> +func_with_other_call (int n)
>> +{
>> + return change_global (n + 1);
>> +}
>> diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c
>> index c7c038a08d1..459ae547842 100644
>> --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c
>> +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c
>> @@ -47,6 +47,9 @@ main (void)
>> fun (dl);
>> }
>>
>> + fun = dlsym (handle[0], "func_with_other_call");
>> + fun (0);
>> +
>> dlclose (handle[0]); /* TAG: first dlclose */
>> dlclose (handle[1]); /* TAG: second dlclose */
>> dlclose (handle[2]); /* TAG: third dlclose */
>> diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
>> index f3bdfb054d9..fec7adb5317 100644
>> --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
>> +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
>> @@ -123,6 +123,10 @@ proc get_first_so_ns {} {
>> return $ns
>> }
>>
>> +proc ns_id_for_command {ns} {
>> + return "\[\[$ns\]\]"
>> +}
>> +
>> # Run the tests relating to the command "info sharedlibrary", to
>> # verify that the namespace ID is consistent.
>> proc test_info_shared {} {
>> @@ -315,6 +319,55 @@ proc test_info_linker_namespaces {} {
>> ".*" ] "print namespaces with no argument"
>> }
>>
>> +# Test that we can use the [[N]]::symbol syntax, and it's variations
>> +# like [[N]]::func::symbol.
> typo: "and its variations like..."
Fixed.
--
Cheers,
Guinevere Larsen
It/she
> Thanks,
> Andrew
>
>> +proc_with_prefix test_print_namespace_symbol {} {
>> + clean_restart
>> + gdb_load $::binfile
>> +
>> + set ns1 [ns_id_for_command 1]
>> + set ns2 [ns_id_for_command 2]
>> +
>> + if { ![runto_main] } {
>> + return
>> + }
>> +
>> + gdb_breakpoint [gdb_get_line_number "TAG: first dlclose"]
>> + gdb_breakpoint "change_global" allow-pending
>> +
>> + # Test printing variables for non-existent namespace.
>> + gdb_test "print ${ns1}::gdb_dlmopen_glob" "Namespace ..1.. is inactive" \
>> + "Before loading namespaces"
>> +
>> + gdb_continue_to_breakpoint "change_global"
>> +
>> + # Test finding location of variables.
>> + gdb_test "print ${ns1}::gdb_dlmopen_glob" ".* = 0" "before changing"
>> + gdb_test_no_output "set ${ns1}::gdb_dlmopen_glob = 1"
>> + gdb_test "print ${ns1}::gdb_dlmopen_glob" ".* = 1" "after changing"
>> + gdb_test "print ${ns2}::gdb_dlmopen_glob" ".* = 0" "other namespace"
>> +
>> + gdb_test "print gdb_dlmopen_glob" ".* = 1" "changed the right variable"
>> +
>> + # Test finding functions in specific namespaces.
>> + gdb_test "print ${ns1}::inc (2)" ".* = 3"
>> + gdb_test "print ${ns2}::inc (2)" ".* = 2"
>> +
>> + # Test finding a specific block in the backtrace.
>> + gdb_test "print n" ".* = 1"
>> + gdb_test "print ${ns1}::func_with_other_call::n" ".* = 0"
>> + gdb_test "print ${ns2}::func_with_other_call::n" \
>> + "No frame is currently executing in block func_with_other_call."
>> +
>> + # Leave to default namespace.
>> + gdb_continue_to_breakpoint "TAG: first dlclose"
>> + # This global doesn't exist in the default namespace. Rather than
>> + # returning a random one, we just say we didn't find one.
>> + gdb_test "print gdb_dlmopen_glob" \
>> + "No symbol .gdb_dlmopen_glob. in the current linker namespace."
>> +}
>> +
>> test_info_shared
>> test_conv_vars
>> test_info_linker_namespaces
>> +test_print_namespace_symbol
>> --
>> 2.51.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v6 3/3] gdb: extend the [[N]]::foo syntax for files
2026-04-20 15:13 ` Andrew Burgess
@ 2026-04-28 20:20 ` Guinevere Larsen
2026-05-13 17:08 ` Guinevere Larsen
1 sibling, 0 replies; 16+ messages in thread
From: Guinevere Larsen @ 2026-04-28 20:20 UTC (permalink / raw)
To: Andrew Burgess, gdb-patches
On 4/20/26 12:13 PM, Andrew Burgess wrote:
> Guinevere Larsen <guinevere@redhat.com> writes:
>
>> This commit implements the missing support for [[N]]::'file.c'::var
>> syntax that was skipped on the previous commit.
>>
>> This is done by adding a new value to the global parser_state, so that
>> the classify_name function can restrict its search for file names to the
>> specified linker namespace. It had to be done this way because if the
>> logic was contained on the newly added "block: block COLONCOLON
>> FILENAME" rule, we would not have the name to rerun the search.
> Did you consider adding the filename to the <whatever> type such that it
> was available within the rule to allow for the filename to be re-looked
> up?
>
> I'd be interested to know if this was tried, why this was worse than
> pushing parser state back to the lexer, which I always thought was not a
> great design.
I can't remember having tried it, so I'll explore this option and report
back.
>> Because
>> of that, the new rule only exists to make sure this is only used in the
>> intended syntax. This commit also adds a link to the solib_ops relevant
>> to the expression being parsed, as a way to identify if linker
>> namespaces are supported; this could be achieved by guarding the search
>> functions instead, but I think that this is more reliable.
>>
>> The new rule uses "block" rather than a linker namespace specific token,
>> because if we allowed that token to also reduce into block, the new rule
>> would never be triggered as the simple reduction would be preferred. If
>> we didn't allow the linker namespace to reduce into block, the rest of
>> the syntaxes for [[N]]::foo would be more involved, so the option in
>> this commit seemed like the simplest solution.
>>
>> The rule "block: block COLONCOLON name" also had to be updated because,
>> if a user tried to search for a file not present in the linker
>> namespace, GDB would miscategorize it to 'name' instead of 'filename',
>> and if no function of the same name was found, the error would only say
>> "No function \"foo\" (...)" which could confuse a user. The new error
>> says "Nothing named \"foo\" (...)" instead since it is impossible for us
>> to disambiguate between filename or function name, and both would be
>> valid in this code path.
>>
>> The parser_state changes were not used for the previous commit because
>> the lookup_symbol calls would lead to an even more intrusive change for
>> no real gain, since the search would be rerun any way. There is an
>> argument to be made that the results could be different if only
>> namespace had a type and another had a variable, but a situation where
>> that significantly changes the result is quite unlikely, I think.
>> ---
>> gdb/c-exp.y | 18 +++++++++++--
>> gdb/linespec.c | 4 +--
>> gdb/parse.c | 3 ++-
>> gdb/parser-defs.h | 32 +++++++++++++++++++++--
>> gdb/rust-parse.c | 3 ++-
>> gdb/symtab.c | 26 +++++++++++++-----
>> gdb/symtab.h | 7 ++++-
>> gdb/testsuite/gdb.base/dlmopen-ns-ids.exp | 12 +++++++++
>> 8 files changed, 90 insertions(+), 15 deletions(-)
>>
>> diff --git a/gdb/c-exp.y b/gdb/c-exp.y
>> index cb70bf3c863..f59aca327ed 100644
>> --- a/gdb/c-exp.y
>> +++ b/gdb/c-exp.y
>> @@ -1071,6 +1071,7 @@ block : BLOCKNAME
>> {
>> $$.search_namespace = true;
>> $$.namespace_val = $2.val;
>> + pstate->set_linker_namespace ($2.val);
>> }
>> ;
>>
>> @@ -1087,12 +1088,24 @@ block : block COLONCOLON name
>> SEARCH_FUNCTION_DOMAIN,
>> nullptr);
>>
>> - if (tem.symbol == nullptr)
>> + if (tem.symbol == nullptr && !$$.search_namespace)
>> error (_("No function \"%s\" in specified context."),
>> copy.c_str ());
>> + else if (tem.symbol == nullptr && $$.search_namespace)
> My yacc foo is weak, but isn't '$$' the rule's output? Which is only
> being set below. Shouldn't this be $1 maybe? If there's not some
> reason why search_namespace is being set to the correct value (that I'm
> missing) then this would seem to indicate that there's a gap in the
> testing here.
You're right, this must ave slipped past me at some point, thanks!
>
>> + /* COPY can be a function or a file. There is no way
>> + to identify which the user intended, so emit a
>> + generic warning instead. */
>> + error (_("Nothing named \"%s\" in specified context."),
>> + copy.c_str ());
>> $$.b_val = tem.symbol->value_block ();
>> $$.search_namespace = false;
>> }
>> + | block COLONCOLON FILENAME
>> + {
>> + if (!$1.search_namespace)
>> + error (_("Filename must be the first part of the expression"));
>> + $$ = $3;
>> + }
>> ;
>>
>> variable: name_not_typename ENTRY
>> @@ -3173,7 +3186,8 @@ classify_name (struct parser_state *par_state, const struct block *block,
>> || is_quoted_name)
>> {
>> /* See if it's a file name. */
>> - if (auto symtab = lookup_symtab (current_program_space, copy.c_str ());
>> + if (auto symtab = lookup_symtab (current_program_space, copy.c_str (),
>> + par_state->get_linker_namespace ());
>> symtab != nullptr)
>> {
>> yylval.bval.b_val
>> diff --git a/gdb/linespec.c b/gdb/linespec.c
>> index 08f7fdd0daa..ec90ad4826a 100644
>> --- a/gdb/linespec.c
>> +++ b/gdb/linespec.c
>> @@ -3633,11 +3633,11 @@ collect_symtabs_from_filename (const char *file,
>> if (pspace->executing_startup)
>> continue;
>>
>> - iterate_over_symtabs (pspace, file, collector);
>> + iterate_over_symtabs (pspace, file, -1, collector);
>> }
>> }
>> else
>> - iterate_over_symtabs (search_pspace, file, collector);
>> + iterate_over_symtabs (search_pspace, file, -1, collector);
>>
>> /* It is tempting to use the unordered_dense 'extract' method here,
>> and remove the separate vector -- but it's unclear if ordering
>> diff --git a/gdb/parse.c b/gdb/parse.c
>> index d76768f41d7..7358c369d52 100644
>> --- a/gdb/parse.c
>> +++ b/gdb/parse.c
>> @@ -420,7 +420,8 @@ parse_exp_in_context (const char **stringptr, CORE_ADDR pc,
>>
>> parser_state ps (lang, get_current_arch (), expression_context_block,
>> expression_context_pc, flags, *stringptr,
>> - completer != nullptr, tracker);
>> + completer != nullptr, tracker,
>> + current_program_space->solib_ops ());
>>
>> scoped_restore_current_language lang_saver (lang->la_language);
>>
>> diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
>> index ff4ab6a09de..c0be1083f66 100644
>> --- a/gdb/parser-defs.h
>> +++ b/gdb/parser-defs.h
>> @@ -26,6 +26,7 @@
>> #include "expression.h"
>> #include "symtab.h"
>> #include "expop.h"
>> +#include "solib.h"
>>
>> struct block;
>> struct language_defn;
>> @@ -147,7 +148,8 @@ struct parser_state : public expr_builder
>> parser_flags flags,
>> const char *input,
>> bool completion,
>> - innermost_block_tracker *tracker)
>> + innermost_block_tracker *tracker,
>> + const solib_ops *ops)
>> : expr_builder (lang, gdbarch),
>> expression_context_block (context_block),
>> expression_context_pc (context_pc),
>> @@ -157,7 +159,8 @@ struct parser_state : public expr_builder
>> comma_terminates ((flags & PARSER_COMMA_TERMINATES) != 0),
>> parse_completion (completion),
>> void_context_p ((flags & PARSER_VOID_CONTEXT) != 0),
>> - debug ((flags & PARSER_DEBUG) != 0)
>> + debug ((flags & PARSER_DEBUG) != 0),
>> + m_solib_ops (ops)
>> {
>> }
>>
>> @@ -263,6 +266,21 @@ struct parser_state : public expr_builder
>> push (expr::make_operation<T> (std::move (lhs), std::move (rhs)));
>> }
>>
>> + void set_linker_namespace (LONGEST ns_id)
>> + {
>> + if (m_solib_ops == nullptr)
>> + error (_("Linker namespaces require an active inferior"));
>> + if (m_solib_ops->supports_namespaces ())
>> + linker_namespace = ns_id;
>> + else
>> + error (_("Linker namespaces are not supported"));
>> + }
>> +
>> + LONGEST get_linker_namespace ()
> This can be const.
Fixed, just in case I still need to use the parser state in the lexer.
>
>> + {
>> + return linker_namespace;
>> + }
>> +
>> /* Function called from the various parsers' yyerror functions to throw
>> an error. The error will include a message identifying the location
>> of the error within the current expression. */
>> @@ -323,6 +341,16 @@ struct parser_state : public expr_builder
>>
>> /* Stack of operations. */
>> std::vector<expr::operation_up> m_operations;
>> +
>> + /* If the expression is being restricted to a specific namespace, this is
>> + where that information is stored for the block lookup. It should be
>> + accessed through setter/getters to ensure that the linker namespace is
>> + only set when the gdbarch supports it. */
>> + LONGEST linker_namespace = -1;
> This should be renamed m_linker_namespace as it is private.
>
> Also, I couldn't find anything that would reset the linker namepsace
> back to -1 when parsing a complex expression. For example, something
> like:
>
> print [[1]]::'foo.c'::var_a + 'bar.c'::var_b
>
> After parsing the [[1]] linker_namespace will be set to '1', but is it
> ever reset? Will we not end up parsing the "'bar.c'::var_b" as if the
> lookup had to be in namespace 1?
You're right, I think I missed it as a possibility.
Hopefully I'll be able to move away from state in the lexer, and that
won't be a concern.
>
> Thanks,
> Andrew
>
>> +
>> + /* Used to figure out if an inferior is capable of handling linker
>> + namespaces at all. */
>> + const solib_ops *m_solib_ops;
>> };
>>
>> /* A string token, either a char-string or bit-string. Char-strings are
>> diff --git a/gdb/rust-parse.c b/gdb/rust-parse.c
>> index b740d5a7b16..27f03b23e6a 100644
>> --- a/gdb/rust-parse.c
>> +++ b/gdb/rust-parse.c
>> @@ -2315,7 +2315,8 @@ rust_lex_tests (void)
>> {
>> /* Set up dummy "parser", so that rust_type works. */
>> parser_state ps (language_def (language_rust), current_inferior ()->arch (),
>> - nullptr, 0, 0, nullptr, 0, nullptr);
>> + nullptr, 0, 0, nullptr, 0, nullptr,
>> + current_program_space->solib_ops ());
>> rust_parser parser (&ps);
>>
>> rust_lex_test_one (&parser, "", 0);
>> diff --git a/gdb/symtab.c b/gdb/symtab.c
>> index d237a5cc5d2..bbaf94e51d0 100644
>> --- a/gdb/symtab.c
>> +++ b/gdb/symtab.c
>> @@ -618,6 +618,7 @@ compare_filenames_for_search (const char *filename, const char *search_name)
>>
>> void
>> iterate_over_symtabs (program_space *pspace, const char *name,
>> + LONGEST linker_ns,
>> gdb::function_view<bool (symtab *)> callback)
>> {
>> gdb::unique_xmalloc_ptr<char> real_path;
>> @@ -630,20 +631,33 @@ iterate_over_symtabs (program_space *pspace, const char *name,
>> gdb_assert (IS_ABSOLUTE_PATH (real_path.get ()));
>> }
>>
>> - for (objfile &objfile : pspace->objfiles ())
>> - if (objfile.map_symtabs_matching_filename (name, real_path.get (),
>> - callback))
>> + std::vector<objfile *> objfiles_to_search;
>> + if (linker_ns >= 0)
>> + {
>> + gdb_assert (pspace->solib_ops ()->supports_namespaces ());
>> + objfiles_to_search
>> + = get_objfiles_in_linker_namespace (linker_ns, pspace);
>> + }
>> + else
>> + {
>> + for (objfile &objf : pspace->objfiles ())
>> + objfiles_to_search.push_back (&objf);
>> + }
>> +
>> + for (objfile *objfile : objfiles_to_search)
>> + if (objfile->map_symtabs_matching_filename (name, real_path.get (),
>> + callback))
>> return;
>> }
>>
>> /* See symtab.h. */
>>
>> symtab *
>> -lookup_symtab (program_space *pspace, const char *name)
>> +lookup_symtab (program_space *pspace, const char *name, LONGEST linker_ns)
>> {
>> struct symtab *result = NULL;
>>
>> - iterate_over_symtabs (pspace, name, [&] (symtab *symtab)
>> + iterate_over_symtabs (pspace, name, linker_ns, [&] (symtab *symtab)
>> {
>> result = symtab;
>> return true;
>> @@ -6158,7 +6172,7 @@ collect_file_symbol_completion_matches (completion_tracker &tracker,
>>
>> /* Go through symtabs for SRCFILE and check the externs and statics
>> for symbols which match. */
>> - iterate_over_symtabs (current_program_space, srcfile, [&] (symtab *s)
>> + iterate_over_symtabs (current_program_space, srcfile, -1, [&] (symtab *s)
>> {
>> add_symtab_completions (s->compunit (),
>> tracker, mode, lookup_name,
>> diff --git a/gdb/symtab.h b/gdb/symtab.h
>> index fe2304acb4f..bda6e82da02 100644
>> --- a/gdb/symtab.h
>> +++ b/gdb/symtab.h
>> @@ -2079,7 +2079,8 @@ const char *multiple_symbols_select_mode (void);
>>
>> /* Lookup a symbol table in PSPACE by source file name. */
>>
>> -extern symtab *lookup_symtab (program_space *pspace, const char *name);
>> +extern symtab *lookup_symtab (program_space *pspace, const char *name,
>> + LONGEST linker_ns = -1);
>>
>> /* An object of this type is passed as the 'is_a_field_of_this'
>> argument to lookup_symbol and lookup_symbol_in_language. */
>> @@ -2805,10 +2806,14 @@ bool compare_glob_filenames_for_search (const char *filename,
>> psymtabs. *If* there is no '/' in the name, a match after a '/' in the
>> symtab filename will also work.
>>
>> + If LINKER_NS is 0 or greater, only the objfiles in the provided linker
>> + namespace will be iterated over.
>> +
>> Call CALLBACK with each symtab that is found. If CALLBACK returns
>> true, the search stops. */
>>
>> void iterate_over_symtabs (program_space *pspace, const char *name,
>> + LONGEST linker_ns,
>> gdb::function_view<bool (symtab *)> callback);
>>
>> std::vector<const linetable_entry *> find_linetable_entries_for_symtab_line
>> diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
>> index fec7adb5317..a1e18fc39d3 100644
>> --- a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
>> +++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
>> @@ -325,9 +325,15 @@ proc_with_prefix test_print_namespace_symbol {} {
>> clean_restart
>> gdb_load $::binfile
>>
>> + set ns0 [ns_id_for_command 0]
>> set ns1 [ns_id_for_command 1]
>> set ns2 [ns_id_for_command 2]
>>
>> + # Test printing variables before starting the inferior
>> + gdb_test "print ${ns1}::gdb_dlmopen_glob" \
>> + "Linker namespaces require an active inferior" \
>> + "Before starting inferior"
>> +
>> if { ![runto_main] } {
>> return
>> }
>> @@ -365,6 +371,12 @@ proc_with_prefix test_print_namespace_symbol {} {
>> # returning a random one, we just say we didn't find one.
>> gdb_test "print gdb_dlmopen_glob" \
>> "No symbol .gdb_dlmopen_glob. in the current linker namespace."
>> +
>> + # Minimal testing for finding files in namespaces.
>> + gdb_test "print ${ns1}::'${::srcfile_lib}'::gdb_dlmopen_glob" \
>> + ".* = 2"
>> + gdb_test "print ${ns0}::'${::srcfile_lib}'::gdb_dlmopen_glob" \
>> + "Nothing named .${::srcfile_lib}. in specified context."
>> }
>>
>> test_info_shared
>> --
>> 2.51.0
--
Cheers,
Guinevere Larsen
It/she
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v6 3/3] gdb: extend the [[N]]::foo syntax for files
2026-04-20 15:13 ` Andrew Burgess
2026-04-28 20:20 ` Guinevere Larsen
@ 2026-05-13 17:08 ` Guinevere Larsen
1 sibling, 0 replies; 16+ messages in thread
From: Guinevere Larsen @ 2026-05-13 17:08 UTC (permalink / raw)
To: Andrew Burgess, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1586 bytes --]
On 4/20/26 12:13 PM, Andrew Burgess wrote:
> Guinevere Larsen<guinevere@redhat.com> writes:
>
>> This commit implements the missing support for [[N]]::'file.c'::var
>> syntax that was skipped on the previous commit.
>>
>> This is done by adding a new value to the global parser_state, so that
>> the classify_name function can restrict its search for file names to the
>> specified linker namespace. It had to be done this way because if the
>> logic was contained on the newly added "block: block COLONCOLON
>> FILENAME" rule, we would not have the name to rerun the search.
> Did you consider adding the filename to the <whatever> type such that it
> was available within the rule to allow for the filename to be re-looked
> up?
>
> I'd be interested to know if this was tried, why this was worse than
> pushing parser state back to the lexer, which I always thought was not a
> great design.
My one worry with this is, what if there is a file foo in the default
namespace, and a function 'foo' in namespace 1
Could we misidentify this as being a filename, and then we rerun the
search inside the "block: block COLONCOLON FILENAME" and find nothing,
and raise an error when the expression was valid?
I'm not familiar enough with our parser to know if this is the case, but
if it is and I understand it correctly, I think this is a possible
failure case... Although if you think this is a failure that is too
niche, I can go that route, mark it as such on the code and commit
message, and remove the linker namespace ID from the parser.
--
Cheers,
Guinevere Larsen
It/she
[-- Attachment #2: Type: text/html, Size: 2307 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-05-13 17:10 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-29 12:58 [PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols Guinevere Larsen
2025-10-29 12:58 ` [PATCH v6 1/3] gdb: make lookup_minimal_symbol_linkage work with linker namespaces Guinevere Larsen
2026-01-28 11:22 ` Andrew Burgess
2025-10-29 12:58 ` [PATCH v6 2/3] gdb: Make the parser recognize the [[N]] syntax for variables Guinevere Larsen
2026-04-20 13:59 ` Andrew Burgess
2026-04-28 19:32 ` Guinevere Larsen
2025-10-29 12:58 ` [PATCH v6 3/3] gdb: extend the [[N]]::foo syntax for files Guinevere Larsen
2026-04-20 15:13 ` Andrew Burgess
2026-04-28 20:20 ` Guinevere Larsen
2026-05-13 17:08 ` Guinevere Larsen
2025-11-27 20:30 ` [PING]Re: [PATCH v6 0/3] Introduce syntax for linker-namespace specific symbols Guinevere Larsen
2025-12-12 17:20 ` [PINGv2][PATCH " Guinevere Larsen
2026-01-06 17:17 ` Guinevere Larsen
2026-01-14 14:11 ` Guinevere Larsen
2026-03-05 12:20 ` [PINGv3][PATCH " Guinevere Larsen
2026-03-05 12:21 ` Guinevere Larsen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox