Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Andrew Burgess <aburgess@redhat.com>
To: Guinevere Larsen <guinevere@redhat.com>, gdb-patches@sourceware.org
Cc: Guinevere Larsen <guinevere@redhat.com>
Subject: Re: [PATCH v6 3/3] gdb: extend the [[N]]::foo syntax for files
Date: Mon, 20 Apr 2026 16:13:49 +0100	[thread overview]
Message-ID: <87v7dl3brm.fsf@redhat.com> (raw)
In-Reply-To: <20251029125831.2102647-4-guinevere@redhat.com>

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


  reply	other threads:[~2026-04-20 15:14 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
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 [this message]
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=87v7dl3brm.fsf@redhat.com \
    --to=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.org \
    --cc=guinevere@redhat.com \
    /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