extern gdb::optional<int> ext_lang_print_insn
(struct gdbarch *gdbarch, CORE_ADDR address, struct disassemble_info *info);
+/* When GDB calls into an extension language because an objfile was
+ discovered for which GDB couldn't find any debug information, this
+ structure holds the result that the extension language returns.
+
+ There are three possible actions that might be returned by an extension;
+ first an extension can return a filename, this is the path to the file
+ containing the required debug information. The second possibility is
+ to return a flag indicating that GDB should check again for the missing
+ debug information, this would imply that the extension has installed
+ the debug information into a location where GDB can be expected to find
+ it. And the third option is for the extension to just return a null
+ result, indication there is nothing the extension can do to provide the
+ missing debug information. */
+struct ext_lang_missing_debuginfo_result
+{
+ /* Default result. The extension was unable to provide the missing debug
+ info. */
+ ext_lang_missing_debuginfo_result ()
+ { /* Nothing. */ }
+
+ /* When TRY_AGAIN is true GDB should try searching again, the extension
+ may have installed the missing debug info into a suitable location.
+ When TRY_AGAIN is false this is equivalent to the default, no
+ argument, constructor. */
+ ext_lang_missing_debuginfo_result (bool try_again)
+ : m_try_again (try_again)
+ { /* Nothing. */ }
+
+ /* Look in FILENAME for the missing debug info. */
+ ext_lang_missing_debuginfo_result (std::string &&filename)
+ : m_filename (std::move (filename))
+ { /* Nothing. */ }
+
+ /* The filename where GDB can find the missing debuginfo. This is empty
+ if the extension didn't suggest a file that can be used. */
+ const std::string &
+ filename () const
+ {
+ return m_filename;
+ }
+
+ /* Returns true if GDB should look again for the debug information. */
+ const bool
+ try_again () const
+ {
+ return m_try_again;
+ }
+
+private:
+ /* The filename where the missing debuginfo can now be found. */
+ std::string m_filename;
+
+ /* When true GDB will search again for the debuginfo using its standard
+ techniques. When false GDB will not search again. */
+ bool m_try_again = false;
+};
+
+/* Called when GDB failed to find any debug information for OBJFILE. */
+
+extern ext_lang_missing_debuginfo_result ext_lang_handle_missing_debuginfo
+ (struct objfile *objfile);
+
#if GDB_SELF_TEST
namespace selftests {
extern void (*hook_set_active_ext_lang) ();
bool
objfile::find_and_add_separate_symbol_file (symfile_add_flags symfile_flags)
{
- bool has_dwarf = false;
-
- deferred_warnings warnings;
-
- gdb_bfd_ref_ptr debug_bfd;
- std::string filename;
-
- std::tie (debug_bfd, filename) = simple_find_and_open_separate_symbol_file
- (this, find_separate_debug_file_by_buildid, &warnings);
-
- if (debug_bfd == nullptr)
- std::tie (debug_bfd, filename)
- = simple_find_and_open_separate_symbol_file
- (this, find_separate_debug_file_by_debuglink, &warnings);
+ bool has_dwarf2 = false;
+
+ /* Usually we only make a single pass when looking for separate debug
+ information. However, it is possible for an extension language hook
+ to request that GDB make a second pass, in which case max_attempts
+ will be updated, and the loop restarted. */
+ for (unsigned attempt = 0, max_attempts = 1;
+ attempt < max_attempts && !has_dwarf2;
+ ++attempt)
+ {
+ gdb_assert (max_attempts <= 2);
+
+ deferred_warnings warnings;
+ gdb_bfd_ref_ptr debug_bfd;
+ std::string filename;
+
+ std::tie (debug_bfd, filename)
+ = simple_find_and_open_separate_symbol_file
+ (this, find_separate_debug_file_by_buildid, &warnings);
+
+ if (debug_bfd == nullptr)
+ std::tie (debug_bfd, filename)
+ = simple_find_and_open_separate_symbol_file
+ (this, find_separate_debug_file_by_debuglink, &warnings);
+
+ /* Only try debuginfod on the first attempt. Sure, we could imagine
+ an extension that somehow adds the required debug info to the
+ debuginfod server but, at least for now, we don't support this
+ scenario. Better for the extension to return new debug info
+ directly to GDB. Plus, going to the debuginfod server might be
+ slow, so that's a good argument for only doing this once. */
+ if (debug_bfd == nullptr && attempt == 0)
+ std::tie (debug_bfd, filename)
+ = debuginfod_find_and_open_separate_symbol_file (this);
+
+ if (debug_bfd != nullptr)
+ {
+ /* We found a separate debug info symbol file. If this is our
+ first attempt then setting HAS_DWARF2 will cause us to break
+ from the attempt loop. */
+ symbol_file_add_separate (debug_bfd, filename.c_str (),
+ symfile_flags, this);
+ has_dwarf2 = true;
+ }
+ else if (attempt == 0)
+ {
+ /* Failed to find a separate debug info symbol file. Call out to
+ the extension languages. The user might have registered an
+ extension that can find the debug info for us, or maybe give
+ the user a system specific message that guides them to finding
+ the missing debug info. */
+
+ ext_lang_missing_debuginfo_result ext_result
+ = ext_lang_handle_missing_debuginfo (this);
+ if (!ext_result.filename ().empty ())
+ {
+ /* Extension found a suitable debug file for us. */
+ debug_bfd
+ = symfile_bfd_open_no_error (ext_result.filename ().c_str ());
- if (debug_bfd == nullptr)
- std::tie (debug_bfd, filename)
- = debuginfod_find_and_open_separate_symbol_file (this);
+ if (debug_bfd != nullptr)
+ {
+ symbol_file_add_separate (debug_bfd,
+ ext_result.filename ().c_str (),
+ symfile_flags, this);
+ has_dwarf2 = true;
+ }
+ }
+ else if (ext_result.try_again ())
+ {
+ max_attempts = 2;
+ continue;
+ }
+ }
- if (debug_bfd != nullptr)
- {
- symbol_file_add_separate (debug_bfd, filename.c_str (), symfile_flags,
- this);
- has_dwarf = true;
+ /* If we still have not got a separate debug symbol file, then
+ emit any warnings we've collected so far. */
+ if (!has_dwarf2)
+ warnings.emit ();
}
- /* If we still have not got a separate debug symbol file, then
- emit any warnings we've collected so far. */
- if (!has_dwarf)
- warnings.emit ();
-
- return has_dwarf;
+ return has_dwarf2;
}
\f