mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-28 18:10:46 +00:00
Handle DWARF 5 separate debug sections
DWARF 5 standardized the .gnu_debugaltlink section that dwz emits in multi-file mode. This is handled via some new forms, and a new .debug_sup section. This patch adds support for this to gdb. It is largely straightforward, I think, though one oddity is that I chose not to have this code search the system build-id directories for the supplementary file. My feeling was that, while it makes sense for a distro to unify the build-id concept with the hash stored in the .debug_sup section, there's no intrinsic need to do so. This in turn means that a few tests -- for example those that test the index cache -- will not work in this mode. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32808 Acked-By: Simon Marchi <simon.marchi@efficios.com>
This commit is contained in:
@@ -73,7 +73,8 @@ attribute::form_is_string () const
|
||||
|| form == DW_FORM_strx3
|
||||
|| form == DW_FORM_strx4
|
||||
|| form == DW_FORM_GNU_str_index
|
||||
|| form == DW_FORM_GNU_strp_alt);
|
||||
|| form == DW_FORM_GNU_strp_alt
|
||||
|| form == DW_FORM_strp_sup);
|
||||
}
|
||||
|
||||
/* See attribute.h. */
|
||||
@@ -190,6 +191,8 @@ attribute::form_is_unsigned () const
|
||||
{
|
||||
return (form == DW_FORM_ref_addr
|
||||
|| form == DW_FORM_GNU_ref_alt
|
||||
|| form == DW_FORM_ref_sup4
|
||||
|| form == DW_FORM_ref_sup8
|
||||
|| form == DW_FORM_data2
|
||||
|| form == DW_FORM_data4
|
||||
|| form == DW_FORM_data8
|
||||
|
||||
@@ -144,7 +144,9 @@ struct attribute
|
||||
|| form == DW_FORM_ref4
|
||||
|| form == DW_FORM_ref8
|
||||
|| form == DW_FORM_ref_udata
|
||||
|| form == DW_FORM_GNU_ref_alt);
|
||||
|| form == DW_FORM_GNU_ref_alt
|
||||
|| form == DW_FORM_ref_sup4
|
||||
|| form == DW_FORM_ref_sup8);
|
||||
}
|
||||
|
||||
/* Check if the attribute's form is a DW_FORM_block*
|
||||
@@ -168,6 +170,16 @@ struct attribute
|
||||
"reprocessing". */
|
||||
bool form_requires_reprocessing () const;
|
||||
|
||||
/* Check if attribute's form refers to the separate "dwz" file.
|
||||
This is only useful for references to the .debug_info section,
|
||||
not to the supplementary .debug_str section. */
|
||||
bool form_is_alt () const
|
||||
{
|
||||
return (form == DW_FORM_GNU_ref_alt
|
||||
|| form == DW_FORM_ref_sup4
|
||||
|| form == DW_FORM_ref_sup8);
|
||||
}
|
||||
|
||||
/* Return DIE offset of this attribute. Return 0 with complaint if
|
||||
the attribute is not of the required kind. */
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ cooked_indexer::scan_attributes (dwarf2_per_cu *scanning_per_cu,
|
||||
case DW_AT_abstract_origin:
|
||||
case DW_AT_extension:
|
||||
origin_offset = attr.get_ref_die_offset ();
|
||||
origin_is_dwz = attr.form == DW_FORM_GNU_ref_alt;
|
||||
origin_is_dwz = attr.form_is_alt ();
|
||||
break;
|
||||
|
||||
case DW_AT_external:
|
||||
@@ -423,7 +423,7 @@ cooked_indexer::index_imported_unit (cutu_reader *reader,
|
||||
if (attr.name == DW_AT_import)
|
||||
{
|
||||
sect_off = attr.get_ref_die_offset ();
|
||||
is_dwz = (attr.form == DW_FORM_GNU_ref_alt
|
||||
is_dwz = (attr.form_is_alt ()
|
||||
|| reader->cu ()->per_cu->is_dwz);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,8 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die)
|
||||
gdb_puts (hex_string (die->attrs[i].as_unsigned ()), f);
|
||||
break;
|
||||
case DW_FORM_GNU_ref_alt:
|
||||
case DW_FORM_ref_sup4:
|
||||
case DW_FORM_ref_sup8:
|
||||
gdb_printf (f, "alt ref address: ");
|
||||
gdb_puts (hex_string (die->attrs[i].as_unsigned ()), f);
|
||||
break;
|
||||
@@ -123,6 +125,7 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die)
|
||||
case DW_FORM_strx:
|
||||
case DW_FORM_GNU_str_index:
|
||||
case DW_FORM_GNU_strp_alt:
|
||||
case DW_FORM_strp_sup:
|
||||
gdb_printf (f, "string: \"%s\" (%s canonicalized)",
|
||||
die->attrs[i].as_string ()
|
||||
? die->attrs[i].as_string () : "",
|
||||
|
||||
185
gdb/dwarf2/dwz.c
185
gdb/dwarf2/dwz.c
@@ -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"
|
||||
@@ -39,12 +40,12 @@ dwz_file::read_string (struct objfile *objfile, LONGEST str_offset)
|
||||
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')
|
||||
@@ -87,6 +88,139 @@ locate_dwz_sections (struct objfile *objfile, bfd *abfd, asection *sectp,
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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
|
||||
FILENAME) in all of the specified debug file directories provided.
|
||||
|
||||
@@ -95,7 +229,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
|
||||
@@ -163,7 +297,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;
|
||||
@@ -181,9 +315,6 @@ dwz_search_other_debugdirs (std::string &filename, bfd_byte *buildid,
|
||||
void
|
||||
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
|
||||
@@ -195,24 +326,17 @@ dwz_file::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 ());
|
||||
@@ -225,25 +349,26 @@ dwz_file::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)
|
||||
@@ -254,13 +379,15 @@ dwz_file::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 ());
|
||||
|
||||
dwz_file_up result (new dwz_file (std::move (dwz_bfd)));
|
||||
|
||||
@@ -34,8 +34,8 @@ struct dwz_file
|
||||
/* Open the separate '.dwz' debug file, if needed. This will set
|
||||
the appropriate field in the per-BFD structure. If the DWZ file
|
||||
exists, the relevant sections are read in as well. Throws an
|
||||
error if the .gnu_debugaltlink section exists but the file cannot
|
||||
be found. */
|
||||
exception if the .gnu_debugaltlink or .debug_sup section exists
|
||||
but is invalid or if the file cannot be found. */
|
||||
static void read_dwz_file (dwarf2_per_objfile *per_objfile);
|
||||
|
||||
const char *filename () const
|
||||
|
||||
@@ -259,6 +259,7 @@ skip_form_bytes (bfd *abfd, const gdb_byte *bytes, const gdb_byte *buffer_end,
|
||||
case DW_FORM_sec_offset:
|
||||
case DW_FORM_strp:
|
||||
case DW_FORM_GNU_strp_alt:
|
||||
case DW_FORM_strp_sup:
|
||||
bytes += offset_size;
|
||||
break;
|
||||
|
||||
|
||||
@@ -3896,11 +3896,13 @@ cutu_reader::skip_one_attribute (dwarf_form form, const gdb_byte *info_ptr)
|
||||
case DW_FORM_data4:
|
||||
case DW_FORM_ref4:
|
||||
case DW_FORM_strx4:
|
||||
case DW_FORM_ref_sup4:
|
||||
return info_ptr + 4;
|
||||
|
||||
case DW_FORM_data8:
|
||||
case DW_FORM_ref8:
|
||||
case DW_FORM_ref_sig8:
|
||||
case DW_FORM_ref_sup8:
|
||||
return info_ptr + 8;
|
||||
|
||||
case DW_FORM_data16:
|
||||
@@ -3913,6 +3915,7 @@ cutu_reader::skip_one_attribute (dwarf_form form, const gdb_byte *info_ptr)
|
||||
case DW_FORM_sec_offset:
|
||||
case DW_FORM_strp:
|
||||
case DW_FORM_GNU_strp_alt:
|
||||
case DW_FORM_strp_sup:
|
||||
return info_ptr + m_cu->header.offset_size;
|
||||
|
||||
case DW_FORM_exprloc:
|
||||
@@ -5023,7 +5026,7 @@ process_imported_unit_die (struct die_info *die, struct dwarf2_cu *cu)
|
||||
if (attr != NULL)
|
||||
{
|
||||
sect_offset sect_off = attr->get_ref_die_offset ();
|
||||
bool is_dwz = (attr->form == DW_FORM_GNU_ref_alt || cu->per_cu->is_dwz);
|
||||
bool is_dwz = attr->form_is_alt () || cu->per_cu->is_dwz;
|
||||
dwarf2_per_objfile *per_objfile = cu->per_objfile;
|
||||
dwarf2_per_cu *per_cu
|
||||
= dwarf2_find_containing_comp_unit (sect_off, is_dwz,
|
||||
@@ -14914,10 +14917,12 @@ cutu_reader::read_attribute_value (attribute *attr, unsigned form,
|
||||
info_ptr += 2;
|
||||
break;
|
||||
case DW_FORM_data4:
|
||||
case DW_FORM_ref_sup4:
|
||||
attr->set_unsigned (read_4_bytes (m_abfd, info_ptr));
|
||||
info_ptr += 4;
|
||||
break;
|
||||
case DW_FORM_data8:
|
||||
case DW_FORM_ref_sup8:
|
||||
attr->set_unsigned (read_8_bytes (m_abfd, info_ptr));
|
||||
info_ptr += 8;
|
||||
break;
|
||||
@@ -14969,6 +14974,7 @@ cutu_reader::read_attribute_value (attribute *attr, unsigned form,
|
||||
}
|
||||
[[fallthrough]];
|
||||
case DW_FORM_GNU_strp_alt:
|
||||
case DW_FORM_strp_sup:
|
||||
{
|
||||
dwz_file *dwz = per_objfile->per_bfd->get_dwz_file (true);
|
||||
LONGEST str_offset
|
||||
@@ -17251,6 +17257,7 @@ dwarf2_const_value_attr (const struct attribute *attr, struct type *type,
|
||||
case DW_FORM_strx:
|
||||
case DW_FORM_GNU_str_index:
|
||||
case DW_FORM_GNU_strp_alt:
|
||||
case DW_FORM_strp_sup:
|
||||
/* The string is already allocated on the objfile obstack, point
|
||||
directly to it. */
|
||||
*bytes = (const gdb_byte *) attr->as_string ();
|
||||
@@ -17457,7 +17464,7 @@ lookup_die_type (struct die_info *die, const struct attribute *attr,
|
||||
|
||||
/* First see if we have it cached. */
|
||||
|
||||
if (attr->form == DW_FORM_GNU_ref_alt)
|
||||
if (attr->form_is_alt ())
|
||||
{
|
||||
sect_offset sect_off = attr->get_ref_die_offset ();
|
||||
dwarf2_per_cu *per_cu
|
||||
@@ -18241,15 +18248,14 @@ follow_die_ref (struct die_info *src_die, const struct attribute *attr,
|
||||
struct dwarf2_cu *cu = *ref_cu;
|
||||
struct die_info *die;
|
||||
|
||||
if (attr->form != DW_FORM_GNU_ref_alt && src_die->sect_off == sect_off)
|
||||
if (!attr->form_is_alt () && src_die->sect_off == sect_off)
|
||||
{
|
||||
/* Self-reference, we're done. */
|
||||
return src_die;
|
||||
}
|
||||
|
||||
die = follow_die_offset (sect_off,
|
||||
(attr->form == DW_FORM_GNU_ref_alt
|
||||
|| cu->per_cu->is_dwz),
|
||||
attr->form_is_alt () || cu->per_cu->is_dwz,
|
||||
ref_cu);
|
||||
if (!die)
|
||||
error (_(DWARF_ERROR_PREFIX
|
||||
@@ -18460,6 +18466,7 @@ dwarf2_fetch_constant_bytes (sect_offset sect_off,
|
||||
case DW_FORM_strx:
|
||||
case DW_FORM_GNU_str_index:
|
||||
case DW_FORM_GNU_strp_alt:
|
||||
case DW_FORM_strp_sup:
|
||||
/* The string is already allocated on the objfile obstack, point
|
||||
directly to it. */
|
||||
{
|
||||
|
||||
@@ -533,9 +533,9 @@ struct dwarf2_per_bfd
|
||||
}
|
||||
|
||||
/* Return the separate '.dwz' debug file. If there is no
|
||||
.gnu_debugaltlink section in the file, then the result depends on
|
||||
REQUIRE: if REQUIRE is true, error out; if REQUIRE is false,
|
||||
return nullptr. */
|
||||
.gnu_debugaltlink or .debug_sup section in the file, then the
|
||||
result depends on REQUIRE: if REQUIRE is true, error out; if
|
||||
REQUIRE is false, return nullptr. */
|
||||
struct dwz_file *get_dwz_file (bool require = false)
|
||||
{
|
||||
gdb_assert (!require || this->dwz_file.has_value ());
|
||||
@@ -546,7 +546,7 @@ struct dwarf2_per_bfd
|
||||
{
|
||||
result = this->dwz_file->get ();
|
||||
if (require && result == nullptr)
|
||||
error (_("could not read '.gnu_debugaltlink' section"));
|
||||
error (_("could not find supplementary DWARF file"));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -13,160 +13,5 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
load_lib dwarf.exp
|
||||
|
||||
# This test can only be run on targets which support DWARF-2 and use gas.
|
||||
require dwarf2_support
|
||||
|
||||
# No remote host testing either.
|
||||
require {!is_remote host}
|
||||
|
||||
|
||||
# Lots of source files since we test a few cases and make new files
|
||||
# for each.
|
||||
# The tests are:
|
||||
# ok - the main file refers to a dwz and the buildids match
|
||||
# mismatch - the buildids do not match
|
||||
# fallback - the buildids do not match but a match is found via buildid
|
||||
standard_testfile main.c \
|
||||
dwzbuildid-ok-base.S dwzbuildid-ok-sep.S \
|
||||
dwzbuildid-mismatch-base.S dwzbuildid-mismatch-sep.S \
|
||||
dwzbuildid-fallback-base.S dwzbuildid-fallback-sep.S \
|
||||
dwzbuildid-fallback-ok.S
|
||||
|
||||
# Write some assembly that just has a .gnu_debugaltlink section.
|
||||
proc write_just_debugaltlink {filename dwzname buildid} {
|
||||
set asm_file [standard_output_file $filename]
|
||||
|
||||
Dwarf::assemble $asm_file {
|
||||
upvar dwzname dwzname
|
||||
upvar buildid buildid
|
||||
|
||||
gnu_debugaltlink $dwzname $buildid
|
||||
|
||||
# Only the DWARF reader checks .gnu_debugaltlink, so make sure
|
||||
# there is a bit of DWARF in here.
|
||||
cu { label cu_start } {
|
||||
compile_unit {{language @DW_LANG_C}} {
|
||||
}
|
||||
}
|
||||
aranges {} cu_start {
|
||||
arange {} 0 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Write some DWARF that also sets the buildid.
|
||||
proc write_dwarf_file {filename buildid {value 99}} {
|
||||
set asm_file [standard_output_file $filename]
|
||||
|
||||
Dwarf::assemble $asm_file {
|
||||
declare_labels int_label int_label2
|
||||
|
||||
upvar buildid buildid
|
||||
upvar value value
|
||||
|
||||
build_id $buildid
|
||||
|
||||
cu { label cu_start } {
|
||||
compile_unit {{language @DW_LANG_C}} {
|
||||
int_label2: base_type {
|
||||
{name int}
|
||||
{byte_size 4 sdata}
|
||||
{encoding @DW_ATE_signed}
|
||||
}
|
||||
|
||||
constant {
|
||||
{name the_int}
|
||||
{type :$int_label2}
|
||||
{const_value $value data1}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aranges {} cu_start {
|
||||
arange {} 0 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if { [gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile}1.o \
|
||||
object {nodebug}] != "" } {
|
||||
return -1
|
||||
}
|
||||
|
||||
# The values don't really matter, just whether they are equal.
|
||||
set ok_prefix 01
|
||||
set ok_suffix 02030405060708091011121314151617181920
|
||||
set ok_suffix2 020304050607080910111213141516171819ff
|
||||
set ok_buildid ${ok_prefix}${ok_suffix}
|
||||
set ok_buildid2 ${ok_prefix}${ok_suffix2}
|
||||
set bad_buildid [string repeat ff 20]
|
||||
|
||||
set debugdir [standard_output_file {}]
|
||||
set basedir $debugdir/.build-id
|
||||
file mkdir $basedir $basedir/$ok_prefix
|
||||
|
||||
# Test where the separate debuginfo's buildid matches.
|
||||
write_just_debugaltlink $srcfile2 ${binfile}3.o $ok_buildid
|
||||
write_dwarf_file $srcfile3 $ok_buildid
|
||||
|
||||
# Test where the separate debuginfo's buildid does not match.
|
||||
write_just_debugaltlink $srcfile4 ${binfile}5.o $ok_buildid
|
||||
write_dwarf_file $srcfile5 $bad_buildid
|
||||
|
||||
# Test where the separate debuginfo's buildid does not match, but then
|
||||
# we find a match in the .build-id directory.
|
||||
write_just_debugaltlink $srcfile6 ${binfile}7.o $ok_buildid2
|
||||
# Use 77 as the value so that if we load the bad debuginfo, we will
|
||||
# see the wrong result.
|
||||
write_dwarf_file $srcfile7 $bad_buildid 77
|
||||
write_dwarf_file $srcfile8 $ok_buildid2
|
||||
|
||||
# Compile everything.
|
||||
for {set i 2} {$i <= 8} {incr i} {
|
||||
if {[gdb_compile [standard_output_file [set srcfile$i]] \
|
||||
${binfile}$i.o object nodebug] != ""} {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
# Copy a file into the .build-id place for the "fallback" test.
|
||||
file copy -force -- ${binfile}8.o $basedir/$ok_prefix/$ok_suffix2.debug
|
||||
|
||||
proc do_test {} {
|
||||
clean_restart
|
||||
|
||||
gdb_test_no_output "set debug-file-directory $::debugdir" \
|
||||
"set debug-file-directory"
|
||||
|
||||
gdb_load ${::binfile}-${::testname}
|
||||
|
||||
if {![runto_main]} {
|
||||
return
|
||||
}
|
||||
|
||||
if {$::testname == "mismatch"} {
|
||||
gdb_test "print the_int" \
|
||||
"(No symbol table is loaded|No symbol \"the_int\" in current context).*"
|
||||
} else {
|
||||
gdb_test "print the_int" " = 99"
|
||||
}
|
||||
}
|
||||
|
||||
foreach_with_prefix testname { ok mismatch fallback } {
|
||||
if { $testname == "ok" } {
|
||||
set objs [list ${binfile}1.o ${binfile}2.o]
|
||||
} elseif { $testname == "mismatch" } {
|
||||
set objs [list ${binfile}1.o ${binfile}4.o]
|
||||
} elseif { $testname == "fallback" } {
|
||||
set objs [list ${binfile}1.o ${binfile}6.o]
|
||||
}
|
||||
|
||||
if {[gdb_compile $objs ${binfile}-$testname executable {quiet}] != ""} {
|
||||
unsupported "compilation failed"
|
||||
continue
|
||||
}
|
||||
|
||||
do_test
|
||||
}
|
||||
set scenario gnu
|
||||
source $srcdir/$subdir/dwzbuildid.tcl
|
||||
|
||||
184
gdb/testsuite/gdb.dwarf2/dwzbuildid.tcl
Normal file
184
gdb/testsuite/gdb.dwarf2/dwzbuildid.tcl
Normal file
@@ -0,0 +1,184 @@
|
||||
# Copyright 2013-2025 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
load_lib dwarf.exp
|
||||
|
||||
# This test can only be run on targets which support DWARF-2 and use gas.
|
||||
require dwarf2_support
|
||||
|
||||
# No remote host testing either.
|
||||
require {!is_remote host}
|
||||
|
||||
|
||||
# Lots of source files since we test a few cases and make new files
|
||||
# for each.
|
||||
# The tests are:
|
||||
# ok - the main file refers to a dwz and the buildids match
|
||||
# mismatch - the buildids do not match
|
||||
# fallback - the buildids do not match but a match is found via buildid
|
||||
standard_testfile main.c \
|
||||
dwzbuildid-ok-base.S dwzbuildid-ok-sep.S \
|
||||
dwzbuildid-mismatch-base.S dwzbuildid-mismatch-sep.S \
|
||||
dwzbuildid-fallback-base.S dwzbuildid-fallback-sep.S \
|
||||
dwzbuildid-fallback-ok.S
|
||||
|
||||
# Write some assembly that just has a .gnu_debugaltlink section.
|
||||
proc write_just_debugaltlink {filename dwzname buildid} {
|
||||
set asm_file [standard_output_file $filename]
|
||||
|
||||
Dwarf::assemble $asm_file {
|
||||
upvar dwzname dwzname
|
||||
upvar buildid buildid
|
||||
|
||||
if {$::scenario == "gnu"} {
|
||||
gnu_debugaltlink $dwzname $buildid
|
||||
} else {
|
||||
debug_sup 0 $dwzname $buildid
|
||||
}
|
||||
|
||||
# Only the DWARF reader checks .gnu_debugaltlink, so make sure
|
||||
# there is a bit of DWARF in here.
|
||||
cu { label cu_start } {
|
||||
compile_unit {{language @DW_LANG_C}} {
|
||||
}
|
||||
}
|
||||
aranges {} cu_start {
|
||||
arange {} 0 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Write some DWARF that also sets the buildid.
|
||||
proc write_dwarf_file {filename buildid {value 99}} {
|
||||
set asm_file [standard_output_file $filename]
|
||||
|
||||
Dwarf::assemble $asm_file {
|
||||
declare_labels int_label int_label2
|
||||
|
||||
upvar buildid buildid
|
||||
upvar value value
|
||||
|
||||
if {$::scenario == "gnu"} {
|
||||
build_id $buildid
|
||||
} else {
|
||||
debug_sup 1 "" $buildid
|
||||
}
|
||||
|
||||
cu { label cu_start } {
|
||||
compile_unit {{language @DW_LANG_C}} {
|
||||
int_label2: base_type {
|
||||
{name int}
|
||||
{byte_size 4 sdata}
|
||||
{encoding @DW_ATE_signed}
|
||||
}
|
||||
|
||||
constant {
|
||||
{name the_int}
|
||||
{type :$int_label2}
|
||||
{const_value $value data1}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aranges {} cu_start {
|
||||
arange {} 0 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if { [gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile}1.o \
|
||||
object {nodebug}] != "" } {
|
||||
return -1
|
||||
}
|
||||
|
||||
# The values don't really matter, just whether they are equal.
|
||||
set ok_prefix 01
|
||||
set ok_suffix 02030405060708091011121314151617181920
|
||||
set ok_suffix2 020304050607080910111213141516171819ff
|
||||
set ok_buildid ${ok_prefix}${ok_suffix}
|
||||
set ok_buildid2 ${ok_prefix}${ok_suffix2}
|
||||
set bad_buildid [string repeat ff 20]
|
||||
|
||||
set debugdir [standard_output_file {}]
|
||||
set basedir $debugdir/.build-id
|
||||
file mkdir $basedir $basedir/$ok_prefix
|
||||
|
||||
# Test where the separate debuginfo's buildid matches.
|
||||
write_just_debugaltlink $srcfile2 ${binfile}3.o $ok_buildid
|
||||
write_dwarf_file $srcfile3 $ok_buildid
|
||||
|
||||
# Test where the separate debuginfo's buildid does not match.
|
||||
write_just_debugaltlink $srcfile4 ${binfile}5.o $ok_buildid
|
||||
write_dwarf_file $srcfile5 $bad_buildid
|
||||
|
||||
# Test where the separate debuginfo's buildid does not match, but then
|
||||
# we find a match in the .build-id directory.
|
||||
write_just_debugaltlink $srcfile6 ${binfile}7.o $ok_buildid2
|
||||
# Use 77 as the value so that if we load the bad debuginfo, we will
|
||||
# see the wrong result.
|
||||
write_dwarf_file $srcfile7 $bad_buildid 77
|
||||
write_dwarf_file $srcfile8 $ok_buildid2
|
||||
|
||||
# Compile everything.
|
||||
for {set i 2} {$i <= 8} {incr i} {
|
||||
if {[gdb_compile [standard_output_file [set srcfile$i]] \
|
||||
${binfile}$i.o object nodebug] != ""} {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
# Copy a file into the .build-id place for the "fallback" test.
|
||||
file copy -force -- ${binfile}8.o $basedir/$ok_prefix/$ok_suffix2.debug
|
||||
|
||||
proc do_test {} {
|
||||
clean_restart
|
||||
|
||||
gdb_test_no_output "set debug-file-directory $::debugdir" \
|
||||
"set debug-file-directory"
|
||||
|
||||
gdb_load ${::binfile}-${::testname}
|
||||
|
||||
if {![runto_main]} {
|
||||
return
|
||||
}
|
||||
|
||||
if {$::testname == "mismatch"} {
|
||||
gdb_test "print the_int" \
|
||||
"(No symbol table is loaded|No symbol \"the_int\" in current context).*"
|
||||
} else {
|
||||
gdb_test "print the_int" " = 99"
|
||||
}
|
||||
}
|
||||
|
||||
set tests {ok mismatch}
|
||||
if {$scenario == "gnu"} {
|
||||
lappend tests fallback
|
||||
}
|
||||
foreach_with_prefix testname $tests {
|
||||
if { $testname == "ok" } {
|
||||
set objs [list ${binfile}1.o ${binfile}2.o]
|
||||
} elseif { $testname == "mismatch" } {
|
||||
set objs [list ${binfile}1.o ${binfile}4.o]
|
||||
} elseif { $testname == "fallback" } {
|
||||
set objs [list ${binfile}1.o ${binfile}6.o]
|
||||
}
|
||||
|
||||
if {[gdb_compile $objs ${binfile}-$testname executable {quiet}] != ""} {
|
||||
unsupported "compilation failed"
|
||||
continue
|
||||
}
|
||||
|
||||
do_test
|
||||
}
|
||||
17
gdb/testsuite/gdb.dwarf2/dwzbuildid5.exp
Normal file
17
gdb/testsuite/gdb.dwarf2/dwzbuildid5.exp
Normal file
@@ -0,0 +1,17 @@
|
||||
# Copyright 2025 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set scenario dwarf5
|
||||
source $srcdir/$subdir/dwzbuildid.tcl
|
||||
@@ -49,5 +49,5 @@ if {[build_executable $testfile.exp $testfile \
|
||||
|
||||
clean_restart
|
||||
gdb_test "file -readnow $binfile" \
|
||||
"could not read '.gnu_debugaltlink' section" \
|
||||
"could not find supplementary DWARF file" \
|
||||
"file $testfile"
|
||||
|
||||
@@ -38,7 +38,7 @@ if { [build_executable $testfile.exp $testfile [list $srcfile $asm_file]] } {
|
||||
clean_restart
|
||||
gdb_test_no_output "maint set dwarf synchronous on"
|
||||
|
||||
set msg "\r\nwarning: could not find '\.gnu_debugaltlink' file for \[^\r\n\]*"
|
||||
set msg "\r\nwarning: could not find supplementary DWARF file \[^\r\n\]*"
|
||||
gdb_test "file $binfile" "$msg" "file command"
|
||||
|
||||
set question "Load new symbol table from .*\? .y or n. "
|
||||
|
||||
@@ -3068,6 +3068,24 @@ namespace eval Dwarf {
|
||||
}
|
||||
}
|
||||
|
||||
# Emit a .debug_sup section with the given file name and build-id.
|
||||
# The buildid should be represented as a hexadecimal string, like
|
||||
# "ffeeddcc".
|
||||
proc debug_sup {is_sup filename buildid} {
|
||||
_defer_output .debug_sup {
|
||||
# The version.
|
||||
_op .2byte 0x5
|
||||
# Supplementary marker.
|
||||
_op .byte $is_sup
|
||||
_op .ascii [_quote $filename]
|
||||
set len [expr {[string length $buildid] / 2}]
|
||||
_op .uleb128 $len
|
||||
foreach {a b} [split $buildid {}] {
|
||||
_op .byte 0x$a$b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc _note {type name hexdata} {
|
||||
set namelen [expr [string length $name] + 1]
|
||||
set datalen [expr [string length $hexdata] / 2]
|
||||
|
||||
Reference in New Issue
Block a user