@@ -421,6 +421,11 @@ 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
@@ -175,7 +175,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;
@@ -263,6 +263,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. */
@@ -1058,31 +1059,43 @@ 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 \"%ps\" in specified context."),
styled_string (function_name_style.style (),
copy.c_str ()));
- $$ = tem->value_block (); }
+ $$.b_val = tem.symbol->value_block ();
+ $$.search_namespace = false;
+ }
;
variable: name_not_typename ENTRY
@@ -1101,9 +1114,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."),
@@ -1199,8 +1218,17 @@ 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 (!current_program_space->has_full_symbols ()
@@ -1208,6 +1236,9 @@ variable: name_not_typename
error (_("No symbol table is loaded. Use the \"%ps\" command."),
styled_string (command_style.style (),
"file"));
+ 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 ());
@@ -2545,7 +2576,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
@@ -3177,8 +3210,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;
}
@@ -3428,7 +3462,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
@@ -3612,7 +3646,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;
}
}
@@ -10775,6 +10775,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: @samp{[[@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}
@@ -324,7 +324,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
@@ -344,9 +347,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;
@@ -362,53 +365,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;
}
}
}
@@ -461,6 +459,40 @@ 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)
+{
+ return lookup_minimal_symbol_in_objfiles
+ (get_objfiles_in_linker_namespace (get_current_linker_namespace (),
+ pspace),
+ name, nullptr);
+}
+
/* See gdbsupport/symbol.h. */
int
@@ -191,6 +191,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
@@ -362,6 +362,19 @@ struct ttype
struct type *type;
};
+/* A struct to hold all the necessary information when finding a block,
+ or finding symbols inside a block. */
+struct bval_type
+ {
+ /* Whether we are explicitly searching a block in a namespace. */
+ bool search_namespace;
+ /* This is where the result of the search will be stored. */
+ const struct block *b_val;
+ /* If this block, or a parent one, were searched for in a specific
+ namespace, this is where the namespace is stored. */
+ LONGEST namespace_val;
+ };
+
struct symtoken
{
struct stoken stoken;
@@ -2588,6 +2588,46 @@ 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, LONGEST 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 [[%s]] is inactive"), plongest (nsid));
+
+ symbol_lookup_debug_printf ("lookup_symbol_in_linker_namespace (%s, %s, %s)",
+ plongest (nsid), name, domain_name (domain).c_str ());
+ demangle_result_storage storage;
+ const char *demangled_name
+ = demangle_for_lookup (name, current_language->la_language, storage);
+
+ /* We look for both global and static symbols in here, the order
+ is arbitrary. */
+ for (objfile *objf : objfiles_in_namespace)
+ {
+ struct block_symbol bsym
+ = lookup_global_symbol_from_objfile (objf, GLOBAL_BLOCK,
+ demangled_name, domain);
+ if (bsym.symbol != nullptr)
+ return bsym;
+
+ bsym = lookup_global_symbol_from_objfile (objf, STATIC_BLOCK,
+ demangled_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,
@@ -2735,6 +2735,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, LONGEST nsid,
+ const domain_search_flags domain);
+
extern unsigned int symtab_create_debug;
/* Print a "symtab-create" debug statement. */
@@ -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);
+}
@@ -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 */
@@ -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 {} {
@@ -311,6 +315,55 @@ proc test_info_linker_namespaces {} {
".*" ] "print namespaces with no argument"
}
+# Test that we can use the [[N]]::symbol syntax, and its 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