diff options
Diffstat (limited to 'gdb/dwarf2')
-rw-r--r-- | gdb/dwarf2/attribute.c | 5 | ||||
-rw-r--r-- | gdb/dwarf2/attribute.h | 14 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-indexer.c | 4 | ||||
-rw-r--r-- | gdb/dwarf2/die.c | 3 | ||||
-rw-r--r-- | gdb/dwarf2/dwz.c | 193 | ||||
-rw-r--r-- | gdb/dwarf2/dwz.h | 25 | ||||
-rw-r--r-- | gdb/dwarf2/macro.c | 1 | ||||
-rw-r--r-- | gdb/dwarf2/read.c | 19 | ||||
-rw-r--r-- | gdb/dwarf2/read.h | 8 |
9 files changed, 214 insertions, 58 deletions
diff --git a/gdb/dwarf2/attribute.c b/gdb/dwarf2/attribute.c index 1278f97..2d14ebd 100644 --- a/gdb/dwarf2/attribute.c +++ b/gdb/dwarf2/attribute.c @@ -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 diff --git a/gdb/dwarf2/attribute.h b/gdb/dwarf2/attribute.h index 70edff3..ec4f3d8 100644 --- a/gdb/dwarf2/attribute.h +++ b/gdb/dwarf2/attribute.h @@ -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. */ diff --git a/gdb/dwarf2/cooked-indexer.c b/gdb/dwarf2/cooked-indexer.c index 1f3a235..b8b66cf 100644 --- a/gdb/dwarf2/cooked-indexer.c +++ b/gdb/dwarf2/cooked-indexer.c @@ -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); } } diff --git a/gdb/dwarf2/die.c b/gdb/dwarf2/die.c index 8c3d2ca..7ed18bf 100644 --- a/gdb/dwarf2/die.c +++ b/gdb/dwarf2/die.c @@ -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 () : "", diff --git a/gdb/dwarf2/dwz.c b/gdb/dwarf2/dwz.c index e5e18a1..583103b 100644 --- a/gdb/dwarf2/dwz.c +++ b/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" @@ -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') @@ -85,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. @@ -93,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 @@ -161,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; @@ -177,11 +313,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,24 +326,17 @@ 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 ()); @@ -223,25 +349,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,16 +379,18 @@ 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 (), diff --git a/gdb/dwarf2/dwz.h b/gdb/dwarf2/dwz.h index 9f69123..372f7e6 100644 --- a/gdb/dwarf2/dwz.h +++ b/gdb/dwarf2/dwz.h @@ -31,10 +31,12 @@ struct dwarf2_per_objfile; struct dwz_file { - dwz_file (gdb_bfd_ref_ptr &&bfd) - : dwz_bfd (std::move (bfd)) - { - } + /* 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 + 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 { @@ -64,16 +66,15 @@ struct dwz_file return a pointer to the string. */ const char *read_string (struct objfile *objfile, LONGEST str_offset); -}; -using dwz_file_up = std::unique_ptr<dwz_file>; +private: -/* Open the separate '.dwz' debug file, if needed. This just sets 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. */ + explicit dwz_file (gdb_bfd_ref_ptr &&bfd) + : dwz_bfd (std::move (bfd)) + { + } +}; -extern void dwarf2_read_dwz_file (dwarf2_per_objfile *per_objfile); +using dwz_file_up = std::unique_ptr<dwz_file>; #endif /* GDB_DWARF2_DWZ_H */ diff --git a/gdb/dwarf2/macro.c b/gdb/dwarf2/macro.c index 9b8f093..1dc3a9e 100644 --- a/gdb/dwarf2/macro.c +++ b/gdb/dwarf2/macro.c @@ -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; diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 55cf02f..7b019f9 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -1282,7 +1282,7 @@ dwarf2_has_info (struct objfile *objfile, BFD, to avoid races. */ try { - dwarf2_read_dwz_file (per_objfile); + dwz_file::read_dwz_file (per_objfile); } catch (const gdb_exception_error &err) { @@ -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. */ { diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index a9a2aa4..f3e043c 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -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; |