From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 97915385222B for ; Fri, 18 Nov 2022 20:34:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 97915385222B Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1668803645; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=0+nIisr3xwSBqdCVHhubIE9XUDZRZ6/KP5SEZU5Psrw=; b=T/GMptd32fKB8yWkW+leQDie33XPPvspGw+eEqPOonGdVS9PNxbTCyVwHpDSA9FvLikaVS 4/rgUZBmLqYgQfC/HgemZjBp6oBoHYhfuF8IePcFY+GwVt2In0E3BPeOaLCyjJ5c3WRJJ1 03JowjiTXIwRk1bIUR3fwiFUC8LwPXg= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-455-g_tyhmf0NhuH87XHf8bV-A-1; Fri, 18 Nov 2022 15:34:03 -0500 X-MC-Unique: g_tyhmf0NhuH87XHf8bV-A-1 Received: by mail-wr1-f72.google.com with SMTP id r4-20020adfbb04000000b00236639438e9so1962902wrg.11 for ; Fri, 18 Nov 2022 12:34:03 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=0+nIisr3xwSBqdCVHhubIE9XUDZRZ6/KP5SEZU5Psrw=; b=ei3ueOFCxq8T2vTu6C+XRJ5qOl0AA++M5XWarsIuwdLX++h8xyfEWHOre3u4O4QdzJ k0XwBWme5iQsbKawoQfGCsgG/aKt4D6SRQZHdhc0O0yM9UZ8qEpcClV67AeNyx8Agn8T MHxv7TRlFq8Hui7if+cud7jmdWxt1pmcdG5nsO6AQJzveRFd/vb5N6EhkK7X2KNn4s1M iR/jrvKzmJ8ybQlTV3HHtwbMu/nfbN9B6870k33M/c4tgNUTm7/tkKy3njZaFKTowVLo 62TrgzXkM0GMvvKDQEn7NY40umFiBmkUriIPq+CISaV5X/Qwpq6XW0g72o+t4AWXwXjG 7l7g== X-Gm-Message-State: ANoB5plIVEvZXJ1QnUnaSVwAE+uDizgLTknii54CFe4+FKkMzP4jnnxG nQrynv9OOYdzrVTQE4+XMtp+txQ5ym1ALiWwuXO2E90loJulJbSqxQLz5S6DbJ5Ou1nBaeoMsly SWIu9SI+N7aDjurjPu2CQ19jn65lL2vQ4OWiE X-Received: by 2002:a05:600c:3503:b0:3cf:f0a8:d04e with SMTP id h3-20020a05600c350300b003cff0a8d04emr9722580wmq.45.1668803641539; Fri, 18 Nov 2022 12:34:01 -0800 (PST) X-Google-Smtp-Source: AA0mqf7XHnhfdWxw4Eqt6asTNEVolJm7hgXQPYPaDGValcpnQuRz0KuK9xZOQowEpAhwdh6A+E15nTqdo8JVOcFKv7A= X-Received: by 2002:a05:600c:3503:b0:3cf:f0a8:d04e with SMTP id h3-20020a05600c350300b003cff0a8d04emr9722562wmq.45.1668803640889; Fri, 18 Nov 2022 12:34:00 -0800 (PST) MIME-Version: 1.0 References: <20221104223434.794317-1-amerey@redhat.com> In-Reply-To: <20221104223434.794317-1-amerey@redhat.com> From: Aaron Merey Date: Fri, 18 Nov 2022 15:33:49 -0500 Message-ID: Subject: [PING*3][RFC PATCH] gdb/debuginfod: Support on-demand downloading of debuginfo To: gdb-patches@sourceware.org X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Ping Thanks, Aaron On Fri, Nov 4, 2022 at 6:34 PM Aaron Merey 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 *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 *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 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 > *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 > + *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 > +index_cache::lookup_gdb_index_debuginfod (const char *index_path, > + std::unique_ptr *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 *) 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 > +index_cache::lookup_gdb_index_debuginfod (const char *index_path, > + std::unique_ptr *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 *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 > + lookup_gdb_index_debuginfod (const char *index_path, > + std::unique_ptr *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 file_matcher, > + const lookup_name_info *lookup_name, > + gdb::function_view symbol_matcher, > + gdb::function_view 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 dwz_index_content > - = get_gdb_index_contents_dwz (objfile, dwz); > + gdb::array_view 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 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 file_matcher, > + const lookup_name_info *lookup_name, > + gdb::function_view symbol_matcher, > + gdb::function_view 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 > +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 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 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)) > + { > + 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 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 > #include > @@ -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 (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, "", 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 >