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.133.124]) by sourceware.org (Postfix) with ESMTPS id A91B93858D1E for ; Tue, 3 Jan 2023 21:32:46 +0000 (GMT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1672781566; 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=CV9fWtK7J+CCN2HwQ05H6MBhji8X307J5sxtpUUpjd0=; b=O1x7eE62Pj+At110MCegJgY7B4OJVvirpPbaZolX0EXNynGOAHo0zOvdqv7FEEBa58RfdX nphMqIWKhigPqLQzbnGvGXcMEjU4llQLk9uTvfxW+12tJhGTvOTmD+wd55zdJfOr/ZIEQU 1Gfr7Yz0mfu4+ioFaYlOkUTGBYtGLjs= Received: from mail-pl1-f198.google.com (mail-pl1-f198.google.com [209.85.214.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-596-YO8ZexfmMm2hJAJ3IY4nSg-1; Tue, 03 Jan 2023 16:32:45 -0500 X-MC-Unique: YO8ZexfmMm2hJAJ3IY4nSg-1 Received: by mail-pl1-f198.google.com with SMTP id b6-20020a170902d50600b0019139834d47so22371847plg.8 for ; Tue, 03 Jan 2023 13:32:44 -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=CV9fWtK7J+CCN2HwQ05H6MBhji8X307J5sxtpUUpjd0=; b=QqRp+8L4xa7OkravR6B6kMTFJqDvlPYtFztUc4R+ftfWvP8ZcWz9bfViKp6CRJmbKQ 6y7CtaodfMShUx9eCAVuuljKJyZ0m5htK+9hegsOvZKLmfsJaP7vEqk4mugq4Jc/NJZ9 Jw8ak4NhBNxF/KIYQMFqRHy5xVLwXltDQqJZliTe8SA1fjHtNXZRwJLzoHeOGKw6UgoL 1M3LOUX3QNP9ysgSb/XZ4+nhInGyLYtBCQNbsbgPafG7nPBtMk92VFwcTWfajo0yFZcm BiK2yCFRAD9SOwiyWolpMW9Hh/fOelN5k62R8qQiJFsOcDIdLV8S+l01nSZ4zUXeqGM5 c+RQ== X-Gm-Message-State: AFqh2kpOVULr50KAJezUEvvjL+lyrjJDozONG7p/2LVnVjL9i4a5BjIs sYgLWzrwewUXtwHU2wKzkxbBu1RiMoybt+QuxMSuu628bemfalTZuXIJqBUOumK3wwDYN11Drm7 Lr5vJM9ISxSMEXWAyEWOUIMnChdWJXeSa2JGZ X-Received: by 2002:a17:90a:b301:b0:218:fb5c:a762 with SMTP id d1-20020a17090ab30100b00218fb5ca762mr4643355pjr.241.1672781563273; Tue, 03 Jan 2023 13:32:43 -0800 (PST) X-Google-Smtp-Source: AMrXdXtVWS0YfKAhF29U41dEFxOz7Rcvwp1abG/jlUvJ6wXfSpXWuNIr9F3Q7EnE/A5c/pnpCvz3wIbFSIrBYx+tp5M= X-Received: by 2002:a17:90a:b301:b0:218:fb5c:a762 with SMTP id d1-20020a17090ab30100b00218fb5ca762mr4643351pjr.241.1672781562330; Tue, 03 Jan 2023 13:32:42 -0800 (PST) MIME-Version: 1.0 References: <20221104223434.794317-1-amerey@redhat.com> In-Reply-To: From: Aaron Merey Date: Tue, 3 Jan 2023 16:32:31 -0500 Message-ID: Subject: [PING*4][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.3 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 18, 2022 at 3:33 PM Aaron Merey wrote: > > 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 > >