From: Aaron Merey <amerey@redhat.com>
To: gdb-patches@sourceware.org
Cc: Andrew Burgess <aburgess@redhat.com>
Subject: [PING*2][PATCH 3/4 v4] gdb/debuginfod: Support on-demand debuginfo downloading
Date: Mon, 20 Nov 2023 13:39:43 -0500 [thread overview]
Message-ID: <CAJDtP-Qko6KCQxYRVsAWHMW0s3PxMbUTpfCcJJUr7OcNo+t-8w@mail.gmail.com> (raw)
In-Reply-To: <CAJDtP-TwP8t=gLAEbXbjm4OECC8GOPX0WORAi+iUBOSDAXKCSg@mail.gmail.com>
Ping
Thanks,
Aaron
On Sun, Nov 12, 2023 at 3:20 PM Aaron Merey <amerey@redhat.com> wrote:
>
> Ping
>
> Thanks,
> Aaron
>
> On Fri, Oct 27, 2023 at 8:20 PM Aaron Merey <amerey@redhat.com> wrote:
> >
> > v3: https://sourceware.org/pipermail/gdb-patches/2023-June/199987.html
> >
> > v4 improves testcases when running with --target_board=native-gdbserver.
> >
> > v4 also fixes a bug where objfile observers could clear selected_frame
> > if debuginfo was downloaded during get_selected_frame.
> >
> > Commit message:
> >
> > At the beginning of a session, gdb may attempt to download debuginfo
> > for all shared libraries associated with the process or core file
> > being debugged. This can be a waste of time and storage space when much
> > of the debuginfo ends up not being used during the session.
> >
> > To reduce the gdb's startup latency and to download only the debuginfo
> > that is really needed, this patch adds on-demand downloading of debuginfo.
> >
> > 'set debuginfo enabled on' now causes gdb to attempt to download a .gdb_index
> > for each shared library instead of its full debuginfo. Each corresponding
> > separate debuginfo will be deferred until gdb needs to expand symtabs
> > associated with the debuginfo's index.
> >
> > Because these indices are significantly smaller than their corresponding
> > debuginfo, this generally reduces the total amount of data gdb downloads.
> > Reductions of 80%-95% have been observed when debugging large GUI programs.
> >
> > (gdb) set debuginfod enabled on
> > (gdb) start
> > Downloading section .gdb_index for /lib64/libcurl.so.4
> > [...]
> > 1826 client->server_mhandle = curl_multi_init ();
> > (gdb) step
> > Downloading separate debug info for /lib64/libcurl.so.4
> > Downloading separate debug info for [libcurl dwz]
> > Downloading source file /usr/src/debug/curl-7.85.0-6.fc37.x86_64/build-full/lib/../../lib/multi.c
> > curl_multi_init () at ../../lib/multi.c:457
> > 457 {
> > (gdb)
> >
> > Some of the key functions below include dwarf2_has_separate_index which
> > downloads the separate .gdb_index. If successful, the shared library
> > objfile owns the index until the separate debug objfile is downloaded
> > or confirmed to not be available.
> >
> > read_full_dwarf_from_debuginfod downloads the full debuginfo and
> > initializes the separate debug objfile. It is called by functions
> > such as dwarf2_gdb_index::expand_symtabs_matching and
> > dwarf2_base_index_functions::find_pc_sect_compunit_symtab when symtab
> > expansion is required.
> > ---
> > gdb/dwarf2/frame.c | 13 ++
> > gdb/dwarf2/frame.h | 4 +
> > gdb/dwarf2/index-cache.c | 33 ++++
> > gdb/dwarf2/index-cache.h | 13 ++
> > gdb/dwarf2/public.h | 7 +
> > gdb/dwarf2/read-gdb-index.c | 156 +++++++++++++++--
> > gdb/dwarf2/read.c | 146 +++++++++++++++-
> > gdb/dwarf2/read.h | 10 ++
> > gdb/dwarf2/section.c | 3 +-
> > gdb/elfread.c | 2 +-
> > gdb/frame.c | 7 +
> > gdb/objfile-flags.h | 4 +
> > gdb/objfiles.h | 20 +++
> > gdb/quick-symbol.h | 4 +
> > gdb/symfile.c | 13 +-
> > gdb/symtab.c | 18 +-
> > gdb/testsuite/gdb.debuginfod/libsection1.c | 40 +++++
> > gdb/testsuite/gdb.debuginfod/libsection2.c | 37 +++++
> > gdb/testsuite/gdb.debuginfod/section.c | 29 ++++
> > gdb/testsuite/gdb.debuginfod/section.exp | 184 +++++++++++++++++++++
> > gdb/testsuite/lib/debuginfod-support.exp | 27 ++-
> > 21 files changed, 746 insertions(+), 24 deletions(-)
> > create mode 100644 gdb/testsuite/gdb.debuginfod/libsection1.c
> > create mode 100644 gdb/testsuite/gdb.debuginfod/libsection2.c
> > create mode 100644 gdb/testsuite/gdb.debuginfod/section.c
> > create mode 100644 gdb/testsuite/gdb.debuginfod/section.exp
> >
> > diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
> > index abc8d613482..257f0316731 100644
> > --- a/gdb/dwarf2/frame.c
> > +++ b/gdb/dwarf2/frame.c
> > @@ -1617,6 +1617,19 @@ set_comp_unit (struct objfile *objfile, struct comp_unit *unit)
> > return dwarf2_frame_bfd_data.set (abfd, unit);
> > }
> >
> > +/* See frame.h. */
> > +
> > +void
> > +dwarf2_clear_frame_data (struct objfile *objfile)
> > +{
> > + bfd *abfd = objfile->obfd.get ();
> > +
> > + if (gdb_bfd_requires_relocations (abfd))
> > + dwarf2_frame_objfile_data.clear (objfile);
> > + else
> > + dwarf2_frame_bfd_data.clear (abfd);
> > +}
> > +
> > /* Find the FDE for *PC. Return a pointer to the FDE, and store the
> > initial location associated with it into *PC. */
> >
> > diff --git a/gdb/dwarf2/frame.h b/gdb/dwarf2/frame.h
> > index 5643e557513..2391e313e7c 100644
> > --- a/gdb/dwarf2/frame.h
> > +++ b/gdb/dwarf2/frame.h
> > @@ -238,6 +238,10 @@ void dwarf2_append_unwinders (struct gdbarch *gdbarch);
> > extern const struct frame_base *
> > dwarf2_frame_base_sniffer (frame_info_ptr this_frame);
> >
> > +/* Delete OBJFILEs comp_unit. */
> > +
> > +extern void dwarf2_clear_frame_data (struct objfile * objfile);
> > +
> > /* Compute the DWARF CFA for a frame. */
> >
> > CORE_ADDR dwarf2_frame_cfa (frame_info_ptr this_frame);
> > diff --git a/gdb/dwarf2/index-cache.c b/gdb/dwarf2/index-cache.c
> > index 69f70642dc6..8c969ecd590 100644
> > --- a/gdb/dwarf2/index-cache.c
> > +++ b/gdb/dwarf2/index-cache.c
> > @@ -240,6 +240,33 @@ index_cache::lookup_gdb_index (const bfd_build_id *build_id,
> > return {};
> > }
> >
> > +/* See index-cache.h. */
> > +
> > +gdb::array_view<const gdb_byte>
> > +index_cache::lookup_gdb_index_debuginfod (const char *index_path,
> > + std::unique_ptr<index_cache_resource> *resource)
> > +{
> > + try
> > + {
> > + /* Try to map that file. */
> > + index_cache_resource_mmap *mmap_resource
> > + = new index_cache_resource_mmap (index_path);
> > +
> > + /* Hand the resource to the caller. */
> > + resource->reset (mmap_resource);
> > +
> > + return gdb::array_view<const gdb_byte>
> > + ((const gdb_byte *) mmap_resource->mapping.get (),
> > + mmap_resource->mapping.size ());
> > + }
> > + catch (const gdb_exception_error &except)
> > + {
> > + warning (_("Unable to read %s: %s"), index_path, except.what ());
> > + }
> > +
> > + return {};
> > +}
> > +
> > #else /* !HAVE_SYS_MMAN_H */
> >
> > /* See dwarf-index-cache.h. This is a no-op on unsupported systems. */
> > @@ -251,6 +278,12 @@ index_cache::lookup_gdb_index (const bfd_build_id *build_id,
> > return {};
> > }
> >
> > +gdb::array_view<const gdb_byte>
> > +index_cache::lookup_gdb_index_debuginfod (const char *index_path,
> > + std::unique_ptr<index_cache_resource> *resource)
> > +{
> > + return {};
> > +}
> > #endif
> >
> > /* See dwarf-index-cache.h. */
> > diff --git a/gdb/dwarf2/index-cache.h b/gdb/dwarf2/index-cache.h
> > index cfa45435fbd..9d18717fe56 100644
> > --- a/gdb/dwarf2/index-cache.h
> > +++ b/gdb/dwarf2/index-cache.h
> > @@ -90,6 +90,19 @@ class index_cache
> > lookup_gdb_index (const bfd_build_id *build_id,
> > std::unique_ptr<index_cache_resource> *resource);
> >
> > + /* Look for an index file located at INDEX_PATH in the debuginfod cache.
> > + Unlike lookup_gdb_index, this function does not exit early if the
> > + index cache has not been enabled.
> > +
> > + If found, return the contents as an array_view and store the underlying
> > + resources (allocated memory, mapped file, etc) in RESOURCE. The returned
> > + array_view is valid as long as RESOURCE is not destroyed.
> > +
> > + If no matching index file is found, return an empty array view. */
> > + gdb::array_view<const gdb_byte>
> > + lookup_gdb_index_debuginfod (const char *index_path,
> > + std::unique_ptr<index_cache_resource> *resource);
> > +
> > /* Return the number of cache hits. */
> > unsigned int n_hits () const
> > { return m_n_hits; }
> > diff --git a/gdb/dwarf2/public.h b/gdb/dwarf2/public.h
> > index 0e74857eb1a..4a44cdbc223 100644
> > --- a/gdb/dwarf2/public.h
> > +++ b/gdb/dwarf2/public.h
> > @@ -40,4 +40,11 @@ extern void dwarf2_initialize_objfile (struct objfile *objfile);
> >
> > extern void dwarf2_build_frame_info (struct objfile *);
> >
> > +/* Query debuginfod for the .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. */
> > +
> > +extern bool dwarf2_has_separate_index (struct objfile *);
> > +
> > #endif /* DWARF2_PUBLIC_H */
> > diff --git a/gdb/dwarf2/read-gdb-index.c b/gdb/dwarf2/read-gdb-index.c
> > index e789e9c2654..da88a8b405c 100644
> > --- a/gdb/dwarf2/read-gdb-index.c
> > +++ b/gdb/dwarf2/read-gdb-index.c
> > @@ -139,6 +139,7 @@ struct dwarf2_gdb_index : public dwarf2_base_index_functions
> > gdb.dwarf2/gdb-index.exp testcase. */
> > void dump (struct objfile *objfile) override;
> >
> > + /* Calls do_expand_matching_symbols and downloads debuginfo if necessary. */
> > void expand_matching_symbols
> > (struct objfile *,
> > const lookup_name_info &lookup_name,
> > @@ -146,6 +147,14 @@ struct dwarf2_gdb_index : public dwarf2_base_index_functions
> > int global,
> > symbol_compare_ftype *ordered_compare) override;
> >
> > + void do_expand_matching_symbols
> > + (struct objfile *,
> > + const lookup_name_info &lookup_name,
> > + domain_enum domain,
> > + int global,
> > + symbol_compare_ftype *ordered_compare);
> > +
> > + /* Calls do_expand_symtabs_matching and downloads debuginfo if necessary. */
> > bool expand_symtabs_matching
> > (struct objfile *objfile,
> > gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
> > @@ -155,8 +164,59 @@ struct dwarf2_gdb_index : public dwarf2_base_index_functions
> > block_search_flags search_flags,
> > domain_enum domain,
> > enum search_domain kind) override;
> > +
> > + bool do_expand_symtabs_matching
> > + (struct objfile *objfile,
> > + gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
> > + const lookup_name_info *lookup_name,
> > + gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
> > + gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
> > + block_search_flags search_flags,
> > + domain_enum domain,
> > + enum search_domain kind);
> > +
> > + /* Calls dwarf2_base_index_functions::expand_all_symtabs and downloads
> > + debuginfo if necessary. */
> > + void expand_all_symtabs (struct objfile *objfile) override;
> > +
> > + /* Calls dwarf2_base_index_functions::find_last_source_symtab and downloads
> > + debuginfo if necessary. */
> > + struct symtab *find_last_source_symtab (struct objfile *objfile) override;
> > };
> >
> > +void
> > +dwarf2_gdb_index::expand_all_symtabs (struct objfile *objfile)
> > +{
> > + try
> > + {
> > + dwarf2_base_index_functions::expand_all_symtabs (objfile);
> > + }
> > + catch (const gdb_exception &e)
> > + {
> > + if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
> > + exception_print (gdb_stderr, e);
> > + else
> > + read_full_dwarf_from_debuginfod (objfile, this);
> > + }
> > +}
> > +
> > +struct symtab *
> > +dwarf2_gdb_index::find_last_source_symtab (struct objfile *objfile)
> > +{
> > + try
> > + {
> > + return dwarf2_base_index_functions::find_last_source_symtab (objfile);
> > + }
> > + catch (const gdb_exception &e)
> > + {
> > + if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
> > + exception_print (gdb_stderr, e);
> > + else
> > + read_full_dwarf_from_debuginfod (objfile, this);
> > + return nullptr;
> > + }
> > +}
> > +
> > /* This dumps minimal information about the index.
> > It is called via "mt print objfiles".
> > One use is to verify .gdb_index has been loaded by the
> > @@ -318,7 +378,7 @@ dw2_symtab_iter_next (struct dw2_symtab_iterator *iter,
> > }
> >
> > void
> > -dwarf2_gdb_index::expand_matching_symbols
> > +dwarf2_gdb_index::do_expand_matching_symbols
> > (struct objfile *objfile,
> > const lookup_name_info &name, domain_enum domain,
> > int global,
> > @@ -356,6 +416,29 @@ dwarf2_gdb_index::expand_matching_symbols
> > }, per_objfile);
> > }
> >
> > +void
> > +dwarf2_gdb_index::expand_matching_symbols
> > + (struct objfile *objfile,
> > + const lookup_name_info &lookup_name,
> > + domain_enum domain,
> > + int global,
> > + symbol_compare_ftype *ordered_compare)
> > +{
> > + try
> > + {
> > + do_expand_matching_symbols (objfile, lookup_name, domain,
> > + global, ordered_compare);
> > + }
> > + catch (const gdb_exception &e)
> > + {
> > + if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
> > + exception_print (gdb_stderr, e);
> > + else
> > + read_full_dwarf_from_debuginfod (objfile, this);
> > + return;
> > + }
> > +}
> > +
> > /* Helper for dw2_expand_matching symtabs. Called on each symbol
> > matched, to expand corresponding CUs that were marked. IDX is the
> > index of the symbol name that matched. */
> > @@ -458,7 +541,7 @@ dw2_expand_marked_cus
> > }
> >
> > bool
> > -dwarf2_gdb_index::expand_symtabs_matching
> > +dwarf2_gdb_index::do_expand_symtabs_matching
> > (struct objfile *objfile,
> > gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
> > const lookup_name_info *lookup_name,
> > @@ -507,6 +590,39 @@ dwarf2_gdb_index::expand_symtabs_matching
> > return result;
> > }
> >
> > +bool
> > +dwarf2_gdb_index::expand_symtabs_matching
> > + (struct objfile *objfile,
> > + gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
> > + const lookup_name_info *lookup_name,
> > + gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
> > + gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
> > + block_search_flags search_flags,
> > + domain_enum domain,
> > + enum search_domain kind)
> > +{
> > + if (objfile->flags & OBJF_READNEVER)
> > + return false;
> > +
> > + try
> > + {
> > + return do_expand_symtabs_matching (objfile, file_matcher, lookup_name,
> > + symbol_matcher, expansion_notify,
> > + search_flags, domain, kind);
> > + }
> > + catch (const gdb_exception &e)
> > + {
> > + if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
> > + {
> > + exception_print (gdb_stderr, e);
> > + return false;
> > + }
> > +
> > + read_full_dwarf_from_debuginfod (objfile, this);
> > + return true;
> > + }
> > +}
> > +
> > quick_symbol_functions_up
> > mapped_gdb_index::make_quick_functions () const
> > {
> > @@ -842,28 +958,32 @@ 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)
> > {
> > mapped_gdb_index dwz_map;
> > const gdb_byte *dwz_types_ignore;
> > offset_type dwz_types_elements_ignore;
> > + dwz = dwarf2_get_dwz_file (per_bfd);
> >
> > - gdb::array_view<const gdb_byte> dwz_index_content
> > - = get_gdb_index_contents_dwz (objfile, dwz);
> > -
> > - 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))
> > + if (dwz != nullptr)
> > {
> > - warning (_("could not read '.gdb_index' section from %s; skipping"),
> > - bfd_get_filename (dwz->dwz_bfd.get ()));
> > - return 0;
> > + gdb::array_view<const gdb_byte> dwz_index_content
> > + = get_gdb_index_contents_dwz (objfile, dwz);
> > +
> > + 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;
> > + }
> > }
> > }
> >
> > diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
> > index ea0b2328a3e..0c5689c63ef 100644
> > --- a/gdb/dwarf2/read.c
> > +++ b/gdb/dwarf2/read.c
> > @@ -34,6 +34,7 @@
> > #include "dwarf2/attribute.h"
> > #include "dwarf2/comp-unit-head.h"
> > #include "dwarf2/cu.h"
> > +#include "dwarf2/frame.h"
> > #include "dwarf2/index-cache.h"
> > #include "dwarf2/index-common.h"
> > #include "dwarf2/leb.h"
> > @@ -95,6 +96,8 @@
> > #include "split-name.h"
> > #include "gdbsupport/parallel-for.h"
> > #include "gdbsupport/thread-pool.h"
> > +#include "inferior.h"
> > +#include "debuginfod-support.h"
> >
> > /* When == 1, print basic high level tracing messages.
> > When > 1, be more verbose.
> > @@ -3188,7 +3191,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::do_find_pc_sect_compunit_symtab
> > (struct objfile *objfile,
> > struct bound_minimal_symbol msymbol,
> > CORE_ADDR pc,
> > @@ -3219,6 +3222,32 @@ 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 do_find_pc_sect_compunit_symtab (objfile, msymbol, pc,
> > + section, warn_if_readin);
> > + }
> > + catch (const gdb_exception &e)
> > + {
> > + if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
> > + exception_print (gdb_stderr, e);
> > + else
> > + read_full_dwarf_from_debuginfod (objfile, this);
> > + return nullptr;
> > + }
> > +}
> > +
> > void
> > dwarf2_base_index_functions::map_symbol_filenames
> > (struct objfile *objfile,
> > @@ -3375,6 +3404,29 @@ get_gdb_index_contents_from_cache_dwz (objfile *obj, dwz_file *dwz)
> > return global_index_cache.lookup_gdb_index (build_id, &dwz->index_cache_res);
> > }
> >
> > +/* Query debuginfod for the .gdb_index matching OBJFILE's build-id. Return the
> > + contents if successful. */
> > +
> > +static gdb::array_view<const gdb_byte>
> > +get_gdb_index_contents_from_debuginfod (objfile *objfile, dwarf2_per_bfd *per_bfd)
> > +{
> > + const bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
> > + if (build_id == nullptr)
> > + return {};
> > +
> > + gdb::unique_xmalloc_ptr<char> index_path;
> > + scoped_fd fd = debuginfod_section_query (build_id->data, build_id->size,
> > + bfd_get_filename
> > + (objfile->obfd.get ()),
> > + ".gdb_index",
> > + &index_path);
> > + if (fd.get () < 0)
> > + return {};
> > +
> > + return global_index_cache.lookup_gdb_index_debuginfod
> > + (index_path.get (), &per_bfd->index_cache_res);
> > +}
> > +
> > static quick_symbol_functions_up make_cooked_index_funcs ();
> >
> > /* See dwarf2/public.h. */
> > @@ -3440,10 +3492,102 @@ dwarf2_initialize_objfile (struct objfile *objfile)
> > return;
> > }
> >
> > + if ((objfile->flags & OBJF_DOWNLOAD_DEFERRED)
> > + && dwarf2_read_gdb_index (per_objfile,
> > + get_gdb_index_contents_from_debuginfod,
> > + nullptr))
> > + {
> > + dwarf_read_debug_printf ("found .gdb_index from debuginfod");
> > + objfile->qf.push_front (per_bfd->index_table->make_quick_functions ());
> > + objfile->qf.begin ()->get ()->from_separate_index = true;
> > + return;
> > + }
> > +
> > global_index_cache.miss ();
> > objfile->qf.push_front (make_cooked_index_funcs ());
> > }
> >
> > +/* See read.h. */
> > +
> > +void
> > +read_full_dwarf_from_debuginfod (struct objfile *objfile,
> > + dwarf2_base_index_functions *fncs)
> > +{
> > + gdb_assert (objfile->flags & OBJF_DOWNLOAD_DEFERRED);
> > +
> > + const struct bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
> > + const char *filename;
> > + gdb_bfd_ref_ptr debug_bfd;
> > + gdb::unique_xmalloc_ptr<char> symfile_path;
> > + scoped_fd fd;
> > +
> > + if (build_id == nullptr)
> > + goto unset;
> > +
> > + filename = bfd_get_filename (objfile->obfd.get ());
> > + fd = debuginfod_debuginfo_query (build_id->data, build_id->size,
> > + filename, &symfile_path);
> > + if (fd.get () < 0)
> > + goto unset;
> > +
> > + /* Separate debuginfo successfully retrieved from server. */
> > + 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 unset;
> > + }
> > +
> > + /* Clear frame data so it can be recalculated using DWARF. */
> > + dwarf2_clear_frame_data (objfile);
> > +
> > + /* This may also trigger a dwz download. */
> > + symbol_file_add_separate (debug_bfd, symfile_path.get (),
> > + current_inferior ()->symfile_flags, objfile);
> > +
> > +unset:
> > + objfile->remove_deferred_status ();
> > +}
> > +
> > +/* See public.h. */
> > +
> > +bool
> > +dwarf2_has_separate_index (struct objfile *objfile)
> > +{
> > + if (objfile->flags & OBJF_DOWNLOAD_DEFERRED)
> > + return true;
> > + if (objfile->flags & OBJF_MAINLINE)
> > + return false;
> > + if (!IS_DIR_SEPARATOR (*objfile_filename (objfile)))
> > + return false;
> > +
> > + gdb::unique_xmalloc_ptr<char> index_path;
> > + const bfd_build_id *build_id = build_id_bfd_get (objfile->obfd.get ());
> > +
> > + if (build_id == nullptr)
> > + return false;
> > +
> > + 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 false;
> > +
> > + /* We found a separate .gdb_index file so a separate debuginfo file
> > + should exist, but we don't want to download it until necessary.
> > + Attach the index to this objfile and defer the debuginfo download
> > + until gdb needs to expand symtabs referenced by the index. */
> > + objfile->flags |= OBJF_DOWNLOAD_DEFERRED;
> > + dwarf2_initialize_objfile (objfile);
> > + return true;
> > +}
> > +
> >
> >
> > /* Build a partial symbol table. */
> > diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
> > index dc7abf23ba4..6ed0be7203b 100644
> > --- a/gdb/dwarf2/read.h
> > +++ b/gdb/dwarf2/read.h
> > @@ -883,6 +883,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 *do_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
> > {
> > @@ -959,4 +963,10 @@ extern bool read_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
> > dwarf2_section_info *section,
> > addrmap *mutable_map);
> >
> > +/* If OBJFILE contains information from a separately downloaded .gdb_index,
> > + attempt to download the full debuginfo. */
> > +
> > +extern void read_full_dwarf_from_debuginfod (struct objfile *,
> > + dwarf2_base_index_functions *);
> > +
> > #endif /* DWARF2READ_H */
> > diff --git a/gdb/dwarf2/section.c b/gdb/dwarf2/section.c
> > index 1235f293f45..b674103c72f 100644
> > --- a/gdb/dwarf2/section.c
> > +++ b/gdb/dwarf2/section.c
> > @@ -54,7 +54,8 @@ 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)
> > + error (_("Can't find owner of DWARF section."));
> > return section->s.section->owner;
> > }
> >
> > diff --git a/gdb/elfread.c b/gdb/elfread.c
> > index 7900dfbc388..5c89598eee7 100644
> > --- a/gdb/elfread.c
> > +++ b/gdb/elfread.c
> > @@ -1235,7 +1235,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/frame.c b/gdb/frame.c
> > index 7077016ccba..00dbffed1ef 100644
> > --- a/gdb/frame.c
> > +++ b/gdb/frame.c
> > @@ -1892,6 +1892,13 @@ get_selected_frame (const char *message)
> > error (("%s"), message);
> >
> > lookup_selected_frame (selected_frame_id, selected_frame_level);
> > +
> > + /* It is possible for lookup_selected_frame to cause a new objfile
> > + to be loaded. Some objfile observers may choose to clear
> > + selected_frame when an objfile is loaded. Work around this by
> > + calling lookup_selected_frame again if the first try failed. */
> > + if (selected_frame == nullptr)
> > + lookup_selected_frame (selected_frame_id, selected_frame_level);
> > }
> > /* There is always a frame. */
> > gdb_assert (selected_frame != NULL);
> > diff --git a/gdb/objfile-flags.h b/gdb/objfile-flags.h
> > index 9dee2ee51a0..fb3f741c899 100644
> > --- a/gdb/objfile-flags.h
> > +++ b/gdb/objfile-flags.h
> > @@ -60,6 +60,10 @@ enum objfile_flag : unsigned
> > /* User requested that we do not read this objfile's symbolic
> > information. */
> > OBJF_READNEVER = 1 << 6,
> > +
> > + /* A separate .gdb_index has been downloaded for this objfile.
> > + Debuginfo for this objfile can be downloaded when required. */
> > + OBJF_DOWNLOAD_DEFERRED = 1 << 7,
> > };
> >
> > DEF_ENUM_FLAGS_TYPE (enum objfile_flag, objfile_flags);
> > diff --git a/gdb/objfiles.h b/gdb/objfiles.h
> > index c20b63ceadf..ea9bd2157dc 100644
> > --- a/gdb/objfiles.h
> > +++ b/gdb/objfiles.h
> > @@ -612,6 +612,26 @@ struct objfile
> > /* See quick_symbol_functions. */
> > void require_partial_symbols (bool verbose);
> >
> > + /* Indicate that the aquisition of this objfile's separate debug objfile
> > + is no longer deferred. Used when the debug objfile has been aquired
> > + or could not be found. */
> > + void remove_deferred_status ()
> > + {
> > + flags &= ~OBJF_DOWNLOAD_DEFERRED;
> > +
> > + /* Remove quick_symbol_functions derived from a separately downloaded
> > + index. If available the separate debug objfile's index will be used
> > + instead, since that objfile actually contains the symbols and CUs
> > + referenced in the index.
> > +
> > + No more than one element of qf should have from_separate_index set
> > + to true. */
> > + qf.remove_if ([&] (const quick_symbol_functions_up &qf_up)
> > + {
> > + return qf_up->from_separate_index;
> > + });
> > + }
> > +
> > /* Return the relocation offset applied to SECTION. */
> > CORE_ADDR section_offset (bfd_section *section) const
> > {
> > diff --git a/gdb/quick-symbol.h b/gdb/quick-symbol.h
> > index a7fea2ccb49..e7163503e39 100644
> > --- a/gdb/quick-symbol.h
> > +++ b/gdb/quick-symbol.h
> > @@ -225,6 +225,10 @@ struct quick_symbol_functions
> > virtual void read_partial_symbols (struct objfile *objfile)
> > {
> > }
> > +
> > + /* True if this quick_symbol_functions is derived from a separately
> > + downloaded index. */
> > + bool from_separate_index = false;
> > };
> >
> > typedef std::unique_ptr<quick_symbol_functions> quick_symbol_functions_up;
> > diff --git a/gdb/symfile.c b/gdb/symfile.c
> > index eebc5ea44b9..0491a33e8f5 100644
> > --- a/gdb/symfile.c
> > +++ b/gdb/symfile.c
> > @@ -991,6 +991,10 @@ syms_from_objfile (struct objfile *objfile,
> > static void
> > finish_new_objfile (struct objfile *objfile, symfile_add_flags add_flags)
> > {
> > + struct objfile *parent = objfile->separate_debug_objfile_backlink;
> > + bool was_deferred
> > + = (parent != nullptr) && (parent->flags & OBJF_DOWNLOAD_DEFERRED);
> > +
> > /* If this is the main symbol file we have to clean up all users of the
> > old main symbol file. Otherwise it is sufficient to fixup all the
> > breakpoints that may have been redefined by this symbol file. */
> > @@ -1001,7 +1005,8 @@ finish_new_objfile (struct objfile *objfile, symfile_add_flags add_flags)
> >
> > clear_symtab_users (add_flags);
> > }
> > - else if ((add_flags & SYMFILE_DEFER_BP_RESET) == 0)
> > + else if ((add_flags & SYMFILE_DEFER_BP_RESET) == 0
> > + && !was_deferred)
> > {
> > breakpoint_re_set ();
> > }
> > @@ -1122,6 +1127,12 @@ symbol_file_add_with_addrs (const gdb_bfd_ref_ptr &abfd, const char *name,
> > if (objfile->sf != nullptr)
> > finish_new_objfile (objfile, add_flags);
> >
> > + /* Remove deferred status now in case any observers trigger symtab
> > + expansion. Otherwise gdb might try to read parent for psymbols
> > + when it should read the separate debug objfile instead. */
> > + if (parent != nullptr && (parent->flags & OBJF_DOWNLOAD_DEFERRED))
> > + parent->remove_deferred_status ();
> > +
> > gdb::observers::new_objfile.notify (objfile);
> >
> > bfd_cache_close_all ();
> > diff --git a/gdb/symtab.c b/gdb/symtab.c
> > index 5ec56f4f2af..bd01a75189d 100644
> > --- a/gdb/symtab.c
> > +++ b/gdb/symtab.c
> > @@ -2925,14 +2925,30 @@ find_pc_sect_compunit_symtab (CORE_ADDR pc, struct obj_section *section)
> > if (best_cust != NULL)
> > return best_cust;
> >
> > + int warn_if_readin = 1;
> > +
> > /* Not found in symtabs, search the "quick" symtabs (e.g. psymtabs). */
> >
> > for (objfile *objf : current_program_space->objfiles ())
> > {
> > + bool was_deferred = objf->flags & OBJF_DOWNLOAD_DEFERRED;
> > +
> > struct compunit_symtab *result
> > - = objf->find_pc_sect_compunit_symtab (msymbol, pc, section, 1);
> > + = objf->find_pc_sect_compunit_symtab (msymbol, pc, section,
> > + warn_if_readin);
> > +
> > if (result != NULL)
> > return result;
> > +
> > + /* If objf's separate debug info was just acquired, disable
> > + warn_if_readin for the next iteration of this loop. This prevents
> > + a spurious warning in case an observer already triggered expansion
> > + of the separate debug objfile's symtabs. */
> > + if (was_deferred && objf->separate_debug_objfile != nullptr
> > + && (objf->flags & OBJF_DOWNLOAD_DEFERRED) == 0)
> > + warn_if_readin = 0;
> > + else if (warn_if_readin == 0)
> > + warn_if_readin = 1;
> > }
> >
> > return NULL;
> > diff --git a/gdb/testsuite/gdb.debuginfod/libsection1.c b/gdb/testsuite/gdb.debuginfod/libsection1.c
> > new file mode 100644
> > index 00000000000..60824b415c6
> > --- /dev/null
> > +++ b/gdb/testsuite/gdb.debuginfod/libsection1.c
> > @@ -0,0 +1,40 @@
> > +/* This testcase is part of GDB, the GNU debugger.
> > +
> > + Copyright 2023 Free Software Foundation, Inc.
> > +
> > + This program is free software; you can redistribute it and/or modify
> > + it under the terms of the GNU General Public License as published by
> > + the Free Software Foundation; either version 3 of the License, or
> > + (at your option) any later version.
> > +
> > + This program is distributed in the hope that it will be useful,
> > + but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + GNU General Public License for more details.
> > +
> > + You should have received a copy of the GNU General Public License
> > + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> > +
> > +#include <stdio.h>
> > +#include <pthread.h>
> > +#include <unistd.h>
> > +
> > +extern void libsection2_test ();
> > +extern void *libsection2_thread_test (void *);
> > +
> > +void
> > +libsection1_test ()
> > +{
> > + pthread_t thr;
> > +
> > + printf ("In libsection1\n");
> > + libsection2_test ();
> > +
> > + pthread_create (&thr, NULL, libsection2_thread_test, NULL);
> > +
> > + /* Give the new thread a chance to actually enter libsection2_thread_test. */
> > + sleep (3);
> > + printf ("Cancelling thread\n");
> > +
> > + pthread_cancel (thr);
> > +}
> > diff --git a/gdb/testsuite/gdb.debuginfod/libsection2.c b/gdb/testsuite/gdb.debuginfod/libsection2.c
> > new file mode 100644
> > index 00000000000..629a67f94a5
> > --- /dev/null
> > +++ b/gdb/testsuite/gdb.debuginfod/libsection2.c
> > @@ -0,0 +1,37 @@
> > +/* This testcase is part of GDB, the GNU debugger.
> > +
> > + Copyright 2023 Free Software Foundation, Inc.
> > +
> > + This program is free software; you can redistribute it and/or modify
> > + it under the terms of the GNU General Public License as published by
> > + the Free Software Foundation; either version 3 of the License, or
> > + (at your option) any later version.
> > +
> > + This program is distributed in the hope that it will be useful,
> > + but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + GNU General Public License for more details.
> > +
> > + You should have received a copy of the GNU General Public License
> > + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> > +
> > +#include <stdio.h>
> > +
> > +void
> > +libsection2_test ()
> > +{
> > + printf ("In libsection2\n");
> > +}
> > +
> > +void *
> > +libsection2_thread_test (void *arg)
> > +{
> > + (void) arg;
> > +
> > + printf ("In thread test\n");
> > +
> > + while (1)
> > + ;
> > +
> > + return NULL;
> > +}
> > diff --git a/gdb/testsuite/gdb.debuginfod/section.c b/gdb/testsuite/gdb.debuginfod/section.c
> > new file mode 100644
> > index 00000000000..d391a8f898e
> > --- /dev/null
> > +++ b/gdb/testsuite/gdb.debuginfod/section.c
> > @@ -0,0 +1,29 @@
> > +/* This testcase is part of GDB, the GNU debugger.
> > +
> > + Copyright 2023 Free Software Foundation, Inc.
> > +
> > + This program is free software; you can redistribute it and/or modify
> > + it under the terms of the GNU General Public License as published by
> > + the Free Software Foundation; either version 3 of the License, or
> > + (at your option) any later version.
> > +
> > + This program is distributed in the hope that it will be useful,
> > + but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + GNU General Public License for more details.
> > +
> > + You should have received a copy of the GNU General Public License
> > + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> > +
> > +#include <stdio.h>
> > +
> > +extern void libsection1_test ();
> > +
> > +int
> > +main()
> > +{
> > + libsection1_test ();
> > + printf ("in section exec\n");
> > +
> > + return 0;
> > +}
> > diff --git a/gdb/testsuite/gdb.debuginfod/section.exp b/gdb/testsuite/gdb.debuginfod/section.exp
> > new file mode 100644
> > index 00000000000..ff57c6e32b7
> > --- /dev/null
> > +++ b/gdb/testsuite/gdb.debuginfod/section.exp
> > @@ -0,0 +1,184 @@
> > +# Copyright 2023 Free Software Foundation, Inc.
> > +
> > +# This program is free software; you can redistribute it and/or modify
> > +# it under the terms of the GNU General Public License as published by
> > +# the Free Software Foundation; either version 3 of the License, or
> > +# (at your option) any later version.
> > +#
> > +# This program is distributed in the hope that it will be useful,
> > +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +# GNU General Public License for more details.
> > +#
> > +# You should have received a copy of the GNU General Public License
> > +# along with this program. If not, see <http://www.gnu.org/licenses/>.
> > +
> > +# Test debuginfod functionality
> > +
> > +standard_testfile
> > +
> > +load_lib debuginfod-support.exp
> > +
> > +require allow_debuginfod_tests
> > +
> > +set sourcetmp [standard_output_file tmp-${srcfile}]
> > +set outputdir [standard_output_file {}]
> > +
> > +# SECTEXEC is an executable which calls a function from LIB_SL1.
> > +set sectfile "section"
> > +set sectsrc $srcdir/$subdir/section.c
> > +set sectexec [standard_output_file $sectfile]
> > +
> > +# Solib LIB_SL1 calls functions from LIB_SL2.
> > +set libfile1 "libsection1"
> > +set libsrc1 $srcdir/$subdir/$libfile1.c
> > +set lib_sl1 [standard_output_file $libfile1.sl]
> > +
> > +set libfile2 "libsection2"
> > +set libsrc2 $srcdir/$subdir/$libfile2.c
> > +set lib_sl2 [standard_output_file $libfile2.sl]
> > +
> > +set lib_opts1 [list debug build-id shlib=$lib_sl2]
> > +set lib_opts2 [list debug build-id]
> > +set exec_opts [list debug build-id shlib=$lib_sl1 shlib=$lib_sl2]
> > +
> > +clean_restart
> > +
> > +if {[enable_section_downloads] == 0} {
> > + untested "GDB does not support debuginfod section downloads"
> > + return -1
> > +}
> > +
> > +# Compile SECTEXEC, LIB_SL1 and LIB_SL2.
> > +if { [gdb_compile_shlib $libsrc2 $lib_sl2 $lib_opts2] != "" } {
> > + untested "failed to compile $libfile2"
> > + return -1
> > +}
> > +
> > +if { [gdb_compile_shlib_pthreads $libsrc1 $lib_sl1 $lib_opts1] != "" } {
> > + untested "failed to compile $libfile1"
> > + return -1
> > +}
> > +
> > +if { [gdb_compile $sectsrc $sectexec executable $exec_opts] != "" } {
> > + untested "failed to compile $sectfile"
> > + return -1
> > +}
> > +
> > +# Add .gdb_index to solibs.
> > +if { [have_index $lib_sl1] != "gdb_index"
> > + && [add_gdb_index $lib_sl1] == 0 } {
> > + untested "failed to add .gdb_index to $libfile1"
> > + return -1
> > +}
> > +
> > +if { [have_index $lib_sl2] != "gdb_index"
> > + && [add_gdb_index $lib_sl2] == 0 } {
> > + untested "failed to add .gdb_index to $libfile2"
> > + return -1
> > +}
> > +
> > +# Strip solib debuginfo into separate files.
> > +if { [gdb_gnu_strip_debug $lib_sl1 ""] != 0} {
> > + fail "strip $lib_sl1 debuginfo"
> > + return -1
> > +}
> > +
> > +if { [gdb_gnu_strip_debug $lib_sl2 ""] != 0} {
> > + fail "strip $lib_sl2 debuginfo"
> > + return -1
> > +}
> > +
> > +# Move debuginfo files into directory that debuginfod will serve from.
> > +set debugdir [standard_output_file "debug"]
> > +set debuginfo_sl1 [standard_output_file $libfile1.sl.debug]
> > +set debuginfo_sl2 [standard_output_file $libfile2.sl.debug]
> > +
> > +file mkdir $debugdir
> > +file rename -force $debuginfo_sl1 $debugdir
> > +file rename -force $debuginfo_sl2 $debugdir
> > +
> > +# Restart GDB and clear the debuginfod client cache. Then load BINFILE into
> > +# GDB and start running it. Match output with pattern RES and use TESTNAME
> > +# as the test name.
> > +proc_with_prefix clean_restart_with_prompt { binfile res testname } {
> > + global cache
> > +
> > + # Delete client cache so debuginfo downloads again.
> > + file delete -force $cache
> > + clean_restart
> > +
> > + gdb_test "set debuginfod enabled on" "" "clean_restart enable $testname"
> > + gdb_load $binfile
> > +
> > + if {![runto_main]} {
> > + return
> > + }
> > +}
> > +
> > +# Tests with no debuginfod server running.
> > +proc_with_prefix no_url { } {
> > + global sectexec libfile1 libfile2
> > +
> > + gdb_load $sectexec
> > + if {![runto_main]} {
> > + return
> > + }
> > +
> > + # Check that no section is downloaded and no debuginfo is found.
> > + gdb_test "info sharedlibrary" ".*Yes \\(\\*\\).*$libfile1.*" \
> > + "found no url lib1"
> > + gdb_test "info sharedlibrary" ".*Yes \\(\\*\\).*$libfile2.*" \
> > + "found no url lib2"
> > +}
> > +
> > +# Tests with a debuginfod server running.
> > +proc_with_prefix local_url { } {
> > + global sectexec
> > + global libsrc1 lib_sl1 libfile1
> > + global libsrc2 lib_sl2 libfile2
> > + global debugdir db
> > +
> > + set url [start_debuginfod $db $debugdir]
> > + if { $url == "" } {
> > + unresolved "failed to start debuginfod server"
> > + return
> > + }
> > +
> > + # Point GDB to the server.
> > + setenv DEBUGINFOD_URLS $url
> > +
> > + # Download .gdb_index for solibs.
> > + set res ".*section \.gdb_index for $lib_sl1.*\
> > + section \.gdb_index for $lib_sl2.*"
> > + clean_restart_with_prompt $sectexec $res "index"
> > +
> > + # Download debuginfo when stepping into a function.
> > + set res ".*separate debug info for $lib_sl1.*\"In ${libfile1}\\\\n\".*"
> > + gdb_test "step" $res "step"
> > +
> > + clean_restart_with_prompt $sectexec "" "break"
> > +
> > + # Download debuginfo when setting a breakpoint.
> > + set res "Download.*separate debug info for $lib_sl2.*"
> > + gdb_test "br libsection2_test" $res "break set"
> > +
> > + # Hit the breakpoint.
> > + set res ".*Breakpoint 2, libsection2_test.*\"In ${libfile2}\\\\n\".*"
> > + gdb_test "c" $res "break continue"
> > +
> > + # Check that download progress message is correctly formatted
> > + # during backtrace.
> > + set res ".*debug info for $lib_sl1\.\.\.\r\n\#1.*"
> > + gdb_test "bt" $res "break backtrace"
> > +}
> > +
> > +# Create CACHE and DB directories ready for debuginfod to use.
> > +prepare_for_debuginfod cache db
> > +
> > +with_debuginfod_env $cache {
> > + no_url
> > + local_url
> > +}
> > +
> > +stop_debuginfod
> > diff --git a/gdb/testsuite/lib/debuginfod-support.exp b/gdb/testsuite/lib/debuginfod-support.exp
> > index 50a8b512a4a..e0b3dc39f51 100644
> > --- a/gdb/testsuite/lib/debuginfod-support.exp
> > +++ b/gdb/testsuite/lib/debuginfod-support.exp
> > @@ -113,6 +113,8 @@ proc with_debuginfod_env { cache body } {
> > proc start_debuginfod { db debugdir } {
> > global debuginfod_spawn_id spawn_id
> >
> > + set logfile [standard_output_file "server_log"]
> > +
> > # Find an unused port.
> > set port 7999
> > set found false
> > @@ -127,7 +129,8 @@ proc start_debuginfod { db debugdir } {
> > set old_spawn_id $spawn_id
> > }
> >
> > - spawn debuginfod -vvvv -d $db -p $port -F $debugdir
> > + spawn sh -c "debuginfod -vvvv -d $db -p $port -F $debugdir 2>&1 \
> > + | tee $logfile"
> > set debuginfod_spawn_id $spawn_id
> >
> > if { [info exists old_spawn_id] } {
> > @@ -194,3 +197,25 @@ proc stop_debuginfod { } {
> > unset debuginfod_spawn_id
> > }
> > }
> > +
> > +# Return 1 if gdb is configured to download ELF/DWARF sections from
> > +# debuginfod servers. Otherwise return 0.
> > +proc enable_section_downloads { } {
> > + global gdb_prompt
> > +
> > + set cmd "maint set debuginfod download-sections on"
> > + set msg "enable section downloads"
> > +
> > + gdb_test_multiple $cmd $msg {
> > + -re -wrap ".*not compiled into GDB.*" {
> > + return 0
> > + }
> > + -re -wrap "^" {
> > + return 1
> > + }
> > + -re -wrap "" {
> > + fail "$gdb_test_name (unexpected output)"
> > + return 0
> > + }
> > + }
> > +}
> > --
> > 2.41.0
> >
next prev parent reply other threads:[~2023-11-20 18:39 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-28 0:20 [PATCH 0/4] On-demand " Aaron Merey
2023-10-28 0:20 ` [PATCH 1/4 v7] gdb: Buffer output streams during events that might download debuginfo Aaron Merey
2023-11-12 20:20 ` Aaron Merey
2023-11-20 18:38 ` [PING*2][PATCH " Aaron Merey
2023-11-30 16:29 ` [PING*3][PATCH " Aaron Merey
2023-12-12 15:00 ` [PING*4][PATCH " Aaron Merey
2023-12-20 14:57 ` [PING*5][PATCH " Aaron Merey
2023-12-26 16:28 ` [PATCH " Thiago Jung Bauermann
2024-01-17 17:49 ` Aaron Merey
2024-01-17 18:05 ` Andrew Burgess
2023-10-28 0:20 ` [PATCH 2/4 v2] gdb/progspace: Add reverse safe iterator and template for unwrapping iterator Aaron Merey
2023-11-12 20:20 ` Aaron Merey
2023-11-20 18:39 ` [PING*2][PATCH " Aaron Merey
2023-11-30 16:30 ` [PING*3][PATCH " Aaron Merey
2023-12-12 15:01 ` [PING*4][PATCH " Aaron Merey
2023-12-20 14:57 ` [PING*5][PATCH " Aaron Merey
2023-12-26 17:09 ` [PATCH " Thiago Jung Bauermann
2023-10-28 0:20 ` [PATCH 3/4 v4] gdb/debuginfod: Support on-demand debuginfo downloading Aaron Merey
2023-11-12 20:20 ` Aaron Merey
2023-11-20 18:39 ` Aaron Merey [this message]
2023-11-30 16:30 ` [PING*3][PATCH " Aaron Merey
2023-12-12 15:01 ` [PING*4][PATCH " Aaron Merey
2023-12-20 14:57 ` [PING*5][PATCH " Aaron Merey
2023-12-26 18:35 ` [PATCH " Thiago Jung Bauermann
2023-10-28 0:20 ` [PATCH 4/4 v5] gdb/debuginfod: Add .debug_line downloading Aaron Merey
2023-11-12 20:21 ` Aaron Merey
2023-11-20 18:40 ` [PING*2][PATCH " Aaron Merey
2023-11-30 16:30 ` [PING*3][PATCH " Aaron Merey
2023-12-12 15:08 ` [PING*4][PATCH " Aaron Merey
2023-12-20 14:58 ` [PING*5][PATCH " Aaron Merey
2023-12-27 0:30 ` [PATCH " Thiago Jung Bauermann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAJDtP-Qko6KCQxYRVsAWHMW0s3PxMbUTpfCcJJUr7OcNo+t-8w@mail.gmail.com \
--to=amerey@redhat.com \
--cc=aburgess@redhat.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).