aboutsummaryrefslogtreecommitdiff
path: root/gdb/dwarf2/dwz.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/dwarf2/dwz.c')
-rw-r--r--gdb/dwarf2/dwz.c253
1 files changed, 191 insertions, 62 deletions
diff --git a/gdb/dwarf2/dwz.c b/gdb/dwarf2/dwz.c
index f36d6a6..1aa0d03 100644
--- a/gdb/dwarf2/dwz.c
+++ b/gdb/dwarf2/dwz.c
@@ -1,6 +1,6 @@
/* DWARF DWZ handling for GDB.
- Copyright (C) 2003-2024 Free Software Foundation, Inc.
+ Copyright (C) 2003-2025 Free Software Foundation, Inc.
This file is part of GDB.
@@ -21,6 +21,7 @@
#include "build-id.h"
#include "debuginfod-support.h"
+#include "dwarf2/leb.h"
#include "dwarf2/read.h"
#include "dwarf2/sect-names.h"
#include "filenames.h"
@@ -34,15 +35,17 @@
const char *
dwz_file::read_string (struct objfile *objfile, LONGEST str_offset)
{
- str.read (objfile);
+ /* This must be true because the sections are read in when the
+ dwz_file is created. */
+ gdb_assert (str.readin);
if (str.buffer == NULL)
- error (_("DW_FORM_GNU_strp_alt used without .debug_str "
+ error (_("supplementary DWARF file missing .debug_str "
"section [in module %s]"),
this->filename ());
if (str_offset >= str.size)
- error (_("DW_FORM_GNU_strp_alt pointing outside of "
- ".debug_str section [in module %s]"),
+ error (_("invalid string reference to supplementary DWARF file "
+ "[in module %s]"),
this->filename ());
gdb_assert (HOST_CHAR_BIT == 8);
if (str.buffer[str_offset] == '\0')
@@ -53,36 +56,171 @@ dwz_file::read_string (struct objfile *objfile, LONGEST str_offset)
/* A helper function to find the sections for a .dwz file. */
static void
-locate_dwz_sections (struct objfile *objfile, bfd *abfd, asection *sectp,
- dwz_file *dwz_file)
+locate_dwz_sections (objfile *objfile, dwz_file &dwz_file)
{
- dwarf2_section_info *sect = nullptr;
+ for (asection *sec : gdb_bfd_sections (dwz_file.dwz_bfd))
+ {
+ dwarf2_section_info *sect = nullptr;
- /* Note that we only support the standard ELF names, because .dwz
+ /* 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))
- sect = &dwz_file->abbrev;
- else if (dwarf2_elf_names.info.matches (sectp->name))
- sect = &dwz_file->info;
- else if (dwarf2_elf_names.str.matches (sectp->name))
- sect = &dwz_file->str;
- else if (dwarf2_elf_names.line.matches (sectp->name))
- sect = &dwz_file->line;
- else if (dwarf2_elf_names.macro.matches (sectp->name))
- sect = &dwz_file->macro;
- else if (dwarf2_elf_names.gdb_index.matches (sectp->name))
- sect = &dwz_file->gdb_index;
- else if (dwarf2_elf_names.debug_names.matches (sectp->name))
- sect = &dwz_file->debug_names;
- else if (dwarf2_elf_names.types.matches (sectp->name))
- sect = &dwz_file->types;
-
- if (sect != nullptr)
+ if (dwarf2_elf_names.abbrev.matches (sec->name))
+ sect = &dwz_file.abbrev;
+ else if (dwarf2_elf_names.info.matches (sec->name))
+ sect = &dwz_file.info;
+ else if (dwarf2_elf_names.str.matches (sec->name))
+ sect = &dwz_file.str;
+ else if (dwarf2_elf_names.line.matches (sec->name))
+ sect = &dwz_file.line;
+ else if (dwarf2_elf_names.macro.matches (sec->name))
+ sect = &dwz_file.macro;
+ else if (dwarf2_elf_names.gdb_index.matches (sec->name))
+ sect = &dwz_file.gdb_index;
+ else if (dwarf2_elf_names.debug_names.matches (sec->name))
+ sect = &dwz_file.debug_names;
+ else if (dwarf2_elf_names.types.matches (sec->name))
+ sect = &dwz_file.types;
+
+ if (sect != nullptr)
+ {
+ sect->s.section = sec;
+ sect->size = bfd_section_size (sec);
+ sect->read (objfile);
+ }
+ }
+}
+
+/* Helper that throws an exception when reading the .debug_sup
+ section. */
+
+static void
+debug_sup_failure (const char *text, bfd *abfd)
+{
+ error (_("%s [in modules %s]"), text, bfd_get_filename (abfd));
+}
+
+/* Look for the .debug_sup section and read it. If the section does
+ not exist, this returns false. If the section does exist but fails
+ to parse for some reason, an exception is thrown. Otherwise, if
+ everything goes well, this returns true and fills in the out
+ parameters. */
+
+static bool
+get_debug_sup_info (bfd *abfd,
+ std::string *filename,
+ size_t *buildid_len,
+ gdb::unique_xmalloc_ptr<bfd_byte> *buildid)
+{
+ asection *sect = bfd_get_section_by_name (abfd, ".debug_sup");
+ if (sect == nullptr)
+ return false;
+
+ bfd_byte *contents;
+ if (!bfd_malloc_and_get_section (abfd, sect, &contents))
+ debug_sup_failure (_("could not read .debug_sup section"), abfd);
+
+ gdb::unique_xmalloc_ptr<bfd_byte> content_holder (contents);
+ bfd_size_type size = bfd_section_size (sect);
+
+ /* Version of this section. */
+ if (size < 4)
+ debug_sup_failure (_(".debug_sup section too short"), abfd);
+ unsigned int version = read_2_bytes (abfd, contents);
+ contents += 2;
+ size -= 2;
+ if (version != 5)
+ debug_sup_failure (_(".debug_sup has wrong version number"), abfd);
+
+ /* Skip the is_supplementary value. We already ensured there were
+ enough bytes, above. */
+ ++contents;
+ --size;
+
+ /* The spec says that in the supplementary file, this must be \0,
+ but it doesn't seem very important. */
+ const char *fname = (const char *) contents;
+ size_t len = strlen (fname) + 1;
+ if (filename != nullptr)
+ *filename = fname;
+ contents += len;
+ size -= len;
+
+ if (size == 0)
+ debug_sup_failure (_(".debug_sup section missing ID"), abfd);
+
+ unsigned int bytes_read;
+ *buildid_len = read_unsigned_leb128 (abfd, contents, &bytes_read);
+ contents += bytes_read;
+ size -= bytes_read;
+
+ if (size < *buildid_len)
+ debug_sup_failure (_("extra data after .debug_sup section ID"), abfd);
+
+ if (*buildid_len != 0)
+ buildid->reset ((bfd_byte *) xmemdup (contents, *buildid_len,
+ *buildid_len));
+
+ return true;
+}
+
+/* Validate that ABFD matches the given BUILDID. If DWARF5 is true,
+ then this is done by examining the .debug_sup data. */
+
+static bool
+verify_id (bfd *abfd, size_t len, const bfd_byte *buildid, bool dwarf5)
+{
+ if (!bfd_check_format (abfd, bfd_object))
+ return false;
+
+ if (dwarf5)
{
- sect->s.section = sectp;
- sect->size = bfd_section_size (sectp);
- sect->read (objfile);
+ size_t new_len;
+ gdb::unique_xmalloc_ptr<bfd_byte> new_id;
+
+ if (!get_debug_sup_info (abfd, nullptr, &new_len, &new_id))
+ return false;
+ return (len == new_len
+ && memcmp (buildid, new_id.get (), len) == 0);
}
+ else
+ return build_id_verify (abfd, len, buildid);
+}
+
+/* Find either the .debug_sup or .gnu_debugaltlink section and return
+ its contents. Returns true on success and sets out parameters, or
+ false if nothing is found. */
+
+static bool
+read_alt_info (bfd *abfd, std::string *filename,
+ size_t *buildid_len,
+ gdb::unique_xmalloc_ptr<bfd_byte> *buildid,
+ bool *dwarf5)
+{
+ if (get_debug_sup_info (abfd, filename, buildid_len, buildid))
+ {
+ *dwarf5 = true;
+ return true;
+ }
+
+ bfd_size_type buildid_len_arg;
+ bfd_set_error (bfd_error_no_error);
+ bfd_byte *buildid_out;
+ gdb::unique_xmalloc_ptr<char> new_filename
+ (bfd_get_alt_debug_link_info (abfd, &buildid_len_arg,
+ &buildid_out));
+ if (new_filename == nullptr)
+ {
+ if (bfd_get_error () == bfd_error_no_error)
+ return false;
+ error (_("could not read '.gnu_debugaltlink' section: %s"),
+ bfd_errmsg (bfd_get_error ()));
+ }
+ *filename = new_filename.get ();
+
+ *buildid_len = buildid_len_arg;
+ buildid->reset (buildid_out);
+ *dwarf5 = false;
+ return true;
}
/* Attempt to find a .dwz file (whose full path is represented by
@@ -93,7 +231,7 @@ locate_dwz_sections (struct objfile *objfile, bfd *abfd, asection *sectp,
static gdb_bfd_ref_ptr
dwz_search_other_debugdirs (std::string &filename, bfd_byte *buildid,
- size_t buildid_len)
+ size_t buildid_len, bool dwarf5)
{
/* Let's assume that the path represented by FILENAME has the
"/.dwz/" subpath in it. This is what (most) GNU/Linux
@@ -161,7 +299,7 @@ dwz_search_other_debugdirs (std::string &filename, bfd_byte *buildid,
if (dwz_bfd == nullptr)
continue;
- if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
+ if (!verify_id (dwz_bfd.get (), buildid_len, buildid, dwarf5))
{
dwz_bfd.reset (nullptr);
continue;
@@ -177,11 +315,8 @@ dwz_search_other_debugdirs (std::string &filename, bfd_byte *buildid,
/* See dwz.h. */
void
-dwarf2_read_dwz_file (dwarf2_per_objfile *per_objfile)
+dwz_file::read_dwz_file (dwarf2_per_objfile *per_objfile)
{
- bfd_size_type buildid_len_arg;
- size_t buildid_len;
- bfd_byte *buildid;
dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
/* This may query the user via the debuginfod support, so it may
@@ -193,29 +328,22 @@ dwarf2_read_dwz_file (dwarf2_per_objfile *per_objfile)
/* Set this early, so that on error it remains NULL. */
per_bfd->dwz_file.emplace (nullptr);
- 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)
+ size_t buildid_len;
+ gdb::unique_xmalloc_ptr<bfd_byte> buildid;
+ std::string filename;
+ bool dwarf5;
+ if (!read_alt_info (per_bfd->obfd, &filename, &buildid_len, &buildid,
+ &dwarf5))
{
- if (bfd_get_error () == bfd_error_no_error)
- return;
- error (_("could not read '.gnu_debugaltlink' section: %s"),
- bfd_errmsg (bfd_get_error ()));
+ /* Nothing found, nothing to do. */
+ return;
}
- 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 (per_bfd->filename ());
- filename = ldirname (abs.get ()) + SLASH_STRING + filename;
+ filename = gdb_ldirname (abs.get ()) + SLASH_STRING + filename;
}
/* First try the file name given in the section. If that doesn't
@@ -223,25 +351,26 @@ dwarf2_read_dwz_file (dwarf2_per_objfile *per_objfile)
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))
+ if (!verify_id (dwz_bfd.get (), buildid_len, buildid.get (), dwarf5))
dwz_bfd.reset (nullptr);
}
if (dwz_bfd == NULL)
- dwz_bfd = build_id_to_debug_bfd (buildid_len, buildid);
+ dwz_bfd = build_id_to_debug_bfd (buildid_len, buildid.get ());
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);
+ dwz_bfd = dwz_search_other_debugdirs (filename, buildid.get (),
+ buildid_len, dwarf5);
}
if (dwz_bfd == nullptr)
{
gdb::unique_xmalloc_ptr<char> alt_filename;
scoped_fd fd
- = debuginfod_debuginfo_query (buildid, buildid_len,
+ = debuginfod_debuginfo_query (buildid.get (), buildid_len,
per_bfd->filename (), &alt_filename);
if (fd.get () >= 0)
@@ -252,20 +381,20 @@ dwarf2_read_dwz_file (dwarf2_per_objfile *per_objfile)
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))
+ else if (!verify_id (dwz_bfd.get (), buildid_len, buildid.get (),
+ dwarf5))
dwz_bfd.reset (nullptr);
}
}
if (dwz_bfd == NULL)
- error (_("could not find '.gnu_debugaltlink' file for %s"),
+ error (_("could not find supplementary DWARF file (%s) for %s"),
+ filename.c_str (),
per_bfd->filename ());
- auto result = std::make_unique<dwz_file> (std::move (dwz_bfd));
+ dwz_file_up result (new dwz_file (std::move (dwz_bfd)));
- for (asection *sec : gdb_bfd_sections (result->dwz_bfd))
- locate_dwz_sections (per_objfile->objfile, result->dwz_bfd.get (),
- sec, result.get ());
+ locate_dwz_sections (per_objfile->objfile, *result);
gdb_bfd_record_inclusion (per_bfd->obfd, result->dwz_bfd.get ());
bfd_cache_close (result->dwz_bfd.get ());