From: Aaron Merey <amerey@redhat.com>
To: gdb-patches@sourceware.org
Subject: [PING*3][RFC PATCH] gdb/debuginfod: Support on-demand downloading of debuginfo
Date: Fri, 18 Nov 2022 15:33:49 -0500 [thread overview]
Message-ID: <CAJDtP-TCxr5-rZOYP2oNjNkKSM=2Bmuaa=ovorDQ2+FdD0d9XQ@mail.gmail.com> (raw)
In-Reply-To: <20221104223434.794317-1-amerey@redhat.com>
Ping
Thanks,
Aaron
On Fri, Nov 4, 2022 at 6:34 PM Aaron Merey <amerey@redhat.com> wrote:
>
> Ping. I've tweaked the patch to require the latest version of
> libdebuginfod which contains the new section query feature used by this
> patch.
>
> Thanks,
> Aaron
>
> ---
> 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.
>
> This patch changes the libdebuginfod version requirement from 0.179 to
> 0.188 in order to support queries for individual ELF sections.
> libdebuginfod-0.188 is a part of elfutils-0.188 [1].
>
> 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.
>
> 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.
>
> [1] https://sourceware.org/git/?p=elfutils.git;a=commit;h=e9f3045caa5c4498f371383e5519151942d48b6d
> ---
> binutils/configure | 20 +--
> config/debuginfod.m4 | 2 +-
> gdb/configure | 20 +--
> 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 +
> 17 files changed, 552 insertions(+), 43 deletions(-)
>
> diff --git a/binutils/configure b/binutils/configure
> index 2e33584e548..ea66a71f1f2 100755
> --- a/binutils/configure
> +++ b/binutils/configure
> @@ -11795,19 +11795,19 @@ $as_echo "$with_debuginfod" >&6; }
> if test "x$with_debuginfod" != xno; then
>
> pkg_failed=no
> -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdebuginfod >= 0.179" >&5
> -$as_echo_n "checking for libdebuginfod >= 0.179... " >&6; }
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdebuginfod >= 0.188" >&5
> +$as_echo_n "checking for libdebuginfod >= 0.188... " >&6; }
>
> if test -n "$DEBUGINFOD_CFLAGS"; then
> pkg_cv_DEBUGINFOD_CFLAGS="$DEBUGINFOD_CFLAGS"
> elif test -n "$PKG_CONFIG"; then
> if test -n "$PKG_CONFIG" && \
> - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdebuginfod >= 0.179\""; } >&5
> - ($PKG_CONFIG --exists --print-errors "libdebuginfod >= 0.179") 2>&5
> + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdebuginfod >= 0.188\""; } >&5
> + ($PKG_CONFIG --exists --print-errors "libdebuginfod >= 0.188") 2>&5
> ac_status=$?
> $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> test $ac_status = 0; }; then
> - pkg_cv_DEBUGINFOD_CFLAGS=`$PKG_CONFIG --cflags "libdebuginfod >= 0.179" 2>/dev/null`
> + pkg_cv_DEBUGINFOD_CFLAGS=`$PKG_CONFIG --cflags "libdebuginfod >= 0.188" 2>/dev/null`
> test "x$?" != "x0" && pkg_failed=yes
> else
> pkg_failed=yes
> @@ -11819,12 +11819,12 @@ if test -n "$DEBUGINFOD_LIBS"; then
> pkg_cv_DEBUGINFOD_LIBS="$DEBUGINFOD_LIBS"
> elif test -n "$PKG_CONFIG"; then
> if test -n "$PKG_CONFIG" && \
> - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdebuginfod >= 0.179\""; } >&5
> - ($PKG_CONFIG --exists --print-errors "libdebuginfod >= 0.179") 2>&5
> + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdebuginfod >= 0.188\""; } >&5
> + ($PKG_CONFIG --exists --print-errors "libdebuginfod >= 0.188") 2>&5
> ac_status=$?
> $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> test $ac_status = 0; }; then
> - pkg_cv_DEBUGINFOD_LIBS=`$PKG_CONFIG --libs "libdebuginfod >= 0.179" 2>/dev/null`
> + pkg_cv_DEBUGINFOD_LIBS=`$PKG_CONFIG --libs "libdebuginfod >= 0.188" 2>/dev/null`
> test "x$?" != "x0" && pkg_failed=yes
> else
> pkg_failed=yes
> @@ -11869,9 +11869,9 @@ else
> _pkg_short_errors_supported=no
> fi
> if test $_pkg_short_errors_supported = yes; then
> - DEBUGINFOD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libdebuginfod >= 0.179" 2>&1`
> + DEBUGINFOD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libdebuginfod >= 0.188" 2>&1`
> else
> - DEBUGINFOD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libdebuginfod >= 0.179" 2>&1`
> + DEBUGINFOD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libdebuginfod >= 0.188" 2>&1`
> fi
> # Put the nasty error message in config.log where it belongs
> echo "$DEBUGINFOD_PKG_ERRORS" >&5
> diff --git a/config/debuginfod.m4 b/config/debuginfod.m4
> index 2c1bfbdb544..d861156a643 100644
> --- a/config/debuginfod.m4
> +++ b/config/debuginfod.m4
> @@ -15,7 +15,7 @@ AC_MSG_CHECKING([whether to use debuginfod])
> AC_MSG_RESULT([$with_debuginfod])
>
> if test "x$with_debuginfod" != xno; then
> - PKG_CHECK_MODULES([DEBUGINFOD], [libdebuginfod >= 0.179],
> + PKG_CHECK_MODULES([DEBUGINFOD], [libdebuginfod >= 0.188],
> [AC_DEFINE([HAVE_LIBDEBUGINFOD], [1], [Define to 1 if debuginfod is enabled.])],
> [if test "x$with_debuginfod" = xyes; then
> AC_MSG_ERROR(["--with-debuginfod was given, but libdebuginfod is missing or unusable."])
> diff --git a/gdb/configure b/gdb/configure
> index 33677262783..6548714da2e 100755
> --- a/gdb/configure
> +++ b/gdb/configure
> @@ -7032,19 +7032,19 @@ $as_echo "$with_debuginfod" >&6; }
> if test "x$with_debuginfod" != xno; then
>
> pkg_failed=no
> -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdebuginfod >= 0.179" >&5
> -$as_echo_n "checking for libdebuginfod >= 0.179... " >&6; }
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdebuginfod >= 0.188" >&5
> +$as_echo_n "checking for libdebuginfod >= 0.188... " >&6; }
>
> if test -n "$DEBUGINFOD_CFLAGS"; then
> pkg_cv_DEBUGINFOD_CFLAGS="$DEBUGINFOD_CFLAGS"
> elif test -n "$PKG_CONFIG"; then
> if test -n "$PKG_CONFIG" && \
> - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdebuginfod >= 0.179\""; } >&5
> - ($PKG_CONFIG --exists --print-errors "libdebuginfod >= 0.179") 2>&5
> + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdebuginfod >= 0.188\""; } >&5
> + ($PKG_CONFIG --exists --print-errors "libdebuginfod >= 0.188") 2>&5
> ac_status=$?
> $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> test $ac_status = 0; }; then
> - pkg_cv_DEBUGINFOD_CFLAGS=`$PKG_CONFIG --cflags "libdebuginfod >= 0.179" 2>/dev/null`
> + pkg_cv_DEBUGINFOD_CFLAGS=`$PKG_CONFIG --cflags "libdebuginfod >= 0.188" 2>/dev/null`
> test "x$?" != "x0" && pkg_failed=yes
> else
> pkg_failed=yes
> @@ -7056,12 +7056,12 @@ if test -n "$DEBUGINFOD_LIBS"; then
> pkg_cv_DEBUGINFOD_LIBS="$DEBUGINFOD_LIBS"
> elif test -n "$PKG_CONFIG"; then
> if test -n "$PKG_CONFIG" && \
> - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdebuginfod >= 0.179\""; } >&5
> - ($PKG_CONFIG --exists --print-errors "libdebuginfod >= 0.179") 2>&5
> + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdebuginfod >= 0.188\""; } >&5
> + ($PKG_CONFIG --exists --print-errors "libdebuginfod >= 0.188") 2>&5
> ac_status=$?
> $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> test $ac_status = 0; }; then
> - pkg_cv_DEBUGINFOD_LIBS=`$PKG_CONFIG --libs "libdebuginfod >= 0.179" 2>/dev/null`
> + pkg_cv_DEBUGINFOD_LIBS=`$PKG_CONFIG --libs "libdebuginfod >= 0.188" 2>/dev/null`
> test "x$?" != "x0" && pkg_failed=yes
> else
> pkg_failed=yes
> @@ -7106,9 +7106,9 @@ else
> _pkg_short_errors_supported=no
> fi
> if test $_pkg_short_errors_supported = yes; then
> - DEBUGINFOD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libdebuginfod >= 0.179" 2>&1`
> + DEBUGINFOD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libdebuginfod >= 0.188" 2>&1`
> else
> - DEBUGINFOD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libdebuginfod >= 0.179" 2>&1`
> + DEBUGINFOD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libdebuginfod >= 0.188" 2>&1`
> fi
> # Put the nasty error message in config.log where it belongs
> echo "$DEBUGINFOD_PKG_ERRORS" >&5
> diff --git a/gdb/debuginfod-support.c b/gdb/debuginfod-support.c
> index 5f04a2b38ca..c2f4d54256c 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, &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 60e120a9d76..fff4b1eb136 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 64aeb239670..c229575d1b3 100644
> --- a/gdb/elfread.c
> +++ b/gdb/elfread.c
> @@ -1225,7 +1225,7 @@ elf_symfile_read_dwarf2 (struct objfile *objfile,
> symbol_file_add_separate (debug_bfd, debugfile.c_str (),
> symfile_flags, objfile);
> }
> - else
> + else if (!dwarf2_has_separate_index (objfile))
> {
> has_dwarf2 = false;
> const struct bfd_build_id *build_id
> 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 9a152cbc387..971fa7d587d 100644
> --- a/gdb/objfiles.h
> +++ b/gdb/objfiles.h
> @@ -497,6 +497,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 ffd1acddfdb..9b42ec64aeb 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 4f3e84bbbe9..b5d266ae39b 100644
> --- a/gdb/symtab.h
> +++ b/gdb/symtab.h
> @@ -2206,6 +2206,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
>
next prev parent reply other threads:[~2022-11-18 20:34 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 ` [PING][RFC PATCH] " Aaron Merey
2022-11-04 22:34 ` [PATCH] " Aaron Merey
2022-11-18 20:33 ` Aaron Merey [this message]
2023-01-03 21:32 ` [PING*4][RFC PATCH] " 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-TCxr5-rZOYP2oNjNkKSM=2Bmuaa=ovorDQ2+FdD0d9XQ@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).