From: Guinevere Larsen <guinevere@redhat.com>
To: Andrew Burgess <aburgess@redhat.com>, gdb-patches@sourceware.org
Cc: Eli Zaretskii <eliz@gnu.org>
Subject: Re: [PATCH v6 2/3] gdb: Make the parser recognize the [[N]] syntax for variables
Date: Tue, 28 Apr 2026 16:32:23 -0300 [thread overview]
Message-ID: <a6cd982b-8a99-4f56-95a0-843923bc6477@redhat.com> (raw)
In-Reply-To: <87y0ih3f85.fsf@redhat.com>
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
next prev parent reply other threads:[~2026-04-28 19:33 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=a6cd982b-8a99-4f56-95a0-843923bc6477@redhat.com \
--to=guinevere@redhat.com \
--cc=aburgess@redhat.com \
--cc=eliz@gnu.org \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox