aboutsummaryrefslogtreecommitdiff
path: root/gdb/linux-tdep.c
diff options
context:
space:
mode:
authorAndrew Burgess <aburgess@redhat.com>2024-05-02 15:37:42 +0100
committerAndrew Burgess <aburgess@redhat.com>2024-12-24 14:15:25 +0000
commit44a61f1b9f1df069cb1e5de2cd3a1534280b33da (patch)
tree722b8103ef17ff9ea3aba79fd640f1a6656d93ea /gdb/linux-tdep.c
parentad24bc3b505517ee7a3f1d83a28e20710035fe3f (diff)
downloadfsf-binutils-gdb-44a61f1b9f1df069cb1e5de2cd3a1534280b33da.zip
fsf-binutils-gdb-44a61f1b9f1df069cb1e5de2cd3a1534280b33da.tar.gz
fsf-binutils-gdb-44a61f1b9f1df069cb1e5de2cd3a1534280b33da.tar.bz2
gdb: improve GDB's ability to auto-load the exec for a core file
GDB already has a limited mechanism for auto-loading the executable corresponding to a core file, this can be found in the function locate_exec_from_corefile_build_id in corelow.c. However, this approach uses the build-id of the core file to look in either the debug directory (for a symlink back to the executable) or by asking debuginfod. This is great, and works fine if the core file is a "system" binary, but often, when I'm debugging a core file, it's part of my development cycle, so there's no build-id symlink in the debug directory, and debuginfod doesn't know about the binary either, so GDB can't auto load the executable.... ... but the executable is right there! This commit builds on the earlier commits in this series to make GDB smarter. On GNU/Linux, when we parse the execution context from the core file (see linux-tdep.c), we already grab the command pointed to by AT_EXECFN. If this is an absolute path then GDB can use this to locate the executable, a build-id check ensures we've found the correct file. With this small change GDB suddenly becomes a lot better at auto-loading the executable for a core file. But we can do better! Often the AT_EXECFN is not an absolute path. If it is a relative path then we check for this path relative to the core file. This helps if a user does something like: $ ./build/bin/some_prog Aborted (core dumped) $ gdb -c corefile In this case the core file in the current directory will have an AT_EXECFN value of './build/bin/some_prog', so if we look for that path relative to the location of the core file this might result in a hit, again, a build-id check ensures we found the right file. But we can do better still! What if the user moves the core file? Or the user is using some tool to manage core files (e.g. the systemd core file management tool), and the user downloads the core file to a location from which the relative path no longer works? Well in this case we can make use of the core file's mapped file information (the NT_FILE note). The executable will be included in the mapped file list, and the path within the mapped file list will be an absolute path. We can search for mapped file information based on an address within the mapped file, and the auxv vector happens to include an AT_ENTRY value, which is the entry address in the main executable. If we look up the mapped file containing this address we'll have the absolute path to the main executable, a build-id check ensures this really is the file we're looking for. It might be tempting to jump straight to the third approach, however, there is one small downside to the third approach: if the executable is a symlink then the AT_EXECFN string will be the name of the symlink, that is, the thing the user asked to run. The mapped file entry will be the name of the actual file, i.e. the symlink target. When we auto-load the executable based on the third approach, the file loaded might have a different name to that which the user expects, though the build-id check (almost) guarantees that we've loaded the correct binary. But there's one more thing we can check for! If the user has placed the core file and the executable into a directory together, for example, as might happen with a bug report, then neither the absolute path check, nor the relative patch check will find the executable. So GDB will also look for a file with the right name in the same directory as the core file. Again, a build-id check is performed to ensure we find the correct file. Of course, it's still possible that GDB is unable to find the executable using any of these approaches. In this case, nothing changes, GDB will check in the debug info directory for a build-id based link back to the executable, and if that fails, GDB will ask debuginfod for the executable. If this all fails, then, as usual, the user is able to load the correct executable with the 'file' command, but hopefully, this should be needed far less from now on.
Diffstat (limited to 'gdb/linux-tdep.c')
-rw-r--r--gdb/linux-tdep.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 6d90e89..d3ab02d 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -2090,7 +2090,29 @@ linux_corefile_parse_exec_context_1 (struct gdbarch *gdbarch, bfd *cbfd)
if (execfn == nullptr)
return {};
+ /* When the core-file was loaded GDB processed the file backed mappings
+ (from the NT_FILE note). One of these should have been for the
+ executable. The AT_EXECFN string might not be an absolute path, but
+ the path in NT_FILE will be absolute, though if AT_EXECFN is a
+ symlink, then the NT_FILE entry will point to the actual file, not the
+ symlink.
+
+ Use the AT_ENTRY address to look for the NT_FILE entry which contains
+ that address, this should be the executable. */
+ gdb::unique_xmalloc_ptr<char> exec_filename;
+ CORE_ADDR exec_entry_addr;
+ if (target_auxv_search (contents, current_inferior ()->top_target (),
+ gdbarch, AT_ENTRY, &exec_entry_addr) == 1)
+ {
+ std::optional<core_target_mapped_file_info> info
+ = core_target_find_mapped_file (nullptr, exec_entry_addr);
+ if (info.has_value () && !info->filename ().empty ()
+ && IS_ABSOLUTE_PATH (info->filename ().c_str ()))
+ exec_filename = make_unique_xstrdup (info->filename ().c_str ());
+ }
+
return core_file_exec_context (std::move (execfn),
+ std::move (exec_filename),
std::move (arguments),
std::move (environment));
}