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 1/3] gdb: make lookup_minimal_symbol_linkage work with linker namespaces
Date: Wed, 28 Jan 2026 11:22:54 +0000	[thread overview]
Message-ID: <87jyx2f0c1.fsf@redhat.com> (raw)
In-Reply-To: <20251029125831.2102647-2-guinevere@redhat.com>

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


  reply	other threads:[~2026-01-28 11:23 UTC|newest]

Thread overview: 11+ 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 [this message]
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 ` [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
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=87jyx2f0c1.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