aboutsummaryrefslogtreecommitdiff
path: root/gdb/dwarf2/dwz.c
diff options
context:
space:
mode:
authorTom Tromey <tom@tromey.com>2021-03-06 09:26:39 -0700
committerTom Tromey <tom@tromey.com>2021-03-06 09:26:40 -0700
commit9938d15a01031e0aded4159adaa77d5b2b2319f6 (patch)
tree645f40859ccd77edd69dd75aaab6ad02b0d82729 /gdb/dwarf2/dwz.c
parent1803565556f36692a0d49e3c1aeae1595a64709d (diff)
downloadbinutils-9938d15a01031e0aded4159adaa77d5b2b2319f6.zip
binutils-9938d15a01031e0aded4159adaa77d5b2b2319f6.tar.gz
binutils-9938d15a01031e0aded4159adaa77d5b2b2319f6.tar.bz2
Move dwarf2_get_dwz_file to dwarf2/dwz.h
This moves dwarf2_get_dwz_file and some helper code to dwarf2/dwz.h. The main benefit of this is just shrinking dwarf2/read.c a little bit. gdb/ChangeLog 2021-03-06 Tom Tromey <tom@tromey.com> * dwarf2/sect-names.h (dwarf2_elf_names): Declare. * dwarf2/read.h (dwarf2_get_dwz_file): Move to dwz.h. * dwarf2/read.c (dwarf2_elf_names): No longer static. (locate_dwz_sections, dwz_search_other_debugdirs) (dwarf2_get_dwz_file): Move to dwz.c. * dwarf2/dwz.h (dwarf2_get_dwz_file): Move declaration from read.h. * dwarf2/dwz.c (locate_dwz_sections, dwz_search_other_debugdirs) (dwarf2_get_dwz_file): Move from read.c.
Diffstat (limited to 'gdb/dwarf2/dwz.c')
-rw-r--r--gdb/dwarf2/dwz.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/gdb/dwarf2/dwz.c b/gdb/dwarf2/dwz.c
index 6be2fa9..f9d5db6 100644
--- a/gdb/dwarf2/dwz.c
+++ b/gdb/dwarf2/dwz.c
@@ -20,6 +20,16 @@
#include "defs.h"
#include "dwarf2/dwz.h"
+#include "build-id.h"
+#include "debuginfod-support.h"
+#include "dwarf2/read.h"
+#include "dwarf2/sect-names.h"
+#include "filenames.h"
+#include "gdb_bfd.h"
+#include "gdbcore.h"
+#include "gdbsupport/pathstuff.h"
+#include "gdbsupport/scoped_fd.h"
+
const char *
dwz_file::read_string (struct objfile *objfile, LONGEST str_offset)
{
@@ -38,3 +48,235 @@ dwz_file::read_string (struct objfile *objfile, LONGEST str_offset)
return NULL;
return (const char *) (str.buffer + str_offset);
}
+
+/* A helper function to find the sections for a .dwz file. */
+
+static void
+locate_dwz_sections (bfd *abfd, asection *sectp, dwz_file *dwz_file)
+{
+ /* Note that we only support the standard ELF names, because .dwz
+ is ELF-only (at the time of writing). */
+ if (dwarf2_elf_names.abbrev.matches (sectp->name))
+ {
+ dwz_file->abbrev.s.section = sectp;
+ dwz_file->abbrev.size = bfd_section_size (sectp);
+ }
+ else if (dwarf2_elf_names.info.matches (sectp->name))
+ {
+ dwz_file->info.s.section = sectp;
+ dwz_file->info.size = bfd_section_size (sectp);
+ }
+ else if (dwarf2_elf_names.str.matches (sectp->name))
+ {
+ dwz_file->str.s.section = sectp;
+ dwz_file->str.size = bfd_section_size (sectp);
+ }
+ else if (dwarf2_elf_names.line.matches (sectp->name))
+ {
+ dwz_file->line.s.section = sectp;
+ dwz_file->line.size = bfd_section_size (sectp);
+ }
+ else if (dwarf2_elf_names.macro.matches (sectp->name))
+ {
+ dwz_file->macro.s.section = sectp;
+ dwz_file->macro.size = bfd_section_size (sectp);
+ }
+ else if (dwarf2_elf_names.gdb_index.matches (sectp->name))
+ {
+ dwz_file->gdb_index.s.section = sectp;
+ dwz_file->gdb_index.size = bfd_section_size (sectp);
+ }
+ else if (dwarf2_elf_names.debug_names.matches (sectp->name))
+ {
+ dwz_file->debug_names.s.section = sectp;
+ dwz_file->debug_names.size = bfd_section_size (sectp);
+ }
+}
+
+/* Attempt to find a .dwz file (whose full path is represented by
+ FILENAME) in all of the specified debug file directories provided.
+
+ Return the equivalent gdb_bfd_ref_ptr of the .dwz file found, or
+ nullptr if it could not find anything. */
+
+static gdb_bfd_ref_ptr
+dwz_search_other_debugdirs (std::string &filename, bfd_byte *buildid,
+ size_t buildid_len)
+{
+ /* Let's assume that the path represented by FILENAME has the
+ "/.dwz/" subpath in it. This is what (most) GNU/Linux
+ distributions do, anyway. */
+ size_t dwz_pos = filename.find ("/.dwz/");
+
+ if (dwz_pos == std::string::npos)
+ return nullptr;
+
+ /* This is an obvious assertion, but it's here more to educate
+ future readers of this code that FILENAME at DWZ_POS *must*
+ contain a directory separator. */
+ gdb_assert (IS_DIR_SEPARATOR (filename[dwz_pos]));
+
+ gdb_bfd_ref_ptr dwz_bfd;
+ std::vector<gdb::unique_xmalloc_ptr<char>> debugdir_vec
+ = dirnames_to_char_ptr_vec (debug_file_directory);
+
+ for (const gdb::unique_xmalloc_ptr<char> &debugdir : debugdir_vec)
+ {
+ /* The idea is to iterate over the
+ debug file directories provided by the user and
+ replace the hard-coded path in the "filename" by each
+ debug-file-directory.
+
+ For example, suppose that filename is:
+
+ /usr/lib/debug/.dwz/foo.dwz
+
+ And suppose that we have "$HOME/bar" as the
+ debug-file-directory. We would then adjust filename
+ to look like:
+
+ $HOME/bar/.dwz/foo.dwz
+
+ which would hopefully allow us to find the alt debug
+ file. */
+ std::string ddir = debugdir.get ();
+
+ if (ddir.empty ())
+ continue;
+
+ /* Make sure the current debug-file-directory ends with a
+ directory separator. This is needed because, if FILENAME
+ contains something like "/usr/lib/abcde/.dwz/foo.dwz" and
+ DDIR is "/usr/lib/abc", then could wrongfully skip it
+ below. */
+ if (!IS_DIR_SEPARATOR (ddir.back ()))
+ ddir += SLASH_STRING;
+
+ /* Check whether the beginning of FILENAME is DDIR. If it is,
+ then we are dealing with a file which we already attempted to
+ open before, so we just skip it and continue processing the
+ remaining debug file directories. */
+ if (filename.size () > ddir.size ()
+ && filename.compare (0, ddir.size (), ddir) == 0)
+ continue;
+
+ /* Replace FILENAME's default debug-file-directory with
+ DDIR. */
+ std::string new_filename = ddir + &filename[dwz_pos + 1];
+
+ dwz_bfd = gdb_bfd_open (new_filename.c_str (), gnutarget);
+
+ if (dwz_bfd == nullptr)
+ continue;
+
+ if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
+ {
+ dwz_bfd.reset (nullptr);
+ continue;
+ }
+
+ /* Found it. */
+ break;
+ }
+
+ return dwz_bfd;
+}
+
+/* See dwz.h. */
+
+struct dwz_file *
+dwarf2_get_dwz_file (dwarf2_per_bfd *per_bfd, bool require)
+{
+ bfd_size_type buildid_len_arg;
+ size_t buildid_len;
+ bfd_byte *buildid;
+
+ if (per_bfd->dwz_file != NULL)
+ return per_bfd->dwz_file.get ();
+
+ bfd_set_error (bfd_error_no_error);
+ gdb::unique_xmalloc_ptr<char> data
+ (bfd_get_alt_debug_link_info (per_bfd->obfd,
+ &buildid_len_arg, &buildid));
+ if (data == NULL)
+ {
+ if (bfd_get_error () == bfd_error_no_error)
+ {
+ if (!require)
+ return nullptr;
+ error (_("could not read '.gnu_debugaltlink' section"));
+ }
+ error (_("could not read '.gnu_debugaltlink' section: %s"),
+ bfd_errmsg (bfd_get_error ()));
+ }
+
+ gdb::unique_xmalloc_ptr<bfd_byte> buildid_holder (buildid);
+
+ buildid_len = (size_t) buildid_len_arg;
+
+ std::string filename = data.get ();
+
+ if (!IS_ABSOLUTE_PATH (filename.c_str ()))
+ {
+ gdb::unique_xmalloc_ptr<char> abs
+ = gdb_realpath (bfd_get_filename (per_bfd->obfd));
+
+ filename = ldirname (abs.get ()) + SLASH_STRING + filename;
+ }
+
+ /* First try the file name given in the section. If that doesn't
+ work, try to use the build-id instead. */
+ gdb_bfd_ref_ptr dwz_bfd (gdb_bfd_open (filename.c_str (), gnutarget));
+ if (dwz_bfd != NULL)
+ {
+ if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
+ dwz_bfd.reset (nullptr);
+ }
+
+ if (dwz_bfd == NULL)
+ dwz_bfd = build_id_to_debug_bfd (buildid_len, buildid);
+
+ if (dwz_bfd == nullptr)
+ {
+ /* If the user has provided us with different
+ debug file directories, we can try them in order. */
+ dwz_bfd = dwz_search_other_debugdirs (filename, buildid, buildid_len);
+ }
+
+ if (dwz_bfd == nullptr)
+ {
+ gdb::unique_xmalloc_ptr<char> alt_filename;
+ const char *origname = bfd_get_filename (per_bfd->obfd);
+
+ scoped_fd fd (debuginfod_debuginfo_query (buildid,
+ buildid_len,
+ origname,
+ &alt_filename));
+
+ if (fd.get () >= 0)
+ {
+ /* File successfully retrieved from server. */
+ dwz_bfd = gdb_bfd_open (alt_filename.get (), gnutarget);
+
+ if (dwz_bfd == nullptr)
+ warning (_("File \"%s\" from debuginfod cannot be opened as bfd"),
+ alt_filename.get ());
+ else if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
+ dwz_bfd.reset (nullptr);
+ }
+ }
+
+ if (dwz_bfd == NULL)
+ error (_("could not find '.gnu_debugaltlink' file for %s"),
+ bfd_get_filename (per_bfd->obfd));
+
+ std::unique_ptr<struct dwz_file> result
+ (new struct dwz_file (std::move (dwz_bfd)));
+
+ for (asection *sec : gdb_bfd_sections (result->dwz_bfd))
+ locate_dwz_sections (result->dwz_bfd.get (), sec, result.get ());
+
+ gdb_bfd_record_inclusion (per_bfd->obfd, result->dwz_bfd.get ());
+ per_bfd->dwz_file = std::move (result);
+ return per_bfd->dwz_file.get ();
+}