gdb: add extension hook ext_lang_find_objfile_from_buildid

Add a new ext_lang_find_objfile_from_buildid function which is called
from find_objfile_by_build_id and gives extension languages a chance
to find missing objfiles.

This commit adds the ext_lang_find_objfile_from_buildid function and
the extension_language_ops::find_objfile_from_buildid() hook, but does
not implement the hook for any extension languages, that will come in
the next commit.

This commit does rewrite find_objfile_by_build_id (build-id.c) to call
the new hook though.  The basic steps of find_objfile_by_build_id are
now this:

  1. Try to find the missing objfile using the build-id by looking in
  the debug-file-directory's .build-id/ sub-directory.  If we find the
  file then we're done.

  2. Ask debuginfod to download the missing file for us.  If we
  download the file successfully then we're done.

  3. Ask the extension language hook to find the file for us.  If the
  extension language asks us to try again then we repeat step (1) only
  and if we still don't have the file, we move to step (4).  If the
  extension language told us where the file is then we use that file
  and we're done.

  4. We didn't find the file.  Carry on without it.

Only step (3) is new in this logic, everything else was already done.

There are no tests added here as we can't currently write an extension
language callback.  The next commit will add the tests.

Approved-By: Tom Tromey <tom@tromey.com>
This commit is contained in:
Andrew Burgess 2024-07-31 15:54:52 +01:00
parent 629bcc68d7
commit ef1a41f20b
7 changed files with 126 additions and 25 deletions

View File

@ -28,6 +28,7 @@
#include "cli/cli-style.h"
#include "gdbsupport/scoped_fd.h"
#include "debuginfod-support.h"
#include "extension.h"
/* See build-id.h. */
@ -343,32 +344,73 @@ find_separate_debug_file_by_buildid (struct objfile *objfile,
/* See build-id.h. */
gdb_bfd_ref_ptr
find_objfile_by_build_id (const bfd_build_id *build_id,
find_objfile_by_build_id (program_space *pspace,
const bfd_build_id *build_id,
const char *expected_filename)
{
/* Try to find the executable (or shared object) by looking for a
(sym)link on disk from the build-id to the object file. */
gdb_bfd_ref_ptr abfd = build_id_to_exec_bfd (build_id->size,
build_id->data);
gdb_bfd_ref_ptr abfd;
if (abfd != nullptr)
return abfd;
/* Attempt to query debuginfod for the executable. */
gdb::unique_xmalloc_ptr<char> path;
scoped_fd fd = debuginfod_exec_query (build_id->data, build_id->size,
expected_filename, &path);
if (fd.get () >= 0)
for (unsigned attempt = 0, max_attempts = 1;
attempt < max_attempts && abfd == nullptr;
++attempt)
{
abfd = gdb_bfd_open (path.get (), gnutarget);
/* Try to find the executable (or shared object) by looking for a
(sym)link on disk from the build-id to the object file. */
abfd = build_id_to_exec_bfd (build_id->size, build_id->data);
if (abfd == nullptr)
warning (_("\"%ps\" from debuginfod cannot be opened as bfd: %s"),
styled_string (file_name_style.style (), path.get ()),
gdb_bfd_errmsg (bfd_get_error (), nullptr).c_str ());
else if (!build_id_verify (abfd.get (), build_id->size,
build_id->data))
abfd = nullptr;
if (abfd != nullptr || attempt > 0)
break;
/* Attempt to query debuginfod for the executable. This will only
get run during the first attempt, if an extension language hook
(see below) asked for a second attempt then we will have already
broken out of the loop above. */
gdb::unique_xmalloc_ptr<char> path;
scoped_fd fd = debuginfod_exec_query (build_id->data, build_id->size,
expected_filename, &path);
if (fd.get () >= 0)
{
abfd = gdb_bfd_open (path.get (), gnutarget);
if (abfd == nullptr)
warning (_("\"%ps\" from debuginfod cannot be opened as bfd: %s"),
styled_string (file_name_style.style (), path.get ()),
gdb_bfd_errmsg (bfd_get_error (), nullptr).c_str ());
else if (!build_id_verify (abfd.get (), build_id->size,
build_id->data))
abfd = nullptr;
}
if (abfd != nullptr)
break;
ext_lang_missing_file_result ext_result
= ext_lang_find_objfile_from_buildid (pspace, build_id,
expected_filename);
if (!ext_result.filename ().empty ())
{
/* The extension identified the file for us. */
abfd = gdb_bfd_open (ext_result.filename ().c_str (), gnutarget);
if (abfd == nullptr)
{
warning (_("\"%ps\" from extension cannot be opened as bfd: %s"),
styled_string (file_name_style.style (),
ext_result.filename ().c_str ()),
gdb_bfd_errmsg (bfd_get_error (), nullptr).c_str ());
break;
}
/* If the extension gave us a path to a file then we always
assume that it is the correct file, we do no additional check
of its build-id. */
}
else if (ext_result.try_again ())
{
/* The extension might have installed the file in the expected
location, we should try again. */
max_attempts = 2;
continue;
}
}
return abfd;

View File

@ -66,7 +66,8 @@ extern std::string find_separate_debug_file_by_buildid
should be the file we were looking for but couldn't find. */
extern gdb_bfd_ref_ptr find_objfile_by_build_id
(const bfd_build_id *build_id, const char *expected_filename);
(struct program_space *pspace, const bfd_build_id *build_id,
const char *expected_filename);
/* Return an hex-string representation of BUILD_ID. */

View File

@ -506,7 +506,8 @@ core_target::build_file_mappings ()
|| !bfd_check_format (abfd.get (), bfd_object))
&& file_data.build_id != nullptr)
{
abfd = find_objfile_by_build_id (file_data.build_id,
abfd = find_objfile_by_build_id (current_program_space,
file_data.build_id,
filename.c_str ());
if (abfd != nullptr)
@ -892,7 +893,8 @@ locate_exec_from_corefile_build_id (bfd *abfd, core_target *target,
}
gdb_bfd_ref_ptr execbfd
= find_objfile_by_build_id (build_id, filename.c_str ());
= find_objfile_by_build_id (current_program_space, build_id,
filename.c_str ());
if (execbfd != nullptr)
{

View File

@ -295,6 +295,19 @@ struct extension_language_ops
ext_lang_missing_file_result
(*handle_missing_debuginfo) (const struct extension_language_defn *,
struct objfile *objfile);
/* Give extension languages a chance to deal with missing objfiles.
PSPACE is the program space in which GDB is searching for a missing
objfile, and will not be NULL. BUILD_ID is the build-id of the
objfile we're looking for, and will not be NULL. FILENAME is the name
of the file we're looking for, and will not be NULL. See
ext_lang_find_objfile_from_buildid for some additional information
about the meaning of FILENAME. */
ext_lang_missing_file_result
(*find_objfile_from_buildid) (const struct extension_language_defn *,
program_space *pspace,
const struct bfd_build_id *build_id,
const char *filename);
};
/* State necessary to restore a signal handler to its previous value. */

View File

@ -1070,6 +1070,28 @@ ext_lang_handle_missing_debuginfo (struct objfile *objfile)
return {};
}
/* See extension.h. */
ext_lang_missing_file_result
ext_lang_find_objfile_from_buildid (program_space *pspace,
const struct bfd_build_id *build_id,
const char *filename)
{
for (const struct extension_language_defn *extlang : extension_languages)
{
if (extlang->ops == nullptr
|| extlang->ops->find_objfile_from_buildid == nullptr)
continue;
ext_lang_missing_file_result result
= extlang->ops->find_objfile_from_buildid (extlang, pspace, build_id,
filename);
if (!result.filename ().empty () || result.try_again ())
return result;
}
return {};
}
/* Called via an observer before gdb prints its prompt.
Iterate over the extension languages giving them a chance to
change the prompt. The first one to change the prompt wins,

View File

@ -36,6 +36,7 @@ struct ui_file;
struct ui_out;
struct value;
struct value_print_options;
struct program_space;
/* A function to load and process a script file.
The file has been opened and is ready to be read from the beginning.
@ -410,6 +411,25 @@ private:
extern ext_lang_missing_file_result ext_lang_handle_missing_debuginfo
(struct objfile *objfile);
/* Called when GDB opens a core-file to find any object files for which a
build-id could be extracted from the core-file, but the matching file
could not otherwise be found by GDB.
PSPACE is the program space in which GDB is opening the core-file and
is looking for a missing object file. BUILD_ID is the build-id of the
file being looked for, and will not be NULL. FILENAME is the name of
the file GDB is looking for, this will not be NULL. The FILENAME is
provided only for creating helpful messages for the user. FILENAME
might already exist on disk but have the wrong build-id, of FILENAME
might not exist on disk. If the missing objfile can be found then it
does not have to be placed at the location FILENAME.
The returned object indicates if the file could be found or not. */
extern ext_lang_missing_file_result ext_lang_find_objfile_from_buildid
(program_space *pspace, const struct bfd_build_id *build_id,
const char *filename);
#if GDB_SELF_TEST
namespace selftests {
extern void (*hook_set_active_ext_lang) ();

View File

@ -525,7 +525,8 @@ solib_map_sections (solib &so)
abfd = nullptr;
if (abfd == nullptr)
abfd = find_objfile_by_build_id (mapped_file_info->build_id (),
abfd = find_objfile_by_build_id (current_program_space,
mapped_file_info->build_id (),
so.so_name.c_str ());
if (abfd == nullptr && mismatch)