@@ -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);
-
- 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)
+ gdb_bfd_ref_ptr abfd;
+
+ for (unsigned attempt = 0, max_attempts = 1;
+ attempt < max_attempts && abfd == nullptr;
+ ++attempt)
{
- 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;
+ /* 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 || 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;
@@ -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. */
@@ -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)
{
@@ -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. */
@@ -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,
@@ -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 @@ struct ext_lang_missing_file_result
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) ();
@@ -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)