public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Aaron Merey <amerey@redhat.com>
To: gdb-patches@sourceware.org
Subject: [PING][RFC PATCH] gdb/debuginfod: Support on-demand downloading of debuginfo
Date: Fri, 21 Oct 2022 12:44:10 -0400	[thread overview]
Message-ID: <CAJDtP-TXM3CBuny--PLMXYWuESUa1W4YuRMZNBPHd4M4QF2yEw@mail.gmail.com> (raw)
In-Reply-To: <20221006022424.399932-1-amerey@redhat.com>

Ping

Thanks,
Aaron

On Wed, Oct 5, 2022 at 10:24 PM Aaron Merey <amerey@redhat.com> wrote:
>
> At the beginning of a session, GDB attempts to download debuginfo for
> every shared library used by the process being debugged.  One disadvantage
> of this is that time may be spent downloading debuginfo that ultimately
> isn't needed during the current session.
>
> This patch helps address the issue by adding support for on-demand
> downloading and reading of debuginfo.  The basic approach it takes is
> to use debuginfod to download just the .gdb_index of a debuginfo file
> as soon as the corresponding library is linked.  GDB then relies on the
> information in the index for as long as possible.  When the index isn't
> enough then debuginfo is downloaded and read. This helps avoid unnecessary
> downloads.
>
> Although this patch specifically uses .gdb_index, other indexes such
> as .debug_names could be supported in much the same way.
>
> Also with this patch, GDB will not build with the latest release of
> debuginfod, hence the RFC. The debuginfod ELF/DWARF section query
> function used in this patch to fetch .gdb_index is still in development
> and will be included in a future release.
>
> This patch implements basic on-demand functionality but more work needs
> to be done to fully take advantage of this feature.  Currently GDB does
> not attempt to download debuginfo when generating backtraces.  In some
> situations backtraces may lack information for libraries that we ought
> to be able to download debuginfo for.  If the user attempts to print a
> non-existant symbol, GDB will start expanding symtabs one-by-one causing
> all debuginfo to be downloaded. Some uses of the 'list' command also trigger
> the downloading of all debuginfo, such as 'list 1' and 'list printf.c:33'.
>
> Now I'll describe the implementation in more detail.
>
> This patch adds a command 'set debuginfod enabled lazy' which enables
> on-demand debuginfo downloading/reading.  If this 'lazy' mode is enabled
> and a solib's debuginfo cannot be found locally, the new function
> dwarf2_has_separate_index is called in elf_symfile_read. This function
> queries debuginfod servers for the .gdb_index matching the build-id
> of the solib.  If it's found, a new objfile is created to hold the .gdb_index
> information.  The new objfile flag OBJF_INDEX_READLATER is used to indicate
> that the objfile contains quick_symbols_functions for an index has deferred
> debuginfo reading.
>
> When GDB tries and fails to perform
> dwarf2_base_index_functions::find_pc_sect_compunit_symtab or
> dwarf2_gdb_index::expand_symtabs_matching, the new function
> read_full_dwarf_from_debuginfod downloads the actual debuginfo file and
> updates the objfile using the new function objfile::reinit. Symtab expansion
> then proceeds as if the debuginfo was present all along.
>
> Any feedback is appreciated.
>
> Aaron
> ---
>  gdb/debuginfod-support.c |  56 +++++++
>  gdb/debuginfod-support.h |  23 +++
>  gdb/dwarf2/index-cache.c |  33 +++++
>  gdb/dwarf2/index-cache.h |  13 ++
>  gdb/dwarf2/public.h      |   2 +
>  gdb/dwarf2/read.c        | 308 ++++++++++++++++++++++++++++++++++++---
>  gdb/dwarf2/section.c     |   4 +-
>  gdb/elfread.c            |   2 +
>  gdb/objfile-flags.h      |   4 +
>  gdb/objfiles.c           |  16 ++
>  gdb/objfiles.h           |   5 +
>  gdb/symfile.c            |  82 +++++++++++
>  gdb/symfile.h            |   3 +
>  gdb/symtab.h             |   2 +
>  14 files changed, 532 insertions(+), 21 deletions(-)
>
> diff --git a/gdb/debuginfod-support.c b/gdb/debuginfod-support.c
> index 5f04a2b38ca..efcdb309522 100644
> --- a/gdb/debuginfod-support.c
> +++ b/gdb/debuginfod-support.c
> @@ -33,12 +33,14 @@ static cmd_list_element *show_debuginfod_prefix_list;
>  static const char debuginfod_on[] = "on";
>  static const char debuginfod_off[] = "off";
>  static const char debuginfod_ask[] = "ask";
> +static const char debuginfod_lazy[] = "lazy";
>
>  static const char *debuginfod_enabled_enum[] =
>  {
>    debuginfod_on,
>    debuginfod_off,
>    debuginfod_ask,
> +  debuginfod_lazy,
>    nullptr
>  };
>
> @@ -79,6 +81,15 @@ debuginfod_exec_query (const unsigned char *build_id,
>    return scoped_fd (-ENOSYS);
>  }
>
> +scoped_fd
> +debuginfod_section_query (const unsigned char *build_id,
> +                         int build_id_len,
> +                         const char *filename,
> +                         const char *section_name,
> +                         gdb::unique_xmalloc_ptr<char> *destname)
> +{
> +  return scoped_fd (-ENOSYS);
> +}
>  #define NO_IMPL _("Support for debuginfod is not compiled into GDB.")
>
>  #else
> @@ -358,6 +369,51 @@ debuginfod_exec_query (const unsigned char *build_id,
>
>    return fd;
>  }
> +
> +/* See debuginfod-support.h  */
> +
> +scoped_fd
> +debuginfod_section_query (const unsigned char *build_id,
> +                         int build_id_len,
> +                         const char *filename,
> +                         const char *section_name,
> +                         gdb::unique_xmalloc_ptr<char> *destname)
> +{
> +  if (debuginfod_enabled != debuginfod_lazy || !debuginfod_is_enabled ())
> +    return scoped_fd (-ENOSYS);
> +
> +  debuginfod_client *c = get_debuginfod_client ();
> +
> +  if (c == nullptr)
> +    return scoped_fd (-ENOMEM);
> +
> +  char *dname = nullptr;
> +  std::string desc = std::string ("section ") + section_name + " for";
> +  user_data data (desc.c_str (), filename);
> +
> +  debuginfod_set_user_data (c, &data);
> +  gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
> +  if (target_supports_terminal_ours ())
> +    {
> +      term_state.emplace ();
> +      target_terminal::ours ();
> +    }
> +
> +  scoped_fd fd (debuginfod_find_section (c, build_id, build_id_len,
> +                                        section_name, true, &dname));
> +  debuginfod_set_user_data (c, nullptr);
> +
> +  if (fd.get () < 0 && fd.get () != -ENOENT)
> +    gdb_printf (_("Download failed: %s. " \
> +                 "Continuing without section %s for %ps.\n"),
> +               safe_strerror (-fd.get ()), section_name,
> +               styled_string (file_name_style.style (),  filename));
> +
> +  if (fd.get () >= 0 && destname != nullptr)
> +    destname->reset (dname);
> +
> +  return fd;
> +}
>  #endif
>
>  /* Set callback for "set debuginfod enabled".  */
> diff --git a/gdb/debuginfod-support.h b/gdb/debuginfod-support.h
> index 5b1c1cb91f4..5294b65cac4 100644
> --- a/gdb/debuginfod-support.h
> +++ b/gdb/debuginfod-support.h
> @@ -78,4 +78,27 @@ extern scoped_fd debuginfod_exec_query (const unsigned char *build_id,
>                                         const char *filename,
>                                         gdb::unique_xmalloc_ptr<char>
>                                           *destname);
> +
> +/* Query debuginfod servers for the binary contents of a ELF/DWARF section
> +   from a file matching BUILD_ID.  BUILD_ID can be given as a binary blob
> +   or a null-terminated string.  If given as a binary blob, BUILD_ID_LEN
> +   should be the number of bytes.  If given as a null-terminated string,
> +   BUILD_ID_LEN should be 0.
> +
> +   FILENAME should be the name or path associated with the file matching
> +   BUILD_ID.  It is used for printing messages to the user.
> +
> +   SECTION_NAME should be the name of an ELF/DWARF section beginning
> +   with '.'.
> +
> +   If the file is successfully retrieved, its path on the local machine
> +   is stored in DESTNAME.  If GDB is not built with debuginfod, this
> +   function returns -ENOSYS.  */
> +
> +extern scoped_fd debuginfod_section_query (const unsigned char *build_id,
> +                                          int build_id_len,
> +                                          const char *filename,
> +                                          const char *section_name,
> +                                          gdb::unique_xmalloc_ptr<char>
> +                                            *destname);
>  #endif /* DEBUGINFOD_SUPPORT_H */
> diff --git a/gdb/dwarf2/index-cache.c b/gdb/dwarf2/index-cache.c
> index 6de58592050..cc170e8abfe 100644
> --- a/gdb/dwarf2/index-cache.c
> +++ b/gdb/dwarf2/index-cache.c
> @@ -222,6 +222,33 @@ index_cache::lookup_gdb_index (const bfd_build_id *build_id,
>    return {};
>  }
>
> +/* See dwarf-index-cache.h.  */
> +
> +gdb::array_view<const gdb_byte>
> +index_cache::lookup_gdb_index_debuginfod (const char *index_path,
> +                                         std::unique_ptr<index_cache_resource> *resource)
> +{
> +  try
> +    {
> +      /* Try to map that file.  */
> +      index_cache_resource_mmap *mmap_resource
> +       = new index_cache_resource_mmap (index_path);
> +
> +      /* Hand the resource to the caller.  */
> +      resource->reset (mmap_resource);
> +
> +      return gdb::array_view<const gdb_byte>
> +         ((const gdb_byte *) mmap_resource->mapping.get (),
> +          mmap_resource->mapping.size ());
> +    }
> +  catch (const gdb_exception_error &except)
> +    {
> +      warning (_("Unable to read %s: %s"), index_path, except.what ());
> +    }
> +
> +  return {};
> +}
> +
>  #else /* !HAVE_SYS_MMAN_H */
>
>  /* See dwarf-index-cache.h.  This is a no-op on unsupported systems.  */
> @@ -233,6 +260,12 @@ index_cache::lookup_gdb_index (const bfd_build_id *build_id,
>    return {};
>  }
>
> +gdb::array_view<const gdb_byte>
> +index_cache::lookup_gdb_index_debuginfod (const char *index_path,
> +                                         std::unique_ptr<index_cache_resource> *resource)
> +{
> +  return {};
> +}
>  #endif
>
>  /* See dwarf-index-cache.h.  */
> diff --git a/gdb/dwarf2/index-cache.h b/gdb/dwarf2/index-cache.h
> index 6366a9a9360..ecf74684c67 100644
> --- a/gdb/dwarf2/index-cache.h
> +++ b/gdb/dwarf2/index-cache.h
> @@ -65,6 +65,19 @@ class index_cache
>    lookup_gdb_index (const bfd_build_id *build_id,
>                     std::unique_ptr<index_cache_resource> *resource);
>
> +  /* Look for an index file located at INDEX_PATH in the debuginfod cache.
> +     Unlike lookup_gdb_index, this function does not exit early if the
> +     index cache has not been enabled.
> +
> +     If found, return the contents as an array_view and store the underlying
> +     resources (allocated memory, mapped file, etc) in RESOURCE.  The returned
> +     array_view is valid as long as RESOURCE is not destroyed.
> +
> +     If no matching index file is found, return an empty array view.  */
> +  gdb::array_view<const gdb_byte>
> +  lookup_gdb_index_debuginfod (const char *index_path,
> +                              std::unique_ptr<index_cache_resource> *resource);
> +
>    /* Return the number of cache hits.  */
>    unsigned int n_hits () const
>    { return m_n_hits; }
> diff --git a/gdb/dwarf2/public.h b/gdb/dwarf2/public.h
> index a9d4682c856..9971654c62f 100644
> --- a/gdb/dwarf2/public.h
> +++ b/gdb/dwarf2/public.h
> @@ -40,4 +40,6 @@ extern void dwarf2_initialize_objfile (struct objfile *objfile);
>
>  extern void dwarf2_build_frame_info (struct objfile *);
>
> +extern bool dwarf2_has_separate_index (struct objfile *);
> +
>  #endif /* DWARF2_PUBLIC_H */
> diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
> index 8e42c0f4d8d..1df63eba6f5 100644
> --- a/gdb/dwarf2/read.c
> +++ b/gdb/dwarf2/read.c
> @@ -93,6 +93,9 @@
>  #include "split-name.h"
>  #include "gdbsupport/parallel-for.h"
>  #include "gdbsupport/thread-pool.h"
> +#include "symfile.h"
> +#include "inferior.h"
> +#include "debuginfod-support.h"
>
>  /* When == 1, print basic high level tracing messages.
>     When > 1, be more verbose.
> @@ -1846,6 +1849,10 @@ struct dwarf2_base_index_functions : public quick_symbol_functions
>       CORE_ADDR pc, struct obj_section *section, int warn_if_readin)
>         override final;
>
> +  struct compunit_symtab *_find_pc_sect_compunit_symtab
> +    (struct objfile *objfile, struct bound_minimal_symbol msymbol,
> +     CORE_ADDR pc, struct obj_section *section, int warn_if_readin);
> +
>    struct compunit_symtab *find_compunit_symtab_by_address
>      (struct objfile *objfile, CORE_ADDR address) override
>    {
> @@ -1911,6 +1918,16 @@ struct dwarf2_gdb_index : public dwarf2_base_index_functions
>       block_search_flags search_flags,
>       domain_enum domain,
>       enum search_domain kind) override;
> +
> +  bool _expand_symtabs_matching
> +    (struct objfile *objfile,
> +     gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
> +     const lookup_name_info *lookup_name,
> +     gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
> +     gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
> +     block_search_flags search_flags,
> +     domain_enum domain,
> +     enum search_domain kind);
>  };
>
>  struct dwarf2_debug_names_index : public dwarf2_base_index_functions
> @@ -2677,28 +2694,31 @@ dwarf2_read_gdb_index
>
>    /* If there is a .dwz file, read it so we can get its CU list as
>       well.  */
> -  dwz = dwarf2_get_dwz_file (per_bfd);
> -  if (dwz != NULL)
> +  if (get_gdb_index_contents_dwz != nullptr)
>      {
> -      struct mapped_index dwz_map;
> -      const gdb_byte *dwz_types_ignore;
> -      offset_type dwz_types_elements_ignore;
> +      dwz = dwarf2_get_dwz_file (per_bfd);
> +      if (dwz != NULL)
> +       {
> +         struct mapped_index dwz_map;
> +         const gdb_byte *dwz_types_ignore;
> +         offset_type dwz_types_elements_ignore;
>
> -      gdb::array_view<const gdb_byte> dwz_index_content
> -       = get_gdb_index_contents_dwz (objfile, dwz);
> +         gdb::array_view<const gdb_byte> dwz_index_content
> +           = get_gdb_index_contents_dwz (objfile, dwz);
>
> -      if (dwz_index_content.empty ())
> -       return 0;
> +         if (dwz_index_content.empty ())
> +           return 0;
>
> -      if (!read_gdb_index_from_buffer (bfd_get_filename (dwz->dwz_bfd.get ()),
> -                                      1, dwz_index_content, &dwz_map,
> -                                      &dwz_list, &dwz_list_elements,
> -                                      &dwz_types_ignore,
> -                                      &dwz_types_elements_ignore))
> -       {
> -         warning (_("could not read '.gdb_index' section from %s; skipping"),
> -                  bfd_get_filename (dwz->dwz_bfd.get ()));
> -         return 0;
> +         if (!read_gdb_index_from_buffer (bfd_get_filename (dwz->dwz_bfd.get ()),
> +                                          1, dwz_index_content, &dwz_map,
> +                                          &dwz_list, &dwz_list_elements,
> +                                          &dwz_types_ignore,
> +                                          &dwz_types_elements_ignore))
> +           {
> +             warning (_("could not read '.gdb_index' section from %s; skipping"),
> +                      bfd_get_filename (dwz->dwz_bfd.get ()));
> +             return 0;
> +           }
>         }
>      }
>
> @@ -4192,8 +4212,10 @@ dw_expand_symtabs_matching_file_matcher
>      }
>  }
>
> +static bool read_full_dwarf_from_debuginfod (struct objfile *);
> +
>  bool
> -dwarf2_gdb_index::expand_symtabs_matching
> +dwarf2_gdb_index::_expand_symtabs_matching
>      (struct objfile *objfile,
>       gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
>       const lookup_name_info *lookup_name,
> @@ -4242,6 +4264,44 @@ dwarf2_gdb_index::expand_symtabs_matching
>    return result;
>  }
>
> +bool
> +dwarf2_gdb_index::expand_symtabs_matching
> +    (struct objfile *objfile,
> +     gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
> +     const lookup_name_info *lookup_name,
> +     gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
> +     gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
> +     block_search_flags search_flags,
> +     domain_enum domain,
> +     enum search_domain kind)
> +{
> +  if (objfile->flags & OBJF_READNEVER)
> +    return false;
> +
> +  try
> +    {
> +      return _expand_symtabs_matching (objfile, file_matcher, lookup_name,
> +                                      symbol_matcher, expansion_notify,
> +                                      search_flags, domain, kind);
> +    }
> +  catch (gdb_exception e)
> +    {
> +      if ((objfile->flags & OBJF_INDEX_READLATER) == 0)
> +       {
> +         exception_print (gdb_stderr, e);
> +         return false;
> +       }
> +
> +      /* Objfile is a stub holding only index information.  Try to reinitialize
> +        objfile with the full debuginfo.  */
> +      if (!read_full_dwarf_from_debuginfod (objfile))
> +         return false;
> +      return _expand_symtabs_matching (objfile, file_matcher, lookup_name,
> +                                      symbol_matcher, expansion_notify,
> +                                      search_flags, domain, kind);
> +    }
> +}
> +
>  /* A helper for dw2_find_pc_sect_compunit_symtab which finds the most specific
>     symtab.  */
>
> @@ -4281,7 +4341,7 @@ dwarf2_base_index_functions::find_per_cu (dwarf2_per_bfd *per_bfd,
>  }
>
>  struct compunit_symtab *
> -dwarf2_base_index_functions::find_pc_sect_compunit_symtab
> +dwarf2_base_index_functions::_find_pc_sect_compunit_symtab
>       (struct objfile *objfile,
>        struct bound_minimal_symbol msymbol,
>        CORE_ADDR pc,
> @@ -4312,6 +4372,40 @@ dwarf2_base_index_functions::find_pc_sect_compunit_symtab
>    return result;
>  }
>
> +struct compunit_symtab *
> +dwarf2_base_index_functions::find_pc_sect_compunit_symtab
> +     (struct objfile *objfile,
> +      struct bound_minimal_symbol msymbol,
> +      CORE_ADDR pc,
> +      struct obj_section *section,
> +      int warn_if_readin)
> +{
> +  if (objfile->flags & OBJF_READNEVER)
> +    return nullptr;
> +
> +  try
> +    {
> +      return _find_pc_sect_compunit_symtab (objfile, msymbol, pc,
> +                                           section, warn_if_readin);
> +    }
> +  catch (gdb_exception e)
> +    {
> +      if ((objfile->flags & OBJF_INDEX_READLATER) == 0)
> +       {
> +         exception_print (gdb_stderr, e);
> +         return nullptr;
> +       }
> +
> +      /* Objfile is a stub holding only index information.  Try to reinitialize
> +        objfile with the full debuginfo.  */
> +      if (!read_full_dwarf_from_debuginfod (objfile))
> +       return nullptr;
> +
> +      return _find_pc_sect_compunit_symtab (objfile, msymbol, pc,
> +                                           section, warn_if_readin);
> +    }
> +}
> +
>  void
>  dwarf2_base_index_functions::map_symbol_filenames
>       (struct objfile *objfile,
> @@ -5417,6 +5511,180 @@ dwarf2_initialize_objfile (struct objfile *objfile)
>    objfile->qf.push_front (make_cooked_index_funcs ());
>  }
>
> +/* Query debuginfod for the .gdb_index matching OBJFILE's build-id.  Return the
> +   contents if successful.  */
> +
> +static gdb::array_view<const gdb_byte>
> +get_gdb_index_contents_from_debuginfod (objfile *objfile, dwarf2_per_bfd *per_bfd)
> +{
> +  const bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
> +  if (build_id == nullptr)
> +    return {};
> +
> +  gdb::unique_xmalloc_ptr<char> index_path;
> +  scoped_fd fd = debuginfod_section_query (build_id->data, build_id->size,
> +                                          bfd_get_filename
> +                                            (objfile->obfd.get ()),
> +                                          ".gdb_index",
> +                                          &index_path);
> +  if (fd.get () < 0)
> +    return {};
> +
> +  return global_index_cache.lookup_gdb_index_debuginfod
> +    (index_path.get (), &per_bfd->index_cache_res);
> +}
> +
> +/* If OBJFILE is a stub holding only information from a .gdb_index, then attempt
> +   to download the full debuginfo and reinitialize OBJFILE with it.  */
> +
> +static bool
> +read_full_dwarf_from_debuginfod (struct objfile *objfile)
> +{
> +  if ((objfile->flags & OBJF_INDEX_READLATER) == 0)
> +    return false;
> +
> +  const struct bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
> +  if (build_id == nullptr)
> +    return false;
> +
> +  const char *filename = bfd_get_filename (objfile->obfd.get ());
> +  dwarf2_per_bfd *per_bfd;
> +  dwarf2_per_objfile *per_objfile;
> +  gdb_bfd_ref_ptr debug_bfd;
> +  gdb::unique_xmalloc_ptr<char> symfile_path;
> +
> +  scoped_fd fd (debuginfod_debuginfo_query (build_id->data,
> +                                           build_id->size,
> +                                           filename,
> +                                           &symfile_path));
> +
> +  if (fd.get () < 0)
> +    goto fail;
> +
> +  /* File successfully retrieved from server.  Open as a bfd.  */
> +  debug_bfd = symfile_bfd_open (symfile_path.get ());
> +
> +  if (debug_bfd == nullptr
> +      || !build_id_verify (debug_bfd.get (), build_id->size, build_id->data))
> +    {
> +      warning (_("File \"%s\" from debuginfod cannot be opened as bfd"),
> +              filename);
> +      goto fail;
> +    }
> +
> +  /* Fill in objfile's missing information using the debuginfo.  */
> +  objfile->reinit (debug_bfd.release ());
> +
> +  /* Create new per_bfd and per_objfile.  Placeholders based on the
> +     separate_debug_objfile_backlink were deleted during reinit.  */
> +  per_bfd = new dwarf2_per_bfd (objfile->obfd.get (), nullptr, false);
> +  dwarf2_per_bfd_objfile_data_key.set (objfile, per_bfd);
> +  per_objfile = dwarf2_objfile_data_key.emplace (objfile, objfile, per_bfd);
> +
> +  objfile->flags &= ~OBJF_INDEX_READLATER;
> +
> +  /* Have to attach the separate index again.  The dwz will be downloaded at
> +     this point if applicable.  */
> +  if (dwarf2_read_gdb_index (per_objfile,
> +                            get_gdb_index_contents_from_debuginfod,
> +                            get_gdb_index_contents_from_section<dwz_file>))
> +    {
> +      dwarf_read_debug_printf ("found gdb index from debuginfod");
> +      objfile->qf.push_front (per_objfile->per_bfd->index_table->make_quick_functions ());
> +
> +      objfile->flags &= ~OBJF_NOT_FILENAME;
> +      return true;
> +    }
> +
> +fail:
> +  objfile->flags |= OBJF_READNEVER;
> +  return false;
> +}
> +
> +/* Query debuginfod for the separate .gdb_index associated with OBJFILE.  If
> +   successful, create an objfile to hold the .gdb_index information and act
> +   as a placeholder until the full debuginfo needs to be downloaded.  */
> +
> +bool
> +dwarf2_has_separate_index (struct objfile *objfile)
> +{
> +  if (objfile->flags & OBJF_MAINLINE
> +      || objfile->separate_debug_objfile_backlink != nullptr)
> +    return 0;
> +
> +  if (objfile->flags & OBJF_INDEX_READLATER)
> +    return 1;
> +
> +  gdb::unique_xmalloc_ptr<char> index_path;
> +  const bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
> +
> +  scoped_fd fd = debuginfod_section_query (build_id->data,
> +                                          build_id->size,
> +                                          bfd_get_filename
> +                                            (objfile->obfd.get ()),
> +                                          ".gdb_index",
> +                                          &index_path);
> +  if (fd.get () >= 0)
> +    {
> +      /* We have a separate .gdb_index file so a separate debuginfo file
> +        should exist.  We just don't want to read it until we really
> +        have to.  Create an objfile to own the index information and to
> +        act as a placeholder for the debuginfo that we have the option
> +        of aquiring later.  */
> +      gdb_bfd_ref_ptr abfd (gdb_bfd_open (objfile_filename (objfile), gnutarget));
> +      if (abfd == nullptr)
> +       return false;
> +
> +      dwarf2_per_bfd_objfile_data_key.clear (objfile);
> +      dwarf2_objfile_data_key.clear (objfile);
> +
> +      symbol_file_add_from_index
> +       (abfd, current_inferior ()->symfile_flags | SYMFILE_NO_READ, objfile);
> +
> +      dwarf2_per_bfd *per_bfd;
> +      dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
> +
> +      if (per_objfile == nullptr)
> +       {
> +         per_bfd = dwarf2_per_bfd_objfile_data_key.get (objfile);
> +         if (per_bfd == nullptr)
> +           {
> +             per_bfd = new dwarf2_per_bfd (objfile->obfd.get (), nullptr, false);
> +             dwarf2_per_bfd_objfile_data_key.set (objfile, per_bfd);
> +           }
> +         per_objfile = dwarf2_objfile_data_key.emplace (objfile, objfile, per_bfd);
> +       }
> +
> +      struct objfile *stub = objfile->separate_debug_objfile;
> +      per_objfile = get_dwarf2_per_objfile (stub);
> +      if (per_objfile == nullptr)
> +       {
> +         per_bfd = dwarf2_per_bfd_objfile_data_key.get (stub);
> +         if (per_bfd == nullptr)
> +           {
> +             per_bfd = new dwarf2_per_bfd (stub->obfd.get (), nullptr, false);
> +             dwarf2_per_bfd_objfile_data_key.set (stub, per_bfd);
> +           }
> +         per_objfile = dwarf2_objfile_data_key.emplace (stub, stub, per_bfd);
> +       }
> +
> +      if (dwarf2_read_gdb_index (per_objfile,
> +                                get_gdb_index_contents_from_debuginfod,
> +                                nullptr))
> +       {
> +         dwarf_read_debug_printf ("found .gdb_index from debuginfod");
> +         stub->qf.push_front (per_bfd->index_table->make_quick_functions ());
> +         return 1;
> +       }
> +
> +      /* Unable to use the index.  Delete the stub.  */
> +      objfile->flags &= ~OBJF_INDEX_READLATER;
> +      stub->unlink ();
> +    }
> +
> +  return 0;
> +}
> +
>
>
>  /* Build a partial symbol table.  */
> diff --git a/gdb/dwarf2/section.c b/gdb/dwarf2/section.c
> index 32c86cc5d8d..4156ed2fdcb 100644
> --- a/gdb/dwarf2/section.c
> +++ b/gdb/dwarf2/section.c
> @@ -54,7 +54,9 @@ dwarf2_section_info::get_bfd_owner () const
>        section = get_containing_section ();
>        gdb_assert (!section->is_virtual);
>      }
> -  gdb_assert (section->s.section != nullptr);
> +  if (section->s.section == nullptr)
> +    throw_error (NOT_FOUND_ERROR,
> +                _("Can't find owner of DWARF2 section."));
>    return section->s.section->owner;
>  }
>
> diff --git a/gdb/elfread.c b/gdb/elfread.c
> index 8aee634b44b..25bbab065b8 100644
> --- a/gdb/elfread.c
> +++ b/gdb/elfread.c
> @@ -1274,6 +1274,8 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
>           symbol_file_add_separate (debug_bfd, debugfile.c_str (),
>                                     symfile_flags, objfile);
>         }
> +      else if (dwarf2_has_separate_index (objfile))
> +       return;
>        else
>         {
>           has_dwarf2 = false;
> diff --git a/gdb/objfile-flags.h b/gdb/objfile-flags.h
> index b2e07110571..df9bf27d778 100644
> --- a/gdb/objfile-flags.h
> +++ b/gdb/objfile-flags.h
> @@ -68,6 +68,10 @@ enum objfile_flag : unsigned
>      /* User requested that we do not read this objfile's symbolic
>         information.  */
>      OBJF_READNEVER = 1 << 7,
> +
> +    /* This objfile only holds information from an index.  It should
> +       be reinitialized with full debuginfo before expanding symtabs.  */
> +    OBJF_INDEX_READLATER = 1 << 8,
>    };
>
>  DEF_ENUM_FLAGS_TYPE (enum objfile_flag, objfile_flags);
> diff --git a/gdb/objfiles.c b/gdb/objfiles.c
> index 09aba0f80f0..c2c16c97758 100644
> --- a/gdb/objfiles.c
> +++ b/gdb/objfiles.c
> @@ -53,6 +53,7 @@
>  #include "gdb_bfd.h"
>  #include "btrace.h"
>  #include "gdbsupport/pathstuff.h"
> +#include "symfile.h"
>
>  #include <algorithm>
>  #include <vector>
> @@ -299,6 +300,16 @@ build_objfile_section_table (struct objfile *objfile)
>                            objfile, 1);
>  }
>
> +void
> +objfile::reinit (struct bfd *abfd)
> +{
> +  if ((flags & OBJF_INDEX_READLATER) == 0)
> +    return;
> +
> +  this->obfd.reset (abfd);
> +  deferred_read_symbols (this, 0);
> +}
> +
>  /* Given a pointer to an initialized bfd (ABFD) and some flag bits,
>     initialize the new objfile as best we can and link it into the list
>     of all known objfiles.
> @@ -455,6 +466,11 @@ objfile::make (gdb_bfd_ref_ptr bfd_, const char *name_, objfile_flags flags_,
>    if (parent != nullptr)
>      add_separate_debug_objfile (result, parent);
>
> +  /* Objfile was initialized using only an index.  Borrow offsets from the
> +     parent until debuginfo is read.  */
> +  if (flags_ & OBJF_INDEX_READLATER)
> +    result->section_offsets = parent->section_offsets;
> +
>    current_program_space->add_objfile (std::unique_ptr<objfile> (result),
>                                       parent);
>
> diff --git a/gdb/objfiles.h b/gdb/objfiles.h
> index 16dab0d2c69..0ebb16a30bd 100644
> --- a/gdb/objfiles.h
> +++ b/gdb/objfiles.h
> @@ -500,6 +500,11 @@ struct objfile
>    /* See quick_symbol_functions.  */
>    struct symtab *find_last_source_symtab ();
>
> +  /* Reinitialize this objfile using ABFD.  Objfile should have been originally
> +     initialized using a separate index from ABFD.  Updates this objfile with
> +     ABFD's symbols and section information.  */
> +  void reinit (struct bfd *abfd);
> +
>    /* See quick_symbol_functions.  */
>    void forget_cached_source_info ();
>
> diff --git a/gdb/symfile.c b/gdb/symfile.c
> index eb27668f9d3..7edd50d92a2 100644
> --- a/gdb/symfile.c
> +++ b/gdb/symfile.c
> @@ -1074,6 +1074,14 @@ symbol_file_add_with_addrs (const gdb_bfd_ref_ptr &abfd, const char *name,
>      flags |= OBJF_MAINLINE;
>    objfile = objfile::make (abfd, name, flags, parent);
>
> +  if (objfile->flags & OBJF_INDEX_READLATER)
> +    {
> +      /* objfile was initialized only using a separate index so don't
> +        try to read symbols yet.  */
> +      gdb::observers::new_objfile.notify (objfile);
> +      return objfile;
> +    }
> +
>    /* We either created a new mapped symbol table, mapped an existing
>       symbol table file which has not had initial symbol reading
>       performed, or need to read an unmapped symbol table.  */
> @@ -1135,6 +1143,29 @@ symbol_file_add_with_addrs (const gdb_bfd_ref_ptr &abfd, const char *name,
>    return (objfile);
>  }
>
> +/* We know a separate debuginfo file should exist, but we don't want to
> +   read it yet.  Infer some of it's properties from the parent objfile.  */
> +
> +void
> +symbol_file_add_from_index (const gdb_bfd_ref_ptr &bfd,
> +                           symfile_add_flags symfile_flags,
> +                           struct objfile *parent)
> +{
> +  section_addr_info sap = build_section_addr_info_from_objfile (parent);
> +
> +  symbol_file_add_with_addrs
> +    (bfd, "<separate .gdb_index stub>", symfile_flags, &sap,
> +     (parent->flags & (OBJF_REORDERED | OBJF_SHARED | OBJF_READNOW
> +                     | OBJF_USERLOADED | OBJF_MAINLINE | OBJF_PSYMTABS_READ))
> +                  | OBJF_INDEX_READLATER | OBJF_NOT_FILENAME,
> +     parent);
> +
> +  objfile *result = parent->separate_debug_objfile;
> +  init_objfile_sect_indices (result);
> +
> +  return;
> +}
> +
>  /* Add BFD as a separate debug file for OBJFILE.  For NAME description
>     see the objfile constructor.  */
>
> @@ -2415,6 +2446,57 @@ remove_symbol_file_command (const char *args, int from_tty)
>    clear_symtab_users (0);
>  }
>
> +/* Read a separate debuginfo OBJFILE that was originally initialized using
> +   only an index and section information from its parent file.  */
> +
> +void
> +deferred_read_symbols (struct objfile *objfile, int from_tty)
> +{
> +  gdb_assert (objfile->flags & OBJF_INDEX_READLATER);
> +
> +  /* Nuke all the state that we will re-read.  */
> +  objfile->registry_fields.clear_registry ();
> +
> +  objfile->sections = NULL;
> +  objfile->sect_index_bss = -1;
> +  objfile->sect_index_data = -1;
> +  objfile->sect_index_rodata = -1;
> +  objfile->sect_index_text = -1;
> +  objfile->compunit_symtabs = NULL;
> +  objfile->template_symbols = NULL;
> +
> +  {
> +    gdb_bfd_ref_ptr obfd = objfile->obfd;
> +    const char *obfd_filename;
> +
> +    obfd_filename = bfd_get_filename (objfile->obfd.get ());
> +    /* Open the new BFD before freeing the old one, so that
> +       the filename remains live.  */
> +    gdb_bfd_ref_ptr temp (gdb_bfd_open (obfd_filename, gnutarget));
> +    objfile->obfd = std::move (temp);
> +    if (objfile->obfd == NULL)
> +      error (_("Can't open %s to read symbols."), obfd_filename);
> +  }
> +
> +  std::string original_name = objfile->original_name;
> +
> +  /* bfd_openr sets cacheable to true, which is what we want.  */
> +  if (!bfd_check_format (objfile->obfd.get (), bfd_object))
> +    error (_("Can't read symbols from %s: %s."), objfile_name (objfile),
> +          bfd_errmsg (bfd_get_error ()));
> +
> +  objfile->original_name
> +    = obstack_strdup (&objfile->objfile_obstack, original_name);
> +
> +  objfile_set_sym_fns (objfile, find_sym_fns (objfile->obfd.get ()));
> +  build_objfile_section_table (objfile);
> +  (*objfile->sf->sym_init) (objfile);
> +  init_objfile_sect_indices (objfile);
> +
> +  read_symbols (objfile, 0);
> +  objfile->mtime = bfd_get_mtime (objfile->obfd.get ());
> +}
> +
>  /* Re-read symbols if a symbol-file has changed.  */
>
>  void
> diff --git a/gdb/symfile.h b/gdb/symfile.h
> index 1d13e82502b..724e156fc4b 100644
> --- a/gdb/symfile.h
> +++ b/gdb/symfile.h
> @@ -241,6 +241,9 @@ extern struct objfile *symbol_file_add_from_bfd (const gdb_bfd_ref_ptr &,
>  extern void symbol_file_add_separate (const gdb_bfd_ref_ptr &, const char *,
>                                       symfile_add_flags, struct objfile *);
>
> +extern void symbol_file_add_from_index (const gdb_bfd_ref_ptr &,
> +                                       symfile_add_flags, struct objfile *);
> +
>  extern std::string find_separate_debug_file_by_debuglink (struct objfile *);
>
>  /* Build (allocate and populate) a section_addr_info struct from an
> diff --git a/gdb/symtab.h b/gdb/symtab.h
> index 89d7a183ff3..380387162de 100644
> --- a/gdb/symtab.h
> +++ b/gdb/symtab.h
> @@ -2207,6 +2207,8 @@ extern bool find_pc_line_pc_range (CORE_ADDR, CORE_ADDR *, CORE_ADDR *);
>
>  extern void reread_symbols (int from_tty);
>
> +extern void deferred_read_symbols (struct objfile *, int from_tty);
> +
>  /* Look up a type named NAME in STRUCT_DOMAIN in the current language.
>     The type returned must not be opaque -- i.e., must have at least one field
>     defined.  */
> --
> 2.37.3
>


  reply	other threads:[~2022-10-21 16:44 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-06  2:24 [RFC][PATCH] " Aaron Merey
2022-10-21 16:44 ` Aaron Merey [this message]
2022-11-04 22:34   ` [PATCH] " Aaron Merey
2022-11-18 20:33     ` [PING*3][RFC PATCH] " Aaron Merey
2023-01-03 21:32       ` [PING*4][RFC " Aaron Merey
2023-01-11 21:25 ` [RFC][PATCH] " Tom Tromey
2023-01-13  0:49   ` Aaron Merey
2023-01-13  3:53     ` Tom Tromey

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=CAJDtP-TXM3CBuny--PLMXYWuESUa1W4YuRMZNBPHd4M4QF2yEw@mail.gmail.com \
    --to=amerey@redhat.com \
    --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;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).