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 010993856974 for ; Fri, 21 Oct 2022 16:44:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 010993856974 Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-119-mfrFe8A5P4uGjBv_37o-5A-1; Fri, 21 Oct 2022 12:44:23 -0400 X-MC-Unique: mfrFe8A5P4uGjBv_37o-5A-1 Received: by mail-wr1-f69.google.com with SMTP id i14-20020adfa50e000000b0023652707418so957052wrb.20 for ; Fri, 21 Oct 2022 09:44:23 -0700 (PDT) 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=lE2KfNDLcYypgFbT8c74qn3wCCbTzCH2rS8/7U/ypQY=; b=aUX9Bb7d2EiiRzAvvsjhGlKlh1Plwsomiuw+WjbfeGB4iH90JuAdpieehX7uq+ST4M 84+4kd6yo3ULfLvA20us/4bwZ+knbsGjWRhreBYo7HN6Bdc4QijlusLLwPjyBkA6zdav Brfv9puqiJxJDiKt2Em0/nd1It/n9+Ou548FJL4duIGlLW1ExK1gDUfYqhoi9SK1GUWk fv+N0nsALns0oR0YHt6VY+N+krg8vtQjmzAKYCUGbvuVPqt9eaXUKw5TvjqU4jXRzdbu 9QTbwYxF46oC/za38OfZOQOPl//MQjRp2kyg3g3OaHdTwKXQcxULn+1XiWL/lEVzcYAQ RGCg== X-Gm-Message-State: ACrzQf2XBD+SgmbcLJeh2ZFyWeWDAGhxt0QaL0lUmITy2Ha9IVSSA7iZ qV0k1815v+3uuWLRhQWl9+qgE9t7R7ephBIhiuR55DAKOBRI2iIk5vJxSnDuXW1SIEHAy8bz4DT U65UMHvMJYqDWaJQNufgo8JdbePfyMBpq6/uS X-Received: by 2002:adf:d204:0:b0:22e:397:d489 with SMTP id j4-20020adfd204000000b0022e0397d489mr12495393wrh.639.1666370661874; Fri, 21 Oct 2022 09:44:21 -0700 (PDT) X-Google-Smtp-Source: AMsMyM5Ham1pcKcwuePEd740bdmY0l8dfbg2WQka4AtxILlT90e/V5hqc3MwaShsfuQUCizRAMp/d6PUXdLGUF+Vybw= X-Received: by 2002:adf:d204:0:b0:22e:397:d489 with SMTP id j4-20020adfd204000000b0022e0397d489mr12495363wrh.639.1666370661181; Fri, 21 Oct 2022 09:44:21 -0700 (PDT) MIME-Version: 1.0 References: <20221006022424.399932-1-amerey@redhat.com> In-Reply-To: <20221006022424.399932-1-amerey@redhat.com> From: Aaron Merey Date: Fri, 21 Oct 2022 12:44:10 -0400 Message-ID: Subject: [PING][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.8 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 X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 21 Oct 2022 16:44:31 -0000 Ping Thanks, Aaron On Wed, Oct 5, 2022 at 10:24 PM Aaron Merey wrote: > > At the beginning of a session, GDB attempts to download debuginfo for > every shared library used by the process being debugged. One disadvantage > of this is that time may be spent downloading debuginfo that ultimately > isn't needed during the current session. > > This patch helps address the issue by adding support for on-demand > downloading and reading of debuginfo. The basic approach it takes is > to use debuginfod to download just the .gdb_index of a debuginfo file > as soon as the corresponding library is linked. GDB then relies on the > information in the index for as long as possible. When the index isn't > enough then debuginfo is downloaded and read. This helps avoid unnecessary > downloads. > > Although this patch specifically uses .gdb_index, other indexes such > as .debug_names could be supported in much the same way. > > Also with this patch, GDB will not build with the latest release of > debuginfod, hence the RFC. The debuginfod ELF/DWARF section query > function used in this patch to fetch .gdb_index is still in development > and will be included in a future release. > > This patch implements basic on-demand functionality but more work needs > to be done to fully take advantage of this feature. Currently GDB does > not attempt to download debuginfo when generating backtraces. In some > situations backtraces may lack information for libraries that we ought > to be able to download debuginfo for. If the user attempts to print a > non-existant symbol, GDB will start expanding symtabs one-by-one causing > all debuginfo to be downloaded. Some uses of the 'list' command also trigger > the downloading of all debuginfo, such as 'list 1' and 'list printf.c:33'. > > Now I'll describe the implementation in more detail. > > This patch adds a command 'set debuginfod enabled lazy' which enables > on-demand debuginfo downloading/reading. If this 'lazy' mode is enabled > and a solib's debuginfo cannot be found locally, the new function > dwarf2_has_separate_index is called in elf_symfile_read. This function > queries debuginfod servers for the .gdb_index matching the build-id > of the solib. If it's found, a new objfile is created to hold the .gdb_index > information. The new objfile flag OBJF_INDEX_READLATER is used to indicate > that the objfile contains quick_symbols_functions for an index has deferred > debuginfo reading. > > When GDB tries and fails to perform > dwarf2_base_index_functions::find_pc_sect_compunit_symtab or > dwarf2_gdb_index::expand_symtabs_matching, the new function > read_full_dwarf_from_debuginfod downloads the actual debuginfo file and > updates the objfile using the new function objfile::reinit. Symtab expansion > then proceeds as if the debuginfo was present all along. > > Any feedback is appreciated. > > Aaron > --- > gdb/debuginfod-support.c | 56 +++++++ > gdb/debuginfod-support.h | 23 +++ > gdb/dwarf2/index-cache.c | 33 +++++ > gdb/dwarf2/index-cache.h | 13 ++ > gdb/dwarf2/public.h | 2 + > gdb/dwarf2/read.c | 308 ++++++++++++++++++++++++++++++++++++--- > gdb/dwarf2/section.c | 4 +- > gdb/elfread.c | 2 + > gdb/objfile-flags.h | 4 + > gdb/objfiles.c | 16 ++ > gdb/objfiles.h | 5 + > gdb/symfile.c | 82 +++++++++++ > gdb/symfile.h | 3 + > gdb/symtab.h | 2 + > 14 files changed, 532 insertions(+), 21 deletions(-) > > diff --git a/gdb/debuginfod-support.c b/gdb/debuginfod-support.c > index 5f04a2b38ca..efcdb309522 100644 > --- a/gdb/debuginfod-support.c > +++ b/gdb/debuginfod-support.c > @@ -33,12 +33,14 @@ static cmd_list_element *show_debuginfod_prefix_list; > static const char debuginfod_on[] = "on"; > static const char debuginfod_off[] = "off"; > static const char debuginfod_ask[] = "ask"; > +static const char debuginfod_lazy[] = "lazy"; > > static const char *debuginfod_enabled_enum[] = > { > debuginfod_on, > debuginfod_off, > debuginfod_ask, > + debuginfod_lazy, > nullptr > }; > > @@ -79,6 +81,15 @@ debuginfod_exec_query (const unsigned char *build_id, > return scoped_fd (-ENOSYS); > } > > +scoped_fd > +debuginfod_section_query (const unsigned char *build_id, > + int build_id_len, > + const char *filename, > + const char *section_name, > + gdb::unique_xmalloc_ptr *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, true, &dname)); > + debuginfod_set_user_data (c, nullptr); > + > + if (fd.get () < 0 && fd.get () != -ENOENT) > + gdb_printf (_("Download failed: %s. " \ > + "Continuing without section %s for %ps.\n"), > + safe_strerror (-fd.get ()), section_name, > + styled_string (file_name_style.style (), filename)); > + > + if (fd.get () >= 0 && destname != nullptr) > + destname->reset (dname); > + > + return fd; > +} > #endif > > /* Set callback for "set debuginfod enabled". */ > diff --git a/gdb/debuginfod-support.h b/gdb/debuginfod-support.h > index 5b1c1cb91f4..5294b65cac4 100644 > --- a/gdb/debuginfod-support.h > +++ b/gdb/debuginfod-support.h > @@ -78,4 +78,27 @@ extern scoped_fd debuginfod_exec_query (const unsigned char *build_id, > const char *filename, > gdb::unique_xmalloc_ptr > *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 8e42c0f4d8d..1df63eba6f5 100644 > --- a/gdb/dwarf2/read.c > +++ b/gdb/dwarf2/read.c > @@ -93,6 +93,9 @@ > #include "split-name.h" > #include "gdbsupport/parallel-for.h" > #include "gdbsupport/thread-pool.h" > +#include "symfile.h" > +#include "inferior.h" > +#include "debuginfod-support.h" > > /* When == 1, print basic high level tracing messages. > When > 1, be more verbose. > @@ -1846,6 +1849,10 @@ struct dwarf2_base_index_functions : public quick_symbol_functions > CORE_ADDR pc, struct obj_section *section, int warn_if_readin) > override final; > > + struct compunit_symtab *_find_pc_sect_compunit_symtab > + (struct objfile *objfile, struct bound_minimal_symbol msymbol, > + CORE_ADDR pc, struct obj_section *section, int warn_if_readin); > + > struct compunit_symtab *find_compunit_symtab_by_address > (struct objfile *objfile, CORE_ADDR address) override > { > @@ -1911,6 +1918,16 @@ struct dwarf2_gdb_index : public dwarf2_base_index_functions > block_search_flags search_flags, > domain_enum domain, > enum search_domain kind) override; > + > + bool _expand_symtabs_matching > + (struct objfile *objfile, > + gdb::function_view 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 8aee634b44b..25bbab065b8 100644 > --- a/gdb/elfread.c > +++ b/gdb/elfread.c > @@ -1274,6 +1274,8 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags) > symbol_file_add_separate (debug_bfd, debugfile.c_str (), > symfile_flags, objfile); > } > + else if (dwarf2_has_separate_index (objfile)) > + return; > else > { > has_dwarf2 = false; > diff --git a/gdb/objfile-flags.h b/gdb/objfile-flags.h > index b2e07110571..df9bf27d778 100644 > --- a/gdb/objfile-flags.h > +++ b/gdb/objfile-flags.h > @@ -68,6 +68,10 @@ enum objfile_flag : unsigned > /* User requested that we do not read this objfile's symbolic > information. */ > OBJF_READNEVER = 1 << 7, > + > + /* This objfile only holds information from an index. It should > + be reinitialized with full debuginfo before expanding symtabs. */ > + OBJF_INDEX_READLATER = 1 << 8, > }; > > DEF_ENUM_FLAGS_TYPE (enum objfile_flag, objfile_flags); > diff --git a/gdb/objfiles.c b/gdb/objfiles.c > index 09aba0f80f0..c2c16c97758 100644 > --- a/gdb/objfiles.c > +++ b/gdb/objfiles.c > @@ -53,6 +53,7 @@ > #include "gdb_bfd.h" > #include "btrace.h" > #include "gdbsupport/pathstuff.h" > +#include "symfile.h" > > #include > #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 16dab0d2c69..0ebb16a30bd 100644 > --- a/gdb/objfiles.h > +++ b/gdb/objfiles.h > @@ -500,6 +500,11 @@ struct objfile > /* See quick_symbol_functions. */ > struct symtab *find_last_source_symtab (); > > + /* Reinitialize this objfile using ABFD. Objfile should have been originally > + initialized using a separate index from ABFD. Updates this objfile with > + ABFD's symbols and section information. */ > + void reinit (struct bfd *abfd); > + > /* See quick_symbol_functions. */ > void forget_cached_source_info (); > > diff --git a/gdb/symfile.c b/gdb/symfile.c > index eb27668f9d3..7edd50d92a2 100644 > --- a/gdb/symfile.c > +++ b/gdb/symfile.c > @@ -1074,6 +1074,14 @@ symbol_file_add_with_addrs (const gdb_bfd_ref_ptr &abfd, const char *name, > flags |= OBJF_MAINLINE; > objfile = objfile::make (abfd, name, flags, parent); > > + if (objfile->flags & OBJF_INDEX_READLATER) > + { > + /* objfile was initialized only using a separate index so don't > + try to read symbols yet. */ > + gdb::observers::new_objfile.notify (objfile); > + return objfile; > + } > + > /* We either created a new mapped symbol table, mapped an existing > symbol table file which has not had initial symbol reading > performed, or need to read an unmapped symbol table. */ > @@ -1135,6 +1143,29 @@ symbol_file_add_with_addrs (const gdb_bfd_ref_ptr &abfd, const char *name, > return (objfile); > } > > +/* We know a separate debuginfo file should exist, but we don't want to > + read it yet. Infer some of it's properties from the parent objfile. */ > + > +void > +symbol_file_add_from_index (const gdb_bfd_ref_ptr &bfd, > + symfile_add_flags symfile_flags, > + struct objfile *parent) > +{ > + section_addr_info sap = build_section_addr_info_from_objfile (parent); > + > + symbol_file_add_with_addrs > + (bfd, "", symfile_flags, &sap, > + (parent->flags & (OBJF_REORDERED | OBJF_SHARED | OBJF_READNOW > + | OBJF_USERLOADED | OBJF_MAINLINE | OBJF_PSYMTABS_READ)) > + | OBJF_INDEX_READLATER | OBJF_NOT_FILENAME, > + parent); > + > + objfile *result = parent->separate_debug_objfile; > + init_objfile_sect_indices (result); > + > + return; > +} > + > /* Add BFD as a separate debug file for OBJFILE. For NAME description > see the objfile constructor. */ > > @@ -2415,6 +2446,57 @@ remove_symbol_file_command (const char *args, int from_tty) > clear_symtab_users (0); > } > > +/* Read a separate debuginfo OBJFILE that was originally initialized using > + only an index and section information from its parent file. */ > + > +void > +deferred_read_symbols (struct objfile *objfile, int from_tty) > +{ > + gdb_assert (objfile->flags & OBJF_INDEX_READLATER); > + > + /* Nuke all the state that we will re-read. */ > + objfile->registry_fields.clear_registry (); > + > + objfile->sections = NULL; > + objfile->sect_index_bss = -1; > + objfile->sect_index_data = -1; > + objfile->sect_index_rodata = -1; > + objfile->sect_index_text = -1; > + objfile->compunit_symtabs = NULL; > + objfile->template_symbols = NULL; > + > + { > + gdb_bfd_ref_ptr obfd = objfile->obfd; > + const char *obfd_filename; > + > + obfd_filename = bfd_get_filename (objfile->obfd.get ()); > + /* Open the new BFD before freeing the old one, so that > + the filename remains live. */ > + gdb_bfd_ref_ptr temp (gdb_bfd_open (obfd_filename, gnutarget)); > + objfile->obfd = std::move (temp); > + if (objfile->obfd == NULL) > + error (_("Can't open %s to read symbols."), obfd_filename); > + } > + > + std::string original_name = objfile->original_name; > + > + /* bfd_openr sets cacheable to true, which is what we want. */ > + if (!bfd_check_format (objfile->obfd.get (), bfd_object)) > + error (_("Can't read symbols from %s: %s."), objfile_name (objfile), > + bfd_errmsg (bfd_get_error ())); > + > + objfile->original_name > + = obstack_strdup (&objfile->objfile_obstack, original_name); > + > + objfile_set_sym_fns (objfile, find_sym_fns (objfile->obfd.get ())); > + build_objfile_section_table (objfile); > + (*objfile->sf->sym_init) (objfile); > + init_objfile_sect_indices (objfile); > + > + read_symbols (objfile, 0); > + objfile->mtime = bfd_get_mtime (objfile->obfd.get ()); > +} > + > /* Re-read symbols if a symbol-file has changed. */ > > void > diff --git a/gdb/symfile.h b/gdb/symfile.h > index 1d13e82502b..724e156fc4b 100644 > --- a/gdb/symfile.h > +++ b/gdb/symfile.h > @@ -241,6 +241,9 @@ extern struct objfile *symbol_file_add_from_bfd (const gdb_bfd_ref_ptr &, > extern void symbol_file_add_separate (const gdb_bfd_ref_ptr &, const char *, > symfile_add_flags, struct objfile *); > > +extern void symbol_file_add_from_index (const gdb_bfd_ref_ptr &, > + symfile_add_flags, struct objfile *); > + > extern std::string find_separate_debug_file_by_debuglink (struct objfile *); > > /* Build (allocate and populate) a section_addr_info struct from an > diff --git a/gdb/symtab.h b/gdb/symtab.h > index 89d7a183ff3..380387162de 100644 > --- a/gdb/symtab.h > +++ b/gdb/symtab.h > @@ -2207,6 +2207,8 @@ extern bool find_pc_line_pc_range (CORE_ADDR, CORE_ADDR *, CORE_ADDR *); > > extern void reread_symbols (int from_tty); > > +extern void deferred_read_symbols (struct objfile *, int from_tty); > + > /* Look up a type named NAME in STRUCT_DOMAIN in the current language. > The type returned must not be opaque -- i.e., must have at least one field > defined. */ > -- > 2.37.3 >