diff options
Diffstat (limited to 'gdb/dwarf2')
31 files changed, 2019 insertions, 1527 deletions
diff --git a/gdb/dwarf2/attribute.c b/gdb/dwarf2/attribute.c index 1278f97..d2b5364 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. */ @@ -185,11 +186,59 @@ attribute::unsigned_constant () const /* See attribute.h. */ +std::optional<LONGEST> +attribute::signed_constant () const +{ + if (form_is_strictly_signed ()) + return u.snd; + + switch (form) + { + case DW_FORM_data8: + case DW_FORM_udata: + /* Not sure if DW_FORM_udata should be handled or not. Anyway + for DW_FORM_data8, there's no need to sign-extend. */ + return u.snd; + + case DW_FORM_data1: + return sign_extend (u.unsnd, 8); + case DW_FORM_data2: + return sign_extend (u.unsnd, 16); + case DW_FORM_data4: + return sign_extend (u.unsnd, 32); + } + + /* For DW_FORM_data16 see attribute::form_is_constant. */ + complaint (_("Attribute value is not a constant (%s)"), + dwarf_form_name (form)); + return {}; +} + +/* See attribute.h. */ + +std::optional<LONGEST> +attribute::confused_constant () const +{ + if (form_is_strictly_signed ()) + return u.snd; + else if (form_is_constant ()) + return u.unsnd; + + /* For DW_FORM_data16 see attribute::form_is_constant. */ + complaint (_("Attribute value is not a constant (%s)"), + dwarf_form_name (form)); + return {}; +} + +/* See attribute.h. */ + bool 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 @@ -293,5 +342,8 @@ attribute::as_boolean () const return true; else if (form == DW_FORM_flag) return u.unsnd != 0; - return constant_value (0) != 0; + /* Using signed_constant here will work even for the weird case + where a negative value is provided. Probably doesn't matter but + also seems harmless. */ + return signed_constant ().value_or (0) != 0; } diff --git a/gdb/dwarf2/attribute.h b/gdb/dwarf2/attribute.h index 70edff3..234de4e 100644 --- a/gdb/dwarf2/attribute.h +++ b/gdb/dwarf2/attribute.h @@ -114,6 +114,34 @@ struct attribute returned. */ std::optional<ULONGEST> unsigned_constant () const; + /* Return a signed constant value. This only handles constant forms + (i.e., form_is_constant -- and not the extended list of + "unsigned" forms) and assumes a signed value is desired. This + function will sign-extend DW_FORM_data* values. + + If non-constant form is used, then complaint is issued and an + empty value is returned. */ + std::optional<LONGEST> signed_constant () const; + + /* Return a signed constant value. However, for narrow forms like + DW_FORM_data1, sign extension is not done. + + DWARF advises compilers to generally use DW_FORM_[su]data to + avoid ambiguity. However, both GCC and LLVM ignore this for + certain attributes. Furthermore in DWARF, whether a narrower + form causes sign-extension depends on the attribute -- for + attributes that can only assume non-negative values, sign + extension is not done. + + Unfortunately, both compilers also emit certain attributes in a + "confused" way, using DW_FORM_sdata for signed values, and + possibly choosing a narrow form (e.g., DW_FORM_data1) otherwise + -- assuming that sign-extension will not be done. + + This method should only be called when this "confused" treatment + is necessary. */ + std::optional<LONGEST> confused_constant () const; + /* Return non-zero if ATTR's value falls in the 'constant' class, or zero otherwise. When this function returns true, you can apply the constant_value method to it. @@ -144,7 +172,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* @@ -164,10 +194,29 @@ struct attribute false. */ bool form_is_strictly_signed () const; + /* Check if the attribute's form is an unsigned constant form. This + only returns true for forms that are strictly unsigned -- that + is, for a context-dependent form like DW_FORM_data1, this returns + false. */ + bool form_is_strictly_unsigned () const + { + return form == DW_FORM_udata; + } + /* Check if the attribute's form is a form that requires "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/call-site.h b/gdb/dwarf2/call-site.h index e02cc5e..2cc4883 100644 --- a/gdb/dwarf2/call-site.h +++ b/gdb/dwarf2/call-site.h @@ -198,7 +198,7 @@ struct call_site struct call_site *tail_call_next = nullptr; /* * Describe DW_AT_call_target. Missing attribute uses - FIELD_LOC_KIND_DWARF_BLOCK with FIELD_DWARF_BLOCK == NULL. */ + m_loc_kind == DWARF_BLOCK with m_loc.dwarf_block == nullptr. */ struct call_site_target target {}; diff --git a/gdb/dwarf2/cooked-index-entry.c b/gdb/dwarf2/cooked-index-entry.c index 52db851..863ddd6 100644 --- a/gdb/dwarf2/cooked-index-entry.c +++ b/gdb/dwarf2/cooked-index-entry.c @@ -33,6 +33,7 @@ to_string (cooked_index_flag flags) MAP_ENUM_FLAG (IS_LINKAGE), MAP_ENUM_FLAG (IS_TYPE_DECLARATION), MAP_ENUM_FLAG (IS_PARENT_DEFERRED), + MAP_ENUM_FLAG (IS_SYNTHESIZED), }; return flags.to_string (mapping); @@ -233,8 +234,7 @@ cooked_index_entry::write_scope (struct obstack *storage, obstack_grow (storage, sep, strlen (sep)); } -void _initialize_dwarf2_entry (); -void _initialize_dwarf2_entry () +INIT_GDB_FILE (dwarf2_entry) { #if GDB_SELF_TEST selftests::register_test ("cooked_index_entry::compare", test_compare); diff --git a/gdb/dwarf2/cooked-index-worker.c b/gdb/dwarf2/cooked-index-worker.c index da51a8c..09d80ef 100644 --- a/gdb/dwarf2/cooked-index-worker.c +++ b/gdb/dwarf2/cooked-index-worker.c @@ -20,6 +20,7 @@ #include "dwarf2/cooked-index-worker.h" #include "dwarf2/cooked-index.h" #include "gdbsupport/thread-pool.h" +#include "maint.h" #include "run-on-main-thread.h" #include "event-top.h" #include "exceptions.h" @@ -244,8 +245,12 @@ cooked_index_worker::write_to_cache (const cooked_index *idx) void cooked_index_worker::done_reading () { - for (auto &one_result : m_results) - m_all_parents_map.add_map (*one_result.get_parent_map ()); + { + scoped_time_it time_it ("DWARF add parent map", m_per_command_time); + + for (auto &one_result : m_results) + m_all_parents_map.add_map (*one_result.get_parent_map ()); + } dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd; cooked_index *table diff --git a/gdb/dwarf2/cooked-index-worker.h b/gdb/dwarf2/cooked-index-worker.h index df5c31d..8b9766c 100644 --- a/gdb/dwarf2/cooked-index-worker.h +++ b/gdb/dwarf2/cooked-index-worker.h @@ -25,6 +25,8 @@ #include "dwarf2/cooked-index-shard.h" #include "dwarf2/types.h" #include "dwarf2/read.h" +#include "maint.h" +#include "run-on-main-thread.h" #if CXX_STD_THREAD #include <mutex> @@ -107,11 +109,20 @@ public: return &m_parent_map; } - /* Add an exception to the list of exceptions caught while reading. - These are passed forward and printed by the main thread. */ - void note_error (gdb_exception &&except) + /* Catch exceptions from calling F (), and add them to the list of caught + exceptions. These are passed forward and printed by the main thread. */ + template <typename F> + void + catch_error (F &&f) { - m_exceptions.push_back (std::move (except)); + try + { + f (); + } + catch (gdb_exception &ex) + { + m_exceptions.push_back (std::move (ex)); + } } /* Called when the thread using this object is done with its work. @@ -207,8 +218,12 @@ public: explicit cooked_index_worker (dwarf2_per_objfile *per_objfile) : m_per_objfile (per_objfile), - m_cache_store (global_index_cache, per_objfile->per_bfd) - { } + m_cache_store (global_index_cache, per_objfile->per_bfd), + m_per_command_time (per_command_time) + { + /* Make sure we capture per_command_time from the main thread. */ + gdb_assert (is_main_thread ()); + } virtual ~cooked_index_worker () { } DISABLE_COPY_AND_ASSIGN (cooked_index_worker); @@ -298,6 +313,9 @@ protected: std::optional<gdb_exception> m_failed; /* An object used to write to the index cache. */ index_cache_store_context m_cache_store; + + /* Captured value of per_command_time. */ + bool m_per_command_time; }; using cooked_index_worker_up = std::unique_ptr<cooked_index_worker>; diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c index 7948ffa..6209590 100644 --- a/gdb/dwarf2/cooked-index.c +++ b/gdb/dwarf2/cooked-index.c @@ -21,6 +21,7 @@ #include "dwarf2/read.h" #include "dwarf2/stringify.h" #include "event-top.h" +#include "maint.h" #include "observable.h" #include "run-on-main-thread.h" #include "gdbsupport/task-group.h" @@ -101,7 +102,12 @@ cooked_index::set_contents () { auto this_shard = shard.get (); const parent_map_map *parent_maps = m_state->get_parent_map_map (); - finalizers.add_task ([=] () { this_shard->finalize (parent_maps); }); + finalizers.add_task ([=] () + { + scoped_time_it time_it ("DWARF finalize worker", + m_state->m_per_command_time); + this_shard->finalize (parent_maps); + }); } finalizers.start (); @@ -321,9 +327,7 @@ maintenance_wait_for_index_cache (const char *args, int from_tty) wait_for_index_cache (0); } -void _initialize_cooked_index (); -void -_initialize_cooked_index () +INIT_GDB_FILE (cooked_index) { add_cmd ("wait-for-index-cache", class_maintenance, maintenance_wait_for_index_cache, _("\ diff --git a/gdb/dwarf2/cooked-indexer.c b/gdb/dwarf2/cooked-indexer.c index 1f3a235..d4557c45 100644 --- a/gdb/dwarf2/cooked-indexer.c +++ b/gdb/dwarf2/cooked-indexer.c @@ -83,19 +83,17 @@ tag_can_have_linkage_name (enum dwarf_tag tag) cutu_reader * cooked_indexer::ensure_cu_exists (cutu_reader *reader, - sect_offset sect_off, bool is_dwz, + const section_and_offset §_off, bool for_scanning) { /* Lookups for type unit references are always in the CU, and cross-CU references will crash. */ - if (reader->cu ()->per_cu->is_dwz == is_dwz - && reader->cu ()->header.offset_in_cu_p (sect_off)) + if (reader->section () == sect_off.section + && reader->cu ()->header.offset_in_unit_p (sect_off.offset)) return reader; dwarf2_per_objfile *per_objfile = reader->cu ()->per_objfile; - dwarf2_per_cu *per_cu - = dwarf2_find_containing_comp_unit (sect_off, is_dwz, - per_objfile->per_bfd); + dwarf2_per_cu *per_cu = dwarf2_find_containing_unit (sect_off, per_objfile); /* When scanning, we only want to visit a given CU a single time. Doing this check here avoids self-imports as well. */ @@ -109,20 +107,20 @@ cooked_indexer::ensure_cu_exists (cutu_reader *reader, cutu_reader *result = m_index_storage->get_reader (per_cu); if (result == nullptr) { - cutu_reader new_reader (*per_cu, *per_objfile, nullptr, nullptr, false, - language_minimal, - &m_index_storage->get_abbrev_table_cache ()); - - if (new_reader.is_dummy () || new_reader.top_level_die () == nullptr - || !new_reader.top_level_die ()->has_children) + const abbrev_table_cache &abbrev_table_cache + = m_index_storage->get_abbrev_table_cache (); + auto new_reader + = std::make_unique<cutu_reader> (*per_cu, *per_objfile, nullptr, + nullptr, false, language_minimal, + &abbrev_table_cache); + + if (new_reader->is_dummy ()) return nullptr; - auto copy = std::make_unique<cutu_reader> (std::move (new_reader)); - result = m_index_storage->preserve (std::move (copy)); + result = m_index_storage->preserve (std::move (new_reader)); } - if (result->is_dummy () || result->top_level_die () == nullptr - || !result->top_level_die ()->has_children) + if (result->is_dummy ()) return nullptr; if (for_scanning) @@ -148,10 +146,8 @@ cooked_indexer::scan_attributes (dwarf2_per_cu *scanning_per_cu, bool *is_enum_class, bool for_specification) { - bool origin_is_dwz = false; bool is_declaration = false; - sect_offset origin_offset {}; - + std::optional<section_and_offset> origin; std::optional<unrelocated_addr> low_pc; std::optional<unrelocated_addr> high_pc; bool high_pc_relative = false; @@ -221,8 +217,8 @@ cooked_indexer::scan_attributes (dwarf2_per_cu *scanning_per_cu, case DW_AT_specification: 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 = { &get_section_for_ref (attr, reader->cu ()), + attr.get_ref_die_offset () }; break; case DW_AT_external: @@ -311,19 +307,19 @@ cooked_indexer::scan_attributes (dwarf2_per_cu *scanning_per_cu, || (*linkage_name == nullptr && tag_can_have_linkage_name (abbrev->tag)) || (*parent_entry == nullptr && m_language != language_c)) - && origin_offset != sect_offset (0)) + && origin.has_value ()) { cutu_reader *new_reader - = ensure_cu_exists (reader, origin_offset, origin_is_dwz, false); + = ensure_cu_exists (reader, *origin, false); if (new_reader == nullptr) error (_(DWARF_ERROR_PREFIX "cannot follow reference to DIE at %s" " [in module %s]"), - sect_offset_str (origin_offset), + sect_offset_str (origin->offset), bfd_get_filename (reader->abfd ())); const gdb_byte *new_info_ptr - = (new_reader->buffer () + to_underlying (origin_offset)); + = (new_reader->buffer () + to_underlying (origin->offset)); if (*parent_entry == nullptr) { @@ -347,7 +343,7 @@ cooked_indexer::scan_attributes (dwarf2_per_cu *scanning_per_cu, if (new_abbrev == nullptr) error (_(DWARF_ERROR_PREFIX "Unexpected null DIE at offset %s [in module %s]"), - sect_offset_str (origin_offset), + sect_offset_str (origin->offset), bfd_get_filename (new_reader->abfd ())); new_info_ptr += bytes_read; @@ -411,8 +407,7 @@ cooked_indexer::index_imported_unit (cutu_reader *reader, const gdb_byte *info_ptr, const abbrev_info *abbrev) { - sect_offset sect_off {}; - bool is_dwz = false; + std::optional<section_and_offset> target; for (int i = 0; i < abbrev->num_attrs; ++i) { @@ -421,19 +416,16 @@ cooked_indexer::index_imported_unit (cutu_reader *reader, info_ptr = reader->read_attribute (&attr, &abbrev->attrs[i], info_ptr); if (attr.name == DW_AT_import) - { - sect_off = attr.get_ref_die_offset (); - is_dwz = (attr.form == DW_FORM_GNU_ref_alt - || reader->cu ()->per_cu->is_dwz); - } + target = { &get_section_for_ref (attr, reader->cu ()), + attr.get_ref_die_offset () }; } /* Did not find DW_AT_import. */ - if (sect_off == sect_offset (0)) + if (!target.has_value ()) return info_ptr; cutu_reader *new_reader - = ensure_cu_exists (reader, sect_off, is_dwz, true); + = ensure_cu_exists (reader, *target, true); if (new_reader != nullptr) { index_dies (new_reader, new_reader->info_ptr (), nullptr, false); diff --git a/gdb/dwarf2/cooked-indexer.h b/gdb/dwarf2/cooked-indexer.h index 904c55f..83cbf7f 100644 --- a/gdb/dwarf2/cooked-indexer.h +++ b/gdb/dwarf2/cooked-indexer.h @@ -30,6 +30,7 @@ struct cooked_index_worker_result; struct cutu_reader; struct dwarf2_per_cu; struct dwarf2_per_objfile; +struct section_and_offset; /* An instance of this is created to index a CU. */ @@ -55,8 +56,7 @@ private: the DIEs in the CU; when false, this use is assumed to be to look up just a single DIE. */ cutu_reader *ensure_cu_exists (cutu_reader *reader, - sect_offset sect_off, - bool is_dwz, + const section_and_offset §_off, bool for_scanning); /* Index DIEs in the READER starting at INFO_PTR. PARENT is diff --git a/gdb/dwarf2/cu.h b/gdb/dwarf2/cu.h index 5683291..68010a0 100644 --- a/gdb/dwarf2/cu.h +++ b/gdb/dwarf2/cu.h @@ -21,7 +21,7 @@ #define GDB_DWARF2_CU_H #include "buildsym.h" -#include "dwarf2/comp-unit-head.h" +#include "dwarf2/unit-head.h" #include <optional> #include "language.h" #include "gdbsupport/unordered_set.h" @@ -54,6 +54,11 @@ struct dwarf2_cu DISABLE_COPY_AND_ASSIGN (dwarf2_cu); + /* The section the DIEs were effectively read from. This could be + .debug_info, .debug_types, or with split DWARF, their .dwo + variants. */ + const dwarf2_section_info §ion () const; + /* TU version of handle_DW_AT_stmt_list for read_type_unit_scope. Create the set of symtabs used by this TU, or if this TU is sharing symtabs with another TU and the symtabs have already been created @@ -99,8 +104,17 @@ struct dwarf2_cu void add_dependence (dwarf2_per_cu *ref_per_cu) { m_dependencies.emplace (ref_per_cu); } + /* Find the DIE at section offset SECT_OFF. + + Return nullptr if not found. */ + die_info *find_die (sect_offset sect_off) const + { + auto it = die_hash.find (sect_off); + return it != die_hash.end () ? *it : nullptr; + } + /* The header of the compilation unit. */ - struct comp_unit_head header; + struct unit_head header; /* Base address of this compilation unit. */ std::optional<unrelocated_addr> base_address; @@ -360,7 +374,7 @@ public: right place. And since the DW_TAG_compile_unit DIE in the split-unit can't have a DW_AT_ranges attribute, we can use the - die->tag != DW_AT_compile_unit + die->tag != DW_TAG_compile_unit to determine whether the base should be added or not. */ ULONGEST gnu_ranges_base = 0; 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..1aa0d03 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') @@ -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 ()); 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/frame-tailcall.c b/gdb/dwarf2/frame-tailcall.c index 6464ffb..e31ae10 100644 --- a/gdb/dwarf2/frame-tailcall.c +++ b/gdb/dwarf2/frame-tailcall.c @@ -478,9 +478,7 @@ const struct frame_unwind_legacy dwarf2_tailcall_frame_unwind ( tailcall_frame_prev_arch ); -void _initialize_tailcall_frame (); -void -_initialize_tailcall_frame () +INIT_GDB_FILE (tailcall_frame) { cache_htab = htab_create_alloc (50, cache_hash, cache_eq, NULL, xcalloc, xfree); diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c index 1b4de0d..7a37285 100644 --- a/gdb/dwarf2/frame.c +++ b/gdb/dwarf2/frame.c @@ -2247,9 +2247,7 @@ dwarf2_build_frame_info (struct objfile *objfile) set_comp_unit (objfile, unit.release ()); } -void _initialize_dwarf2_frame (); -void -_initialize_dwarf2_frame () +INIT_GDB_FILE (dwarf2_frame) { #if GDB_SELF_TEST selftests::register_test_foreach_arch ("execute_cfa_program", diff --git a/gdb/dwarf2/frame.h b/gdb/dwarf2/frame.h index f8fd8e8..9357cc1 100644 --- a/gdb/dwarf2/frame.h +++ b/gdb/dwarf2/frame.h @@ -198,6 +198,15 @@ struct dwarf2_frame_state bool armcc_cfa_offsets_reversed = false; }; +/* If DWARF supoprt was requested, create the real prototype for the + append_unwinders function. Otherwise, create a fake inline function. + + There is no need to emit a warning for some of these, because they aren't + actively reading DWARF when this is called, they're just initializing GDB. + + These should probably be moved to dwarf2/public.h. */ +#if defined(DWARF_FORMAT_AVAILABLE) + /* Set the architecture-specific register state initialization function for GDBARCH to INIT_REG. */ @@ -287,4 +296,56 @@ extern void *dwarf2_frame_get_fn_data (const frame_info_ptr &this_frame, void **this_cache, fn_prev_register cookie); +#else /* DWARF_FORMAT_AVAILABLE */ + +static inline void dwarf2_append_unwinders (struct gdbarch *gdbarch) { } + +static inline void dwarf2_frame_set_init_reg ( + gdbarch *gdbarch, void (*init_reg) (struct gdbarch *,int, + dwarf2_frame_state_reg *, + const frame_info_ptr &)) { } + +static inline const struct frame_base * + dwarf2_frame_base_sniffer (const frame_info_ptr &this_frame) +{ + warning (_("No dwarf support available.")); + return nullptr; +} + +static inline void dwarf2_frame_set_signal_frame_p + (gdbarch *gdbarch, int (*signal_frame_p) (struct gdbarch *, + const frame_info_ptr &)) { } + +static inline void *dwarf2_frame_get_fn_data (const frame_info_ptr &this_frame, + void **this_cache, + fn_prev_register cookie) +{ + return nullptr; +} + +static inline void *dwarf2_frame_allocate_fn_data + (const frame_info_ptr &this_frame, void **this_cache, + fn_prev_register cookie, unsigned long size) +{ + return nullptr; +} + +static inline int dwarf2_fetch_cfa_info (struct gdbarch *gdbarch, CORE_ADDR pc, + struct dwarf2_per_cu_data *data, + int *regnum_out, LONGEST *offset_out, + CORE_ADDR *text_offset_out, + const gdb_byte **cfa_start_out, + const gdb_byte **cfa_end_out) +{ + return 0; +} + +static inline void + dwarf2_frame_set_adjust_regnum (struct gdbarch *gdbarch, + int (*adjust_regnum) (struct gdbarch *, + int, int)) +{} + +#endif /* DWARF_FORMAT_AVAILABLE */ + #endif /* GDB_DWARF2_FRAME_H */ diff --git a/gdb/dwarf2/index-cache.c b/gdb/dwarf2/index-cache.c index 1715beb..cfe8ce9 100644 --- a/gdb/dwarf2/index-cache.c +++ b/gdb/dwarf2/index-cache.c @@ -342,9 +342,7 @@ show_index_cache_stats_command (const char *arg, int from_tty) indent, global_index_cache.n_misses ()); } -void _initialize_index_cache (); -void -_initialize_index_cache () +INIT_GDB_FILE (index_cache) { /* Set the default index cache directory. */ std::string cache_dir = get_standard_cache_dir (); diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c index 614bdcd..d5b198b 100644 --- a/gdb/dwarf2/index-write.c +++ b/gdb/dwarf2/index-write.c @@ -872,7 +872,7 @@ public: m_debugstrlookup.file_write (file_str); } - void add_cu (dwarf2_per_cu *per_cu, offset_type index) + void add_cu (const dwarf2_per_cu *per_cu, offset_type index) { m_cu_index_htab.emplace (per_cu, index); } @@ -1289,6 +1289,40 @@ write_shortcuts_table (cooked_index *table, data_buf &shortcuts, shortcuts.append_offset (main_name_offset); } +/* Get sorted (by section offset) lists of comp units and type units. */ + +static std::pair<std::vector<const dwarf2_per_cu *>, + std::vector<const signatured_type *>> +get_unit_lists (const dwarf2_per_bfd &per_bfd) +{ + std::vector<const dwarf2_per_cu *> comp_units; + std::vector<const signatured_type *> type_units; + + for (const auto &unit : per_bfd.all_units) + if (unit->is_debug_types) + type_units.emplace_back (static_cast<const signatured_type *> + (unit.get ())); + else + comp_units.emplace_back (unit.get ()); + + auto by_sect_off = [] (const dwarf2_per_cu *lhs, const dwarf2_per_cu *rhs) + { return lhs->sect_off < rhs->sect_off; }; + + /* Sort both lists, even though it is technically not always required: + + - while .gdb_index requires the CU list to be sorted, DWARF 5 doesn't + say anything about the order of CUs in .debug_names. + - .gdb_index doesn't require the TU list to be sorted, and DWARF 5 + doesn't say anything about the order of TUs in .debug_names. + + However, it helps make sure that GDB produce a stable and predictable + output, which is nice. */ + std::sort (comp_units.begin (), comp_units.end (), by_sect_off); + std::sort (type_units.begin (), type_units.end (), by_sect_off); + + return {std::move (comp_units), std::move (type_units)}; +} + /* Write contents of a .gdb_index section for OBJFILE into OUT_FILE. If OBJFILE has an associated dwz file, write contents of a .gdb_index section for that dwz file into DWZ_OUT_FILE. If OBJFILE does not have an @@ -1299,8 +1333,6 @@ write_gdbindex (dwarf2_per_bfd *per_bfd, cooked_index *table, FILE *out_file, FILE *dwz_out_file) { mapped_symtab symtab; - data_buf objfile_cu_list; - data_buf dwz_cu_list; /* While we're scanning CU's create a table that maps a dwarf2_per_cu (which is what addrmap records) to its index (which is what is recorded in the @@ -1308,40 +1340,44 @@ write_gdbindex (dwarf2_per_bfd *per_bfd, cooked_index *table, cu_index_map cu_index_htab; cu_index_htab.reserve (per_bfd->all_units.size ()); - /* Store out the .debug_type CUs, if any. */ - data_buf types_cu_list; + auto [comp_units, type_units] = get_unit_lists (*per_bfd); + int counter = 0; - /* The CU list is already sorted, so we don't need to do additional - work here. */ + /* Write comp units. */ + data_buf objfile_cu_list; + data_buf dwz_cu_list; - int counter = 0; - for (const dwarf2_per_cu_up &per_cu : per_bfd->all_units) + for (const dwarf2_per_cu *per_cu : comp_units) { - const auto insertpair = cu_index_htab.emplace (per_cu.get (), counter); + const auto insertpair = cu_index_htab.emplace (per_cu, counter); gdb_assert (insertpair.second); - /* See enhancement PR symtab/30838. */ - gdb_assert (!(per_cu->is_dwz && per_cu->is_debug_types)); - /* The all_units list contains CUs read from the objfile as well as from the eventual dwz file. We need to place the entry in the corresponding index. */ - data_buf &cu_list = (per_cu->is_debug_types - ? types_cu_list - : per_cu->is_dwz ? dwz_cu_list : objfile_cu_list); + data_buf &cu_list = per_cu->is_dwz ? dwz_cu_list : objfile_cu_list; cu_list.append_uint (8, BFD_ENDIAN_LITTLE, to_underlying (per_cu->sect_off)); - if (per_cu->is_debug_types) - { - signatured_type *sig_type = (signatured_type *) per_cu.get (); - cu_list.append_uint (8, BFD_ENDIAN_LITTLE, - to_underlying (sig_type->type_offset_in_tu)); - cu_list.append_uint (8, BFD_ENDIAN_LITTLE, - sig_type->signature); - } - else - cu_list.append_uint (8, BFD_ENDIAN_LITTLE, per_cu->length ()); + cu_list.append_uint (8, BFD_ENDIAN_LITTLE, per_cu->length ()); + ++counter; + } + + /* Write type units. */ + data_buf types_cu_list; + + for (const signatured_type *sig_type : type_units) + { + const auto insertpair = cu_index_htab.emplace (sig_type, counter); + gdb_assert (insertpair.second); + + /* See enhancement PR symtab/30838. */ + gdb_assert (!sig_type->is_dwz); + types_cu_list.append_uint (8, BFD_ENDIAN_LITTLE, + to_underlying (sig_type->sect_off)); + types_cu_list.append_uint (8, BFD_ENDIAN_LITTLE, + to_underlying (sig_type->type_offset_in_tu)); + types_cu_list.append_uint (8, BFD_ENDIAN_LITTLE, sig_type->signature); ++counter; } @@ -1388,29 +1424,35 @@ write_debug_names (dwarf2_per_bfd *per_bfd, cooked_index *table, const enum bfd_endian dwarf5_byte_order = bfd_big_endian (per_bfd->obfd) ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE; - /* The CU list is already sorted, so we don't need to do additional - work here. Also, the debug_types entries do not appear in - all_units, but only in their own hash table. */ - data_buf cu_list; - data_buf types_cu_list; + auto [comp_units, type_units] = get_unit_lists (*per_bfd); debug_names nametable (per_bfd, dwarf5_is_dwarf64, dwarf5_byte_order); - int counter = 0; - int types_counter = 0; - for (const dwarf2_per_cu_up &per_cu : per_bfd->all_units) + data_buf comp_unit_list; + int comp_unit_counter = 0; + + for (const auto per_cu : comp_units) + { + nametable.add_cu (per_cu, comp_unit_counter); + comp_unit_list.append_uint (nametable.dwarf5_offset_size (), + dwarf5_byte_order, + to_underlying (per_cu->sect_off)); + comp_unit_counter++; + } + + data_buf type_unit_list; + int type_unit_counter = 0; + + for (const auto per_cu : type_units) { - int &this_counter = per_cu->is_debug_types ? types_counter : counter; - data_buf &this_list = per_cu->is_debug_types ? types_cu_list : cu_list; - - nametable.add_cu (per_cu.get (), this_counter); - this_list.append_uint (nametable.dwarf5_offset_size (), - dwarf5_byte_order, - to_underlying (per_cu->sect_off)); - ++this_counter; + nametable.add_cu (per_cu, type_unit_counter); + type_unit_list.append_uint (nametable.dwarf5_offset_size (), + dwarf5_byte_order, + to_underlying (per_cu->sect_off)); + type_unit_counter++; } /* Verify that all units are represented. */ - gdb_assert (counter == per_bfd->all_comp_units.size ()); - gdb_assert (types_counter == per_bfd->all_type_units.size ()); + gdb_assert (comp_unit_counter == per_bfd->num_comp_units); + gdb_assert (type_unit_counter == per_bfd->num_type_units); for (const cooked_index_entry *entry : table->all_entries ()) nametable.insert (entry); @@ -1425,8 +1467,8 @@ write_debug_names (dwarf2_per_bfd *per_bfd, cooked_index *table, + sizeof (dwarf5_augmentation_3)); size_t expected_bytes = 0; expected_bytes += bytes_of_header; - expected_bytes += cu_list.size (); - expected_bytes += types_cu_list.size (); + expected_bytes += comp_unit_list.size (); + expected_bytes += type_unit_list.size (); expected_bytes += nametable.bytes (); data_buf header; @@ -1449,11 +1491,11 @@ write_debug_names (dwarf2_per_bfd *per_bfd, cooked_index *table, header.append_uint (2, dwarf5_byte_order, 0); /* comp_unit_count - The number of CUs in the CU list. */ - header.append_uint (4, dwarf5_byte_order, counter); + header.append_uint (4, dwarf5_byte_order, comp_unit_counter); /* local_type_unit_count - The number of TUs in the local TU list. */ - header.append_uint (4, dwarf5_byte_order, types_counter); + header.append_uint (4, dwarf5_byte_order, type_unit_counter); /* foreign_type_unit_count - The number of TUs in the foreign TU list. */ @@ -1481,8 +1523,8 @@ write_debug_names (dwarf2_per_bfd *per_bfd, cooked_index *table, gdb_assert (header.size () == bytes_of_header); header.file_write (out_file); - cu_list.file_write (out_file); - types_cu_list.file_write (out_file); + comp_unit_list.file_write (out_file); + type_unit_list.file_write (out_file); nametable.file_write (out_file, out_file_str); assert_file_size (out_file, expected_bytes); @@ -1768,9 +1810,7 @@ gdb_index () } /* selftests namespace. */ #endif -void _initialize_dwarf_index_write (); -void -_initialize_dwarf_index_write () +INIT_GDB_FILE (dwarf_index_write) { #if GDB_SELF_TEST selftests::register_test ("gdb_index", selftests::gdb_index); diff --git a/gdb/dwarf2/line-header.c b/gdb/dwarf2/line-header.c index de162b7..4652306 100644 --- a/gdb/dwarf2/line-header.c +++ b/gdb/dwarf2/line-header.c @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "dwarf2/comp-unit-head.h" +#include "dwarf2/unit-head.h" #include "dwarf2/leb.h" #include "dwarf2/line-header.h" #include "dwarf2/read.h" @@ -95,7 +95,7 @@ dwarf2_statement_list_fits_in_line_number_section_complaint (void) static LONGEST read_checked_initial_length_and_offset (bfd *abfd, const gdb_byte *buf, - const struct comp_unit_head *cu_header, + const struct unit_head *cu_header, unsigned int *bytes_read, unsigned int *offset_size) { @@ -253,11 +253,10 @@ read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd, /* See line-header.h. */ line_header_up -dwarf_decode_line_header (sect_offset sect_off, bool is_dwz, - dwarf2_per_objfile *per_objfile, - struct dwarf2_section_info *section, - const struct comp_unit_head *cu_header, - const char *comp_dir) +dwarf_decode_line_header (sect_offset sect_off, bool is_dwz, + dwarf2_per_objfile *per_objfile, + struct dwarf2_section_info *section, + const unit_head *cu_header, const char *comp_dir) { const gdb_byte *line_ptr; unsigned int bytes_read, offset_size; diff --git a/gdb/dwarf2/line-header.h b/gdb/dwarf2/line-header.h index 36385b6..e6f9ea9 100644 --- a/gdb/dwarf2/line-header.h +++ b/gdb/dwarf2/line-header.h @@ -218,7 +218,7 @@ file_entry::include_dir (const line_header *lh) const extern line_header_up dwarf_decode_line_header (sect_offset sect_off, bool is_dwz, dwarf2_per_objfile *per_objfile, - struct dwarf2_section_info *section, const struct comp_unit_head *cu_header, + struct dwarf2_section_info *section, const struct unit_head *cu_header, const char *comp_dir); #endif /* GDB_DWARF2_LINE_HEADER_H */ diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c index e1a5fdd..37c85d8 100644 --- a/gdb/dwarf2/loc.c +++ b/gdb/dwarf2/loc.c @@ -1732,11 +1732,10 @@ dwarf2_evaluate_property (const dynamic_prop *prop, *value = prop->const_val (); return true; - case PROP_ADDR_OFFSET: + case PROP_FIELD: { const dwarf2_property_baton *baton = prop->baton (); const struct property_addr_info *pinfo; - struct value *val; for (pinfo = addr_stack; pinfo != NULL; pinfo = pinfo->next) { @@ -1747,14 +1746,40 @@ dwarf2_evaluate_property (const dynamic_prop *prop, } if (pinfo == NULL) error (_("cannot find reference address for offset property")); - if (pinfo->valaddr.data () != NULL) - val = value_from_contents - (baton->offset_info.type, - pinfo->valaddr.data () + baton->offset_info.offset); - else - val = value_at (baton->offset_info.type, - pinfo->addr + baton->offset_info.offset); - *value = value_as_address (val); + + struct field resolved_field = baton->field; + resolve_dynamic_field (resolved_field, pinfo, initial_frame); + + /* Storage for memory if we need to read it. */ + gdb::byte_vector memory; + const gdb_byte *bytes = pinfo->valaddr.data (); + if (bytes == nullptr) + { + int bitpos = resolved_field.loc_bitpos (); + int bitsize = resolved_field.bitsize (); + if (bitsize == 0) + bitsize = check_typedef (resolved_field.type ())->length () * 8; + + /* Read just the minimum number of bytes needed to satisfy + unpack_field_as_long. So, update the resolved field's + starting offset to remove any unnecessary leading + bytes. */ + int byte_offset = bitpos / 8; + + bitpos %= 8; + resolved_field.set_loc_bitpos (bitpos); + + /* Make sure to include any remaining bit offset in the + size computation, in case the value straddles a + byte. */ + int byte_length = align_up (bitsize + bitpos, 8) / 8; + memory.resize (byte_length); + + read_memory (pinfo->addr + byte_offset, memory.data (), + byte_length); + bytes = memory.data (); + } + *value = unpack_field_as_long (bytes, &resolved_field); return true; } @@ -4129,9 +4154,7 @@ const struct symbol_computed_ops dwarf2_loclist_funcs = { loclist_generate_c_location }; -void _initialize_dwarf2loc (); -void -_initialize_dwarf2loc () +INIT_GDB_FILE (dwarf2loc) { add_setshow_zuinteger_cmd ("entry-values", class_maintenance, &entry_values_debug, diff --git a/gdb/dwarf2/loc.h b/gdb/dwarf2/loc.h index 30c528b..c672320 100644 --- a/gdb/dwarf2/loc.h +++ b/gdb/dwarf2/loc.h @@ -20,6 +20,7 @@ #ifndef GDB_DWARF2_LOC_H #define GDB_DWARF2_LOC_H +#include "gdbtypes.h" #include "dwarf2/expr.h" struct symbol_computed_ops; @@ -99,31 +100,9 @@ struct property_addr_info /* If not NULL, a pointer to the info for the object containing the object described by this node. */ - struct property_addr_info *next; + const property_addr_info *next; }; -/* Converts a dynamic property into a static one. FRAME is the frame in which - the property is evaluated; if NULL, the selected frame (if any) is used - instead. - - ADDR_STACK is the stack of addresses that might be needed to evaluate the - property. When evaluating a property that is not related to a type, it can - be NULL. - - Returns true if PROP could be converted and the static value is passed - back into VALUE, otherwise returns false. - - Any values in PUSH_VALUES will be pushed before evaluating the location - expression, PUSH_VALUES[0] will be pushed first, then PUSH_VALUES[1], - etc. This means the during evaluation PUSH_VALUES[0] will be at the - bottom of the stack. */ - -bool dwarf2_evaluate_property (const struct dynamic_prop *prop, - const frame_info_ptr &frame, - const property_addr_info *addr_stack, - CORE_ADDR *value, - gdb::array_view<CORE_ADDR> push_values = {}); - /* A helper for the compiler interface that compiles a single dynamic property to C code. @@ -167,6 +146,9 @@ struct dwarf2_locexpr_baton directly. */ bool is_reference; + /* True if this object is actually a dwarf2_field_location_baton. */ + bool is_field_location; + /* The objfile that was used when creating this. */ dwarf2_per_objfile *per_objfile; @@ -175,6 +157,23 @@ struct dwarf2_locexpr_baton dwarf2_per_cu *per_cu; }; +/* If the DWARF location for a field used DW_AT_bit_size, then an + object of this type is created to represent the field location. + This is then used to apply the bit offset after computing the + field's byte offset. Objects of this type always set the + 'is_field_location' member in dwarf2_locexpr_baton. See also + apply_bit_offset_to_field. */ + +struct dwarf2_field_location_baton : public dwarf2_locexpr_baton +{ + /* The bit offset, coming from DW_AT_bit_offset. */ + LONGEST bit_offset; + + /* The DW_AT_byte_size of the field. If no explicit byte size was + specified, this is 0. */ + LONGEST explicit_byte_size; +}; + struct dwarf2_loclist_baton { /* The initial base address for the location list, based on the compilation @@ -202,23 +201,6 @@ struct dwarf2_loclist_baton unsigned char dwarf_version; }; -/* The baton used when a dynamic property is an offset to a parent - type. This can be used, for instance, then the bound of an array - inside a record is determined by the value of another field inside - that record. */ - -struct dwarf2_offset_baton -{ - /* The offset from the parent type where the value of the property - is stored. In the example provided above, this would be the offset - of the field being used as the array bound. */ - LONGEST offset; - - /* The type of the object whose property is dynamic. In the example - provided above, this would the array's index type. */ - struct type *type; -}; - /* A dynamic property is either expressed as a single location expression or a location list. If the property is an indirection, pointing to another die, keep track of the targeted type in PROPERTY_TYPE. @@ -241,8 +223,8 @@ struct dwarf2_property_baton /* Location list to be evaluated in the context of PROPERTY_TYPE. */ struct dwarf2_loclist_baton loclist; - /* The location is an offset to PROPERTY_TYPE. */ - struct dwarf2_offset_baton offset_info; + /* The location is stored in a field of PROPERTY_TYPE. */ + struct field field; }; }; @@ -307,8 +289,53 @@ extern struct value *indirect_synthetic_pointer Function always returns non-NULL value. It throws NO_ENTRY_VALUE_ERROR if it cannot resolve the parameter for any reason. */ +#if defined(DWARF_FORMAT_AVAILABLE) + +/* Converts a dynamic property into a static one. FRAME is the frame in which + the property is evaluated; if NULL, the selected frame (if any) is used + instead. + + ADDR_STACK is the stack of addresses that might be needed to evaluate the + property. When evaluating a property that is not related to a type, it can + be NULL. + + Returns true if PROP could be converted and the static value is passed + back into VALUE, otherwise returns false. + + Any values in PUSH_VALUES will be pushed before evaluating the location + expression, PUSH_VALUES[0] will be pushed first, then PUSH_VALUES[1], + etc. This means the during evaluation PUSH_VALUES[0] will be at the + bottom of the stack. */ + +bool dwarf2_evaluate_property (const struct dynamic_prop *prop, + const frame_info_ptr &frame, + const property_addr_info *addr_stack, + CORE_ADDR *value, + gdb::array_view<CORE_ADDR> push_values = {}); + extern struct value *value_of_dwarf_reg_entry (struct type *type, const frame_info_ptr &frame, enum call_site_parameter_kind kind, union call_site_parameter_u kind_u); + +#else /* DWARF_FORMAT_AVAILABLE */ + +static inline bool +dwarf2_evaluate_property (const struct dynamic_prop *, const frame_info_ptr &, + const property_addr_info *, CORE_ADDR *, + gdb::array_view<CORE_ADDR> = {}) +{ + return false; +} + +static inline struct value * +value_of_dwarf_reg_entry (struct type *type, const frame_info_ptr &frame, + enum call_site_parameter_kind kind, + union call_site_parameter_u kind_u) +{ + error (_("No dwarf support available.")); +} + +#endif /* DWARF_FORMAT_AVAILABLE */ + #endif /* GDB_DWARF2_LOC_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/public.h b/gdb/dwarf2/public.h index ed504c6..f9e7488 100644 --- a/gdb/dwarf2/public.h +++ b/gdb/dwarf2/public.h @@ -30,6 +30,8 @@ enum class dw_index_kind DEBUG_NAMES, }; +#if defined(DWARF_FORMAT_AVAILABLE) + /* Try to locate the sections we need for DWARF 2 debugging information. If these are found, begin reading the DWARF and return true. Otherwise, return false. NAMES points to the dwarf2 @@ -44,4 +46,27 @@ extern bool dwarf2_initialize_objfile extern void dwarf2_build_frame_info (struct objfile *); +/* Append the DWARF-2 frame unwinders to GDBARCH's list. */ + +void dwarf2_append_unwinders (struct gdbarch *gdbarch); + +#else /* DWARF_FORMAT_AVAILABLE */ + +static inline bool +dwarf2_initialize_objfile (struct objfile *, + const struct dwarf2_debug_sections * = nullptr, + bool = false) +{ + warning (_("No dwarf support available.")); + return false; +} + +static inline void +dwarf2_build_frame_info (struct objfile *) +{ + warning (_("No dwarf support available.")); +} + +#endif /* DWARF_FORMAT_AVAILABLE */ + #endif /* GDB_DWARF2_PUBLIC_H */ diff --git a/gdb/dwarf2/read-debug-names.c b/gdb/dwarf2/read-debug-names.c index 11de986..97677c0 100644 --- a/gdb/dwarf2/read-debug-names.c +++ b/gdb/dwarf2/read-debug-names.c @@ -114,6 +114,14 @@ struct mapped_debug_names_reader gdb::unordered_map<ULONGEST, index_val> abbrev_map; + /* List of CUs in the same order as found in the index header (DWARF 5 section + 6.1.1.4.2). */ + std::vector<dwarf2_per_cu *> comp_units; + + /* List of local TUs in the same order as found in the index (DWARF 5 section + 6.1.1.4.3). */ + std::vector<dwarf2_per_cu *> type_units; + /* Even though the scanning of .debug_names and creation of the cooked index entries is done serially, we create multiple shards so that the finalization step can be parallelized. The shards @@ -232,7 +240,7 @@ mapped_debug_names_reader::scan_one_entry (const char *name, case DW_IDX_compile_unit: { /* Don't crash on bad data. */ - if (ull >= per_objfile->per_bfd->all_comp_units.size ()) + if (ull >= this->comp_units.size ()) { complaint (_(".debug_names entry has bad CU index %s" " [in module %s]"), @@ -240,30 +248,31 @@ mapped_debug_names_reader::scan_one_entry (const char *name, bfd_get_filename (abfd)); continue; } + + per_cu = this->comp_units[ull]; + break; } - per_cu = per_objfile->per_bfd->get_cu (ull); - break; case DW_IDX_type_unit: - /* Don't crash on bad data. */ - if (ull >= per_objfile->per_bfd->all_type_units.size ()) - { - complaint (_(".debug_names entry has bad TU index %s" - " [in module %s]"), - pulongest (ull), - bfd_get_filename (abfd)); - continue; - } { - int nr_cus = per_objfile->per_bfd->all_comp_units.size (); - per_cu = per_objfile->per_bfd->get_cu (nr_cus + ull); + /* Don't crash on bad data. */ + if (ull >= this->type_units.size ()) + { + complaint (_(".debug_names entry has bad TU index %s" + " [in module %s]"), + pulongest (ull), + bfd_get_filename (abfd)); + continue; + } + + per_cu = this->type_units[ull]; + break; } - break; case DW_IDX_die_offset: die_offset = sect_offset (ull); /* In a per-CU index (as opposed to a per-module index), index entries without CU attribute implicitly refer to the single CU. */ - if (per_cu == NULL) - per_cu = per_objfile->per_bfd->get_cu (0); + if (per_cu == nullptr) + per_cu = this->comp_units[0]; break; case DW_IDX_parent: parent = ull; @@ -416,15 +425,11 @@ cooked_index_worker_debug_names::do_reading () { complaint_interceptor complaint_handler; - try + /* Arbitrarily put all exceptions into the first result. */ + m_map.indices[0].catch_error ([&] () { m_map.scan_all_names (); - } - catch (gdb_exception &exc) - { - /* Arbitrarily put all exceptions into the first result. */ - m_map.indices[0].note_error (std::move (exc)); - } + }); bool first = true; for (auto &iter : m_map.indices) @@ -444,45 +449,45 @@ cooked_index_worker_debug_names::do_reading () bfd_thread_cleanup (); } -/* Check the signatured type hash table from .debug_names. */ +/* Build the list of TUs (mapped_debug_names_reader::type_units) from the index + header and verify that it matches the list of TUs read from the DIEs in + `.debug_info`. + + Return true if they match, false otherwise. */ static bool -check_signatured_type_table_from_debug_names - (dwarf2_per_objfile *per_objfile, - const mapped_debug_names_reader &map, - struct dwarf2_section_info *section) +build_and_check_tu_list_from_debug_names (dwarf2_per_objfile *per_objfile, + mapped_debug_names_reader &map, + dwarf2_section_info *section) { struct objfile *objfile = per_objfile->objfile; dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; - int nr_cus = per_bfd->all_comp_units.size (); - int nr_cus_tus = per_bfd->all_units.size (); section->read (objfile); - uint32_t j = nr_cus; for (uint32_t i = 0; i < map.tu_count; ++i) { + /* Read one entry from the TU list. */ sect_offset sect_off = (sect_offset) (extract_unsigned_integer (map.tu_table_reordered + i * map.offset_size, map.offset_size, map.dwarf5_byte_order)); - bool found = false; - for (; j < nr_cus_tus; j++) - if (per_bfd->get_cu (j)->sect_off == sect_off) - { - found = true; - break; - } - if (!found) + /* Find the matching dwarf2_per_cu. */ + dwarf2_per_cu *per_cu = dwarf2_find_unit ({ section, sect_off }, + per_bfd); + + if (per_cu == nullptr || !per_cu->is_debug_types) { warning (_("Section .debug_names has incorrect entry in TU table," " ignoring .debug_names.")); return false; } - per_bfd->all_comp_units_index_tus.push_back (per_bfd->get_cu (j)); + + map.type_units.emplace_back (per_cu); } + return true; } @@ -704,40 +709,11 @@ read_debug_names_from_section (dwarf2_per_objfile *per_objfile, list. */ static bool -check_cus_from_debug_names_list (dwarf2_per_bfd *per_bfd, - const mapped_debug_names_reader &map, - dwarf2_section_info §ion, - bool is_dwz) +build_and_check_cu_list_from_debug_names (dwarf2_per_bfd *per_bfd, + mapped_debug_names_reader &map, + dwarf2_section_info §ion) { - int nr_cus = per_bfd->all_comp_units.size (); - - if (!map.augmentation_is_gdb) - { - uint32_t j = 0; - for (uint32_t i = 0; i < map.cu_count; ++i) - { - sect_offset sect_off - = (sect_offset) (extract_unsigned_integer - (map.cu_table_reordered + i * map.offset_size, - map.offset_size, - map.dwarf5_byte_order)); - bool found = false; - for (; j < nr_cus; j++) - if (per_bfd->get_cu (j)->sect_off == sect_off) - { - found = true; - break; - } - if (!found) - { - warning (_("Section .debug_names has incorrect entry in CU table," - " ignoring .debug_names.")); - return false; - } - per_bfd->all_comp_units_index_cus.push_back (per_bfd->get_cu (j)); - } - return true; - } + int nr_cus = per_bfd->num_comp_units; if (map.cu_count != nr_cus) { @@ -753,35 +729,43 @@ check_cus_from_debug_names_list (dwarf2_per_bfd *per_bfd, (map.cu_table_reordered + i * map.offset_size, map.offset_size, map.dwarf5_byte_order)); - if (sect_off != per_bfd->get_cu (i)->sect_off) + + /* Find the matching dwarf2_per_cu. */ + dwarf2_per_cu *per_cu = dwarf2_find_unit ({ §ion, sect_off }, per_bfd); + + if (per_cu == nullptr || per_cu->is_debug_types) { warning (_("Section .debug_names has incorrect entry in CU table," " ignoring .debug_names.")); return false; } + + map.comp_units.emplace_back (per_cu); } return true; } -/* Read the CU list from the mapped index, and use it to create all - the CU objects for this dwarf2_per_objfile. */ +/* Build the list of CUs (mapped_debug_names_reader::compile_units) from the + index header and verify that it matches the list of CUs read from the DIEs in + `.debug_info`. + + Return true if they match, false otherwise. */ static bool -check_cus_from_debug_names (dwarf2_per_bfd *per_bfd, - const mapped_debug_names_reader &map, - const mapped_debug_names_reader &dwz_map) +build_and_check_cu_lists_from_debug_names (dwarf2_per_bfd *per_bfd, + mapped_debug_names_reader &map, + mapped_debug_names_reader &dwz_map) { - if (!check_cus_from_debug_names_list (per_bfd, map, per_bfd->infos[0], - false /* is_dwz */)) + if (!build_and_check_cu_list_from_debug_names (per_bfd, map, + per_bfd->infos[0])) return false; if (dwz_map.cu_count == 0) return true; dwz_file *dwz = per_bfd->get_dwz_file (); - return check_cus_from_debug_names_list (per_bfd, dwz_map, dwz->info, - true /* is_dwz */); + return build_and_check_cu_list_from_debug_names (per_bfd, dwz_map, dwz->info); } /* This does all the work for dwarf2_read_debug_names, but putting it @@ -819,7 +803,7 @@ do_dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile) } create_all_units (per_objfile); - if (!check_cus_from_debug_names (per_bfd, map, dwz_map)) + if (!build_and_check_cu_lists_from_debug_names (per_bfd, map, dwz_map)) return false; if (map.tu_count != 0) @@ -835,8 +819,8 @@ do_dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile) ? &per_bfd->types[0] : &per_bfd->infos[0]); - if (!check_signatured_type_table_from_debug_names (per_objfile, - map, section)) + if (!build_and_check_tu_list_from_debug_names (per_objfile, map, + section)) return false; } diff --git a/gdb/dwarf2/read-gdb-index.c b/gdb/dwarf2/read-gdb-index.c index 2029c3e..76317fe 100644 --- a/gdb/dwarf2/read-gdb-index.c +++ b/gdb/dwarf2/read-gdb-index.c @@ -117,6 +117,10 @@ struct mapped_gdb_index : public dwarf_scanner_base /* Index data format version. */ int version = 0; + /* Compile units followed by type units, in the order as found in the + index. Indices found in index entries can index directly into this. */ + std::vector<dwarf2_per_cu *> units; + /* The address table data. */ gdb::array_view<const gdb_byte> address_table; @@ -1106,14 +1110,14 @@ dw2_expand_marked_cus (dwarf2_per_objfile *per_objfile, offset_type idx, } /* Don't crash on bad data. */ - if (cu_index >= per_objfile->per_bfd->all_units.size ()) + if (cu_index >= index.units.size ()) { complaint (_(".gdb_index entry has bad CU index" " [in module %s]"), objfile_name (per_objfile->objfile)); continue; } - dwarf2_per_cu *per_cu = per_objfile->per_bfd->get_cu (cu_index); + dwarf2_per_cu *per_cu = index.units[cu_index]; if (!dw2_expand_symtabs_matching_one (per_cu, per_objfile, file_matcher, expansion_notify, lang_matcher)) @@ -1313,7 +1317,7 @@ static void create_cus_from_gdb_index_list (dwarf2_per_bfd *per_bfd, const gdb_byte *cu_list, offset_type n_elements, struct dwarf2_section_info *section, - int is_dwz) + int is_dwz, std::vector<dwarf2_per_cu *> &units) { for (offset_type i = 0; i < n_elements; i += 2) { @@ -1324,10 +1328,10 @@ create_cus_from_gdb_index_list (dwarf2_per_bfd *per_bfd, ULONGEST length = extract_unsigned_integer (cu_list + 8, 8, BFD_ENDIAN_LITTLE); cu_list += 2 * 8; - per_bfd->all_units.emplace_back (per_bfd->allocate_per_cu (section, - sect_off, - length, - is_dwz)); + dwarf2_per_cu_up per_cu = per_bfd->allocate_per_cu (section, sect_off, + length, is_dwz); + units.emplace_back (per_cu.get ()); + per_bfd->all_units.emplace_back (std::move (per_cu)); } } @@ -1337,20 +1341,21 @@ create_cus_from_gdb_index_list (dwarf2_per_bfd *per_bfd, static void create_cus_from_gdb_index (dwarf2_per_bfd *per_bfd, const gdb_byte *cu_list, offset_type cu_list_elements, + std::vector<dwarf2_per_cu *> &units, const gdb_byte *dwz_list, offset_type dwz_elements) { gdb_assert (per_bfd->all_units.empty ()); per_bfd->all_units.reserve ((cu_list_elements + dwz_elements) / 2); create_cus_from_gdb_index_list (per_bfd, cu_list, cu_list_elements, - &per_bfd->infos[0], 0); + &per_bfd->infos[0], 0, units); if (dwz_elements == 0) return; dwz_file *dwz = per_bfd->get_dwz_file (); create_cus_from_gdb_index_list (per_bfd, dwz_list, dwz_elements, - &dwz->info, 1); + &dwz->info, 1, units); } /* Create the signatured type hash table from the index. */ @@ -1358,7 +1363,8 @@ create_cus_from_gdb_index (dwarf2_per_bfd *per_bfd, static void create_signatured_type_table_from_gdb_index (dwarf2_per_bfd *per_bfd, struct dwarf2_section_info *section, - const gdb_byte *bytes, offset_type elements) + const gdb_byte *bytes, offset_type elements, + std::vector<dwarf2_per_cu *> &units) { signatured_type_set sig_types_hash; @@ -1382,6 +1388,7 @@ create_signatured_type_table_from_gdb_index sig_type->type_offset_in_tu = type_offset_in_tu; sig_types_hash.emplace (sig_type.get ()); + units.emplace_back (sig_type.get ()); per_bfd->all_units.emplace_back (sig_type.release ()); } @@ -1419,14 +1426,14 @@ create_addrmap_from_gdb_index (dwarf2_per_objfile *per_objfile, continue; } - if (cu_index >= per_bfd->all_units.size ()) + if (cu_index >= index->units.size ()) { complaint (_(".gdb_index address table has invalid CU number %u"), (unsigned) cu_index); continue; } - mutable_map.set_empty (lo, hi - 1, per_bfd->get_cu (cu_index)); + mutable_map.set_empty (lo, hi - 1, index->units[cu_index]); } index->index_addrmap @@ -1528,8 +1535,8 @@ dwarf2_read_gdb_index } } - create_cus_from_gdb_index (per_bfd, cu_list, cu_list_elements, dwz_list, - dwz_list_elements); + create_cus_from_gdb_index (per_bfd, cu_list, cu_list_elements, map->units, + dwz_list, dwz_list_elements); if (types_list_elements) { @@ -1548,7 +1555,8 @@ dwarf2_read_gdb_index : &per_bfd->infos[0]); create_signatured_type_table_from_gdb_index (per_bfd, section, types_list, - types_list_elements); + types_list_elements, + map->units); } finalize_all_units (per_bfd); @@ -1562,10 +1570,7 @@ dwarf2_read_gdb_index return true; } -void _initialize_read_gdb_index (); - -void -_initialize_read_gdb_index () +INIT_GDB_FILE (read_gdb_index) { add_setshow_boolean_cmd ("use-deprecated-index-sections", no_class, &use_deprecated_index_sections, _("\ diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 794c397..ec8d376 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -31,7 +31,7 @@ #include "dwarf2/abbrev.h" #include "dwarf2/aranges.h" #include "dwarf2/attribute.h" -#include "dwarf2/comp-unit-head.h" +#include "dwarf2/unit-head.h" #include "dwarf2/cooked-index-worker.h" #include "dwarf2/cooked-indexer.h" #include "dwarf2/cu.h" @@ -52,6 +52,7 @@ #include "event-top.h" #include "exceptions.h" #include "gdbsupport/task-group.h" +#include "maint.h" #include "symtab.h" #include "gdbtypes.h" #include "objfiles.h" @@ -279,7 +280,7 @@ struct dwo_sections struct dwarf2_section_info str; struct dwarf2_section_info str_offsets; /* In the case of a virtual DWO file, these two are unused. */ - struct dwarf2_section_info info; + std::vector<dwarf2_section_info> infos; std::vector<dwarf2_section_info> types; }; @@ -288,24 +289,29 @@ struct dwo_sections struct dwo_unit { /* Backlink to the containing struct dwo_file. */ - struct dwo_file *dwo_file; + struct dwo_file *dwo_file = nullptr; /* The "id" that distinguishes this CU/TU. .debug_info calls this "dwo_id", .debug_types calls this "signature". Since signatures came first, we stick with it for consistency. */ - ULONGEST signature; + ULONGEST signature = 0; /* The section this CU/TU lives in, in the DWO file. */ - struct dwarf2_section_info *section; + dwarf2_section_info *section = nullptr; + + /* This is set if SECTION is owned by this dwo_unit. */ + dwarf2_section_info_up section_holder; /* Same as dwarf2_per_cu::{sect_off,length} but in the DWO section. */ - sect_offset sect_off; - unsigned int length; + sect_offset sect_off {}; + unsigned int length = 0; /* For types, offset in the type's DIE of the type defined by this TU. */ cu_offset type_offset_in_tu; }; +using dwo_unit_up = std::unique_ptr<dwo_unit>; + /* Hash function for dwo_unit objects, based on the signature. */ struct dwo_unit_hash @@ -315,7 +321,7 @@ struct dwo_unit_hash std::size_t operator() (ULONGEST signature) const noexcept { return signature; } - std::size_t operator() (const dwo_unit *unit) const noexcept + std::size_t operator() (const dwo_unit_up &unit) const noexcept { return (*this) (unit->signature); } }; @@ -329,16 +335,16 @@ struct dwo_unit_eq { using is_transparent = void; - bool operator() (ULONGEST sig, const dwo_unit *unit) const noexcept + bool operator() (ULONGEST sig, const dwo_unit_up &unit) const noexcept { return sig == unit->signature; } - bool operator() (const dwo_unit *a, const dwo_unit *b) const noexcept + bool operator() (const dwo_unit_up &a, const dwo_unit_up &b) const noexcept { return (*this) (a->signature, b); } }; /* Set of dwo_unit object, using their signature as identity. */ -using dwo_unit_set = gdb::unordered_set<dwo_unit *, dwo_unit_hash, dwo_unit_eq>; +using dwo_unit_set = gdb::unordered_set<dwo_unit_up, dwo_unit_hash, dwo_unit_eq>; /* include/dwarf2.h defines the DWP section codes. It defines a max value but it doesn't define a min value, which we @@ -598,6 +604,11 @@ struct dwp_file dwo_unit_set loaded_cus; dwo_unit_set loaded_tus; +#if CXX_STD_THREAD + /* Mutex to synchronize access to LOADED_CUS and LOADED_TUS. */ + std::mutex loaded_cutus_lock; +#endif + /* Table to map ELF section numbers to their sections. This is only needed for the DWP V1 file format. */ unsigned int num_sections = 0; @@ -622,15 +633,21 @@ struct variant_field /* A variant can contain other variant parts. */ std::vector<variant_part_builder> variant_parts; - /* If we see a DW_TAG_variant, then this will be set if this is the - default branch. */ - bool default_branch = false; /* If we see a DW_AT_discr_value, then this will be the discriminant - value. */ - ULONGEST discriminant_value = 0; + value. Just the attribute is stored here, because we have to + defer deciding whether the value is signed or unsigned until the + end. */ + const attribute *discriminant_attr = nullptr; /* If we see a DW_AT_discr_list, then this is a pointer to the list data. */ struct dwarf_block *discr_list_data = nullptr; + + /* If both DW_AT_discr_value and DW_AT_discr_list are absent, then + this is the default branch. */ + bool is_default () const + { + return discriminant_attr == nullptr && discr_list_data == nullptr; + } }; /* This represents a DW_TAG_variant_part. */ @@ -727,9 +744,6 @@ show_dwarf_synchronous (struct ui_file *file, int from_tty, /* local function prototypes */ -static void build_type_psymtabs_reader (cutu_reader *reader, - cooked_index_worker_result *storage); - static void var_decode_location (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu); @@ -742,9 +756,9 @@ static unrelocated_addr read_addr_index (struct dwarf2_cu *cu, static sect_offset read_abbrev_offset (dwarf2_per_objfile *per_objfile, dwarf2_section_info *, sect_offset); -static const char *read_indirect_string - (dwarf2_per_objfile *per_objfile, bfd *, const gdb_byte *, - const struct comp_unit_head *, unsigned int *); +static const char *read_indirect_string (dwarf2_per_objfile *per_objfile, bfd *, + const gdb_byte *, const unit_head *, + unsigned int *); static unrelocated_addr read_addr_index_from_leb128 (struct dwarf2_cu *, const gdb_byte *, @@ -1039,14 +1053,7 @@ static struct dwo_unit *lookup_dwo_unit_in_dwp (dwarf2_per_bfd *per_bfd, struct dwp_file *dwp_file, const char *comp_dir, ULONGEST signature, int is_debug_types); -static struct dwp_file *get_dwp_file (dwarf2_per_objfile *per_objfile); - -static struct dwo_unit *lookup_dwo_comp_unit - (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir, - ULONGEST signature); - -static struct dwo_unit *lookup_dwo_type_unit - (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir); +static void open_and_init_dwp_file (dwarf2_per_objfile *per_objfile); static void queue_and_load_all_dwo_tus (dwarf2_cu *cu); @@ -1289,7 +1296,16 @@ 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) + { + warning (_("%s"), err.what ()); + } + + try + { + open_and_init_dwp_file (per_objfile); } catch (const gdb_exception_error &err) { @@ -1316,7 +1332,7 @@ dwarf2_per_bfd::locate_sections (asection *sectp, bfd_size_type size = sectp->size; warning (_("Discarding section %s which has an invalid size (%s) " "[in module %s]"), - bfd_section_name (sectp), phex_nz (size, sizeof (size)), + bfd_section_name (sectp), phex_nz (size), this->filename ()); } else if (names.info.matches (sectp->name)) @@ -1632,7 +1648,7 @@ dw2_do_instantiate_symtab (dwarf2_per_cu *per_cu, && per_objfile->per_bfd->index_table != NULL && !per_objfile->per_bfd->index_table->version_check () /* DWP files aren't supported yet. */ - && get_dwp_file (per_objfile) == NULL) + && per_objfile->per_bfd->dwp_file == nullptr) queue_and_load_all_dwo_tus (cu); } @@ -1674,6 +1690,7 @@ dwarf2_per_bfd::allocate_per_cu (dwarf2_section_info *section, dwarf2_per_cu_up result (new dwarf2_per_cu (this, section, sect_off, length, is_dwz)); result->index = all_units.size (); + this->num_comp_units++; return result; } @@ -1690,7 +1707,7 @@ dwarf2_per_bfd::allocate_signatured_type (dwarf2_section_info *section, = std::make_unique<signatured_type> (this, section, sect_off, length, is_dwz, signature); result->index = all_units.size (); - tu_stats.nr_tus++; + this->num_type_units++; return result; } @@ -1885,13 +1902,13 @@ dwarf2_base_index_functions::print_stats (struct objfile *objfile, for (int i = 0; i < total; ++i) { - dwarf2_per_cu *per_cu = per_objfile->per_bfd->get_cu (i); + dwarf2_per_cu *per_cu = per_objfile->per_bfd->get_unit (i); if (!per_objfile->symtab_set_p (per_cu)) ++count; } - gdb_printf (_(" Number of read CUs: %d\n"), total - count); - gdb_printf (_(" Number of unread CUs: %d\n"), count); + gdb_printf (_(" Number of read units: %d\n"), total - count); + gdb_printf (_(" Number of unread units: %d\n"), count); } void @@ -2354,6 +2371,24 @@ get_abbrev_section_for_cu (dwarf2_per_cu *this_cu) return abbrev; } +/* "less than" function used to both sort and bisect units in the + `dwarf2_per_bfd::all_units` vector. Return true if the LHS CU comes before + (is "less" than) the section and offset in RHS. + + For simplicity, sort sections by their pointer. This is not ideal, because + it can cause the behavior to change across runs, making some bugs harder to + investigate. An improvement would be for sections to be sorted by their + properties. */ + +static bool +all_units_less_than (const dwarf2_per_cu &lhs, const section_and_offset &rhs) +{ + if (lhs.section != rhs.section) + return lhs.section < rhs.section; + + return lhs.sect_off < rhs.offset; +} + /* Fetch the abbreviation table offset from a comp or type unit header. */ static sect_offset @@ -2383,111 +2418,6 @@ read_abbrev_offset (dwarf2_per_objfile *per_objfile, return (sect_offset) read_offset (abfd, info_ptr, offset_size); } -/* A helper for create_dwo_debug_types_hash_table. Read types from SECTION - and fill them into DWO_FILE's type unit hash table. It will process only - type units, therefore DW_UT_type. */ - -static void -create_dwo_debug_type_hash_table (dwarf2_per_objfile *per_objfile, - dwo_file *dwo_file, dwarf2_section_info *section, - rcuh_kind section_kind) -{ - struct objfile *objfile = per_objfile->objfile; - struct dwarf2_section_info *abbrev_section; - bfd *abfd; - const gdb_byte *info_ptr, *end_ptr; - - abbrev_section = &dwo_file->sections.abbrev; - - dwarf_read_debug_printf ("Reading %s for %s", - section->get_name (), - abbrev_section->get_file_name ()); - - section->read (objfile); - info_ptr = section->buffer; - - if (info_ptr == NULL) - return; - - /* We can't set abfd until now because the section may be empty or - not present, in which case the bfd is unknown. */ - abfd = section->get_bfd_owner (); - - /* We don't use cutu_reader here because we don't need to read - any dies: the signature is in the header. */ - - end_ptr = info_ptr + section->size; - while (info_ptr < end_ptr) - { - const gdb_byte *ptr = info_ptr; - struct comp_unit_head header; - unsigned int length; - - sect_offset sect_off = (sect_offset) (ptr - section->buffer); - - /* Initialize it due to a false compiler warning. */ - header.signature = -1; - header.type_cu_offset_in_tu = (cu_offset) -1; - - /* We need to read the type's signature in order to build the hash - table, but we don't need anything else just yet. */ - - ptr = read_and_check_comp_unit_head (per_objfile, &header, section, - abbrev_section, ptr, section_kind); - - length = header.get_length_with_initial (); - - /* Skip dummy type units. */ - if (ptr >= info_ptr + length - || peek_abbrev_code (abfd, ptr) == 0 - || (header.unit_type != DW_UT_type - && header.unit_type != DW_UT_split_type)) - { - info_ptr += length; - continue; - } - - dwo_unit *dwo_tu - = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack, dwo_unit); - dwo_tu->dwo_file = dwo_file; - dwo_tu->signature = header.signature; - dwo_tu->type_offset_in_tu = header.type_cu_offset_in_tu; - dwo_tu->section = section; - dwo_tu->sect_off = sect_off; - dwo_tu->length = length; - - auto [it, inserted] = dwo_file->tus.emplace (dwo_tu); - if (!inserted) - complaint (_("debug type entry at offset %s is duplicate to" - " the entry at offset %s, signature %s"), - sect_offset_str (sect_off), - sect_offset_str ((*it)->sect_off), - hex_string (header.signature)); - - dwarf_read_debug_printf_v (" offset %s, signature %s", - sect_offset_str (sect_off), - hex_string (header.signature)); - - info_ptr += length; - } -} - -/* Create the hash table of all entries in the .debug_types - (or .debug_types.dwo) section(s). - DWO_FILE is a pointer to the DWO file object. - - Note: This function processes DWO files only, not DWP files. */ - -static void -create_dwo_debug_types_hash_table - (dwarf2_per_objfile *per_objfile, dwo_file *dwo_file, - gdb::array_view<dwarf2_section_info> type_sections) -{ - for (dwarf2_section_info §ion : type_sections) - create_dwo_debug_type_hash_table (per_objfile, dwo_file, §ion, - rcuh_kind::TYPE); -} - /* Add an entry for signature SIG to per_bfd->signatured_types. */ static signatured_type_set::iterator @@ -2502,7 +2432,17 @@ add_type_unit (dwarf2_per_bfd *per_bfd, dwarf2_section_info *section, false /* is_dwz */, sig); signatured_type *sig_type = sig_type_holder.get (); - per_bfd->all_units.emplace_back (sig_type_holder.release ()); + /* Preserve the ordering of per_bfd->all_units. */ + auto insert_it + = std::lower_bound (per_bfd->all_units.begin (), per_bfd->all_units.end (), + sig_type, + [] (const dwarf2_per_cu_up &lhs, + const signatured_type *rhs) { + return all_units_less_than (*lhs, { rhs->section, + rhs->sect_off }); + }); + + per_bfd->all_units.emplace (insert_it, sig_type_holder.release ()); auto emplace_ret = per_bfd->signatured_types.emplace (sig_type); /* Assert that an insertion took place - that there wasn't a type unit with @@ -2586,7 +2526,7 @@ lookup_dwo_signatured_type (struct dwarf2_cu *cu, ULONGEST sig) if (it == dwo_file->tus.end ()) return nullptr; - dwo_unit *dwo_entry = *it; + dwo_unit *dwo_entry = it->get (); /* If the global table doesn't have an entry for this TU, add one. */ if (sig_type_it == per_bfd->signatured_types.end ()) @@ -2610,7 +2550,7 @@ lookup_dwp_signatured_type (struct dwarf2_cu *cu, ULONGEST sig) { dwarf2_per_objfile *per_objfile = cu->per_objfile; dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; - struct dwp_file *dwp_file = get_dwp_file (per_objfile); + dwp_file *dwp_file = per_objfile->per_bfd->dwp_file.get (); gdb_assert (cu->dwo_unit); gdb_assert (dwp_file != NULL); @@ -2652,7 +2592,7 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig) { /* We're in a DWO/DWP file, and we're using .gdb_index. These cases require special processing. */ - if (get_dwp_file (per_objfile) == NULL) + if (per_objfile->per_bfd->dwp_file == nullptr) return lookup_dwo_signatured_type (cu, sig); else return lookup_dwp_signatured_type (cu, sig); @@ -2712,9 +2652,8 @@ cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, die_info *stub_comp_unit_die, const char *stub_comp_dir) { - dwarf2_per_objfile *per_objfile = cu->per_objfile; dwarf2_per_cu *per_cu = cu->per_cu; - struct objfile *objfile = per_objfile->objfile; + struct objfile *objfile = cu->per_objfile->objfile; bfd *abfd; struct dwarf2_section_info *dwo_abbrev_section; @@ -2790,9 +2729,10 @@ cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, { signatured_type *sig_type = (struct signatured_type *) per_cu; - m_info_ptr = read_and_check_comp_unit_head (per_objfile, &cu->header, - section, dwo_abbrev_section, - m_info_ptr, rcuh_kind::TYPE); + m_info_ptr = read_and_check_unit_head (&cu->header, section, + dwo_abbrev_section, m_info_ptr, + ruh_kind::TYPE); + /* This is not an assert because it can be caused by bad debug info. */ if (sig_type->signature != cu->header.signature) { @@ -2808,7 +2748,7 @@ cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, /* For DWOs coming from DWP files, we don't know the CU length nor the type's offset in the TU until now. */ dwo_unit->length = cu->header.get_length_with_initial (); - dwo_unit->type_offset_in_tu = cu->header.type_cu_offset_in_tu; + dwo_unit->type_offset_in_tu = cu->header.type_offset_in_tu; /* Establish the type offset that can be used to lookup the type. For DWO files, we don't know it until now. */ @@ -2817,10 +2757,9 @@ cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, } else { - m_info_ptr - = read_and_check_comp_unit_head (per_objfile, &cu->header, section, - dwo_abbrev_section, m_info_ptr, - rcuh_kind::COMPILE); + m_info_ptr = read_and_check_unit_head (&cu->header, section, + dwo_abbrev_section, m_info_ptr, + ruh_kind::COMPILE); gdb_assert (dwo_unit->sect_off == cu->header.sect_off); /* For DWOs coming from DWP files, we don't know the CU length until now. */ @@ -2873,16 +2812,10 @@ lookup_dwo_id (struct dwarf2_cu *cu, struct die_info* comp_unit_die) Returns nullptr if the specified DWO unit cannot be found. */ -static struct dwo_unit * -lookup_dwo_unit (dwarf2_cu *cu, die_info *comp_unit_die, const char *dwo_name) +dwo_unit * +cutu_reader::lookup_dwo_unit (dwarf2_cu *cu, die_info *comp_unit_die, + const char *dwo_name) { -#if CXX_STD_THREAD - /* We need a lock here to handle the DWO hash table. */ - static std::mutex dwo_lock; - - std::lock_guard<std::mutex> guard (dwo_lock); -#endif - dwarf2_per_cu *per_cu = cu->per_cu; struct dwo_unit *dwo_unit; const char *comp_dir; @@ -3037,26 +2970,26 @@ cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, } /* Get the header. */ - if (to_underlying (cu->header.first_die_cu_offset) != 0 && !rereading_dwo_cu) + if (to_underlying (cu->header.first_die_offset_in_unit) != 0 + && !rereading_dwo_cu) { /* We already have the header, there's no need to read it in again. */ - m_info_ptr += to_underlying (cu->header.first_die_cu_offset); + m_info_ptr += to_underlying (cu->header.first_die_offset_in_unit); } else { if (this_cu.is_debug_types) { - m_info_ptr - = read_and_check_comp_unit_head (&per_objfile, &cu->header, section, - abbrev_section, m_info_ptr, - rcuh_kind::TYPE); + m_info_ptr = read_and_check_unit_head (&cu->header, section, + abbrev_section, m_info_ptr, + ruh_kind::TYPE); /* Since per_cu is the first member of struct signatured_type, we can go from a pointer to one to a pointer to the other. */ sig_type = (struct signatured_type *) &this_cu; gdb_assert (sig_type->signature == cu->header.signature); gdb_assert (sig_type->type_offset_in_tu - == cu->header.type_cu_offset_in_tu); + == cu->header.type_offset_in_tu); gdb_assert (this_cu.sect_off == cu->header.sect_off); /* LENGTH has not been set yet for type units if we're @@ -3069,10 +3002,9 @@ cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, } else { - m_info_ptr - = read_and_check_comp_unit_head (&per_objfile, &cu->header, section, - abbrev_section, m_info_ptr, - rcuh_kind::COMPILE); + m_info_ptr = read_and_check_unit_head (&cu->header, section, + abbrev_section, m_info_ptr, + ruh_kind::COMPILE); gdb_assert (this_cu.sect_off == cu->header.sect_off); this_cu.set_length (cu->header.get_length_with_initial ()); @@ -3204,12 +3136,11 @@ cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, m_info_ptr = section->buffer + to_underlying (this_cu.sect_off); const gdb_byte *begin_info_ptr = m_info_ptr; - m_info_ptr - = read_and_check_comp_unit_head (&per_objfile, &m_new_cu->header, section, - abbrev_section, m_info_ptr, - (this_cu.is_debug_types - ? rcuh_kind::TYPE - : rcuh_kind::COMPILE)); + m_info_ptr = read_and_check_unit_head (&m_new_cu->header, section, + abbrev_section, m_info_ptr, + (this_cu.is_debug_types + ? ruh_kind::TYPE + : ruh_kind::COMPILE)); m_new_cu->str_offsets_base = parent_cu.str_offsets_base; m_new_cu->addr_base = parent_cu.addr_base; @@ -3283,33 +3214,131 @@ get_type_unit_group_key (struct dwarf2_cu *cu, const struct attribute *stmt_list return {cu->dwo_unit, static_cast<sect_offset> (line_offset)}; } -/* Subroutine of dwarf2_build_psymtabs_hard to simplify it. - Process compilation unit THIS_CU for a psymtab. */ +/* A subclass of cooked_index_worker that handles scanning + .debug_info. */ -static void -process_psymtab_comp_unit (dwarf2_per_cu *this_cu, - dwarf2_per_objfile *per_objfile, - cooked_index_worker_result *storage) +class cooked_index_worker_debug_info : public cooked_index_worker +{ +public: + cooked_index_worker_debug_info (dwarf2_per_objfile *per_objfile) + : cooked_index_worker (per_objfile) + { + gdb_assert (is_main_thread ()); + + struct objfile *objfile = per_objfile->objfile; + dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; + + dwarf_read_debug_printf ("Building psymtabs of objfile %s ...", + objfile_name (objfile)); + + per_bfd->map_info_sections (objfile); + } + +private: + void do_reading () override; + + /* Print collected type unit statistics. */ + + void print_tu_stats (dwarf2_per_objfile *per_objfile) + { + dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; + tu_stats *tu_stats = &per_bfd->tu_stats; + + dwarf_read_debug_printf ("Type unit statistics:"); + dwarf_read_debug_printf (" %d TUs", per_bfd->num_type_units); + dwarf_read_debug_printf (" %d uniq abbrev tables", + tu_stats->nr_uniq_abbrev_tables); + dwarf_read_debug_printf (" %d symtabs from stmt_list entries", + tu_stats->nr_symtabs); + dwarf_read_debug_printf (" %d symtab sharers", + tu_stats->nr_symtab_sharers); + dwarf_read_debug_printf (" %d type units without a stmt_list", + tu_stats->nr_stmt_less_type_units); + dwarf_read_debug_printf (" %d all_type_units reallocs", + tu_stats->nr_all_type_units_reallocs); + } + + void print_stats () override + { + if (dwarf_read_debug > 0) + print_tu_stats (m_per_objfile); + + if (dwarf_read_debug > 1) + { + dwarf_read_debug_printf_v ("Final m_all_parents_map:"); + m_all_parents_map.dump (m_per_objfile->per_bfd); + } + } + + /* After the last DWARF-reading task has finished, this function + does the remaining work to finish the scan. */ + void done_reading () override; + + /* An iterator for the comp units. */ + using unit_iterator = std::vector<dwarf2_per_cu_up>::iterator; + + /* Process a batch of CUs. This may be called multiple times in + separate threads. TASK_NUMBER indicates which task this is -- + the result is stored in that slot of M_RESULTS. */ + void process_units (size_t task_number, unit_iterator first, + unit_iterator end); + + /* Process unit THIS_CU. */ + void process_unit (dwarf2_per_cu *this_cu, dwarf2_per_objfile *per_objfile, + cooked_index_worker_result *storage); + + /* Process all type units existing in PER_OBJFILE::PER_BFD::ALL_UNITS. */ + void process_type_units (dwarf2_per_objfile *per_objfile, + cooked_index_worker_result *storage); + + /* Process the type unit wrapped in READER. */ + void process_type_unit (cutu_reader *reader, + cooked_index_worker_result *storage); + + /* Process all type units of all DWO files. + + This is needed in case a TU was emitted without its skeleton. + Note: This can't be done until we know what all the DWO files are. */ + void process_skeletonless_type_units (dwarf2_per_objfile *per_objfile, + cooked_index_worker_result *storage); + + /* Process the type unit represented by DWO_UNIT. */ + void process_skeletonless_type_unit (dwo_unit *dwo_unit, + dwarf2_per_objfile *per_objfile, + cooked_index_worker_result *storage); + + /* A storage object for "leftovers" -- see the 'start' method, but + essentially things not parsed during the normal CU parsing + passes. */ + cooked_index_worker_result m_index_storage; +}; + +void +cooked_index_worker_debug_info::process_unit + (dwarf2_per_cu *this_cu, dwarf2_per_objfile *per_objfile, + cooked_index_worker_result *storage) { cutu_reader *reader = storage->get_reader (this_cu); if (reader == nullptr) { - cutu_reader new_reader (*this_cu, *per_objfile, nullptr, nullptr, false, - language_minimal, - &storage->get_abbrev_table_cache ()); + const abbrev_table_cache &abbrev_table_cache + = storage->get_abbrev_table_cache (); + auto new_reader = std::make_unique<cutu_reader> (*this_cu, *per_objfile, + nullptr, nullptr, false, + language_minimal, + &abbrev_table_cache); - if (new_reader.cu () == nullptr || new_reader.is_dummy ()) + if (new_reader->is_dummy ()) return; - auto copy = std::make_unique<cutu_reader> (std::move (new_reader)); - reader = storage->preserve (std::move (copy)); + reader = storage->preserve (std::move (new_reader)); } - if (reader->top_level_die () == nullptr || reader->is_dummy ()) + if (reader->is_dummy ()) return; if (this_cu->is_debug_types) - build_type_psymtabs_reader (reader, storage); + process_type_unit (reader, storage); else if (reader->top_level_die ()->tag != DW_TAG_partial_unit) { bool nope = false; @@ -3322,11 +3351,9 @@ process_psymtab_comp_unit (dwarf2_per_cu *this_cu, } } -/* Reader function for build_type_psymtabs. */ - -static void -build_type_psymtabs_reader (cutu_reader *reader, - cooked_index_worker_result *storage) +void +cooked_index_worker_debug_info::process_type_unit + (cutu_reader *reader, cooked_index_worker_result *storage) { struct dwarf2_cu *cu = reader->cu (); dwarf2_per_cu *per_cu = cu->per_cu; @@ -3360,32 +3387,15 @@ struct tu_abbrev_offset sect_offset abbrev_offset; }; -/* Efficiently read all the type units. - - The efficiency is because we sort TUs by the abbrev table they use and - only read each abbrev table once. In one program there are 200K TUs - sharing 8K abbrev tables. - - The main purpose of this function is to support building the - dwarf2_per_objfile->per_bfd->type_unit_groups table. - TUs typically share the DW_AT_stmt_list of the CU they came from, so we - can collapse the search space by grouping them by stmt_list. - The savings can be significant, in the same program from above the 200K TUs - share 8K stmt_list tables. - - FUNC is expected to call get_type_unit_group, which will create the - struct type_unit_group if necessary and add it to - dwarf2_per_objfile->per_bfd->type_unit_groups. */ - -static void -build_type_psymtabs (dwarf2_per_objfile *per_objfile, - cooked_index_worker_result *storage) +void +cooked_index_worker_debug_info::process_type_units + (dwarf2_per_objfile *per_objfile, cooked_index_worker_result *storage) { struct tu_stats *tu_stats = &per_objfile->per_bfd->tu_stats; abbrev_table_up abbrev_table; sect_offset abbrev_offset; - if (per_objfile->per_bfd->all_type_units.size () == 0) + if (per_objfile->per_bfd->num_type_units == 0) return; /* TUs typically share abbrev tables, and there can be way more TUs than @@ -3412,7 +3422,7 @@ build_type_psymtabs (dwarf2_per_objfile *per_objfile, /* Sort in a separate table to maintain the order of all_units for .gdb_index: TU indices directly index all_type_units. */ std::vector<tu_abbrev_offset> sorted_by_abbrev; - sorted_by_abbrev.reserve (per_objfile->per_bfd->all_type_units.size ()); + sorted_by_abbrev.reserve (per_objfile->per_bfd->num_type_units); for (const auto &cu : per_objfile->per_bfd->all_units) if (cu->is_debug_types) @@ -3445,38 +3455,17 @@ build_type_psymtabs (dwarf2_per_objfile *per_objfile, abbrev_table.get (), nullptr, false, language_minimal); if (!reader.is_dummy ()) - build_type_psymtabs_reader (&reader, storage); + storage->catch_error ([&] () + { + process_type_unit (&reader, storage); + }); } } -/* Print collected type unit statistics. */ - -static void -print_tu_stats (dwarf2_per_objfile *per_objfile) -{ - struct tu_stats *tu_stats = &per_objfile->per_bfd->tu_stats; - - dwarf_read_debug_printf ("Type unit statistics:"); - dwarf_read_debug_printf (" %d TUs", tu_stats->nr_tus); - dwarf_read_debug_printf (" %d uniq abbrev tables", - tu_stats->nr_uniq_abbrev_tables); - dwarf_read_debug_printf (" %d symtabs from stmt_list entries", - tu_stats->nr_symtabs); - dwarf_read_debug_printf (" %d symtab sharers", - tu_stats->nr_symtab_sharers); - dwarf_read_debug_printf (" %d type units without a stmt_list", - tu_stats->nr_stmt_less_type_units); - dwarf_read_debug_printf (" %d all_type_units reallocs", - tu_stats->nr_all_type_units_reallocs); -} - -/* Traversal function for process_skeletonless_type_units. - Read a TU in a DWO file and build partial symbols for it. */ - -static void -process_skeletonless_type_unit (dwo_unit *dwo_unit, - dwarf2_per_objfile *per_objfile, - cooked_index_worker_result *storage) +void +cooked_index_worker_debug_info::process_skeletonless_type_unit + (dwo_unit *dwo_unit, dwarf2_per_objfile *per_objfile, + cooked_index_worker_result *storage) { dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; @@ -3498,82 +3487,29 @@ process_skeletonless_type_unit (dwo_unit *dwo_unit, cutu_reader reader (**sig_type_it, *per_objfile, nullptr, nullptr, false, language_minimal); if (!reader.is_dummy ()) - build_type_psymtabs_reader (&reader, storage); + process_type_unit (&reader, storage); } -/* Scan all TUs of DWO files, verifying we've processed them. - This is needed in case a TU was emitted without its skeleton. - Note: This can't be done until we know what all the DWO files are. */ - -static void -process_skeletonless_type_units (dwarf2_per_objfile *per_objfile, - cooked_index_worker_result *storage) +void +cooked_index_worker_debug_info::process_skeletonless_type_units + (dwarf2_per_objfile *per_objfile, cooked_index_worker_result *storage) { + scoped_time_it time_it ("DWARF skeletonless type units", m_per_command_time); + /* Skeletonless TUs in DWP files without .gdb_index is not supported yet. */ - if (get_dwp_file (per_objfile) == nullptr) + if (per_objfile->per_bfd->dwp_file == nullptr) for (const dwo_file_up &file : per_objfile->per_bfd->dwo_files) - for (dwo_unit *unit : file->tus) - process_skeletonless_type_unit (unit, per_objfile, storage); + for (const dwo_unit_up &unit : file->tus) + storage->catch_error ([&] () + { + process_skeletonless_type_unit (unit.get (), per_objfile, storage); + }); } -/* A subclass of cooked_index_worker that handles scanning - .debug_info. */ - -class cooked_index_worker_debug_info : public cooked_index_worker -{ -public: - cooked_index_worker_debug_info (dwarf2_per_objfile *per_objfile) - : cooked_index_worker (per_objfile) - { - gdb_assert (is_main_thread ()); - - struct objfile *objfile = per_objfile->objfile; - dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; - - dwarf_read_debug_printf ("Building psymtabs of objfile %s ...", - objfile_name (objfile)); - - per_bfd->map_info_sections (objfile); - } - -private: - - void do_reading () override; - - void print_stats () override - { - if (dwarf_read_debug > 0) - print_tu_stats (m_per_objfile); - if (dwarf_read_debug > 1) - { - dwarf_read_debug_printf_v ("Final m_all_parents_map:"); - m_all_parents_map.dump (m_per_objfile->per_bfd); - } - } - - /* After the last DWARF-reading task has finished, this function - does the remaining work to finish the scan. */ - void done_reading () override; - - /* An iterator for the comp units. */ - using unit_iterator = std::vector<dwarf2_per_cu_up>::iterator; - - /* Process a batch of CUs. This may be called multiple times in - separate threads. TASK_NUMBER indicates which task this is -- - the result is stored in that slot of M_RESULTS. */ - void process_cus (size_t task_number, unit_iterator first, - unit_iterator end); - - /* A storage object for "leftovers" -- see the 'start' method, but - essentially things not parsed during the normal CU parsing - passes. */ - cooked_index_worker_result m_index_storage; -}; - void -cooked_index_worker_debug_info::process_cus (size_t task_number, - unit_iterator first, - unit_iterator end) +cooked_index_worker_debug_info::process_units (size_t task_number, + unit_iterator first, + unit_iterator end) { SCOPE_EXIT { bfd_thread_cleanup (); }; @@ -3586,14 +3522,10 @@ cooked_index_worker_debug_info::process_cus (size_t task_number, { dwarf2_per_cu *per_cu = inner->get (); - try + thread_storage.catch_error ([&] () { - process_psymtab_comp_unit (per_cu, m_per_objfile, &thread_storage); - } - catch (gdb_exception &except) - { - thread_storage.note_error (std::move (except)); - } + process_unit (per_cu, m_per_objfile, &thread_storage); + }); } thread_storage.done_reading (complaint_handler.release ()); @@ -3618,7 +3550,7 @@ cooked_index_worker_debug_info::do_reading () dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd; create_all_units (m_per_objfile); - build_type_psymtabs (m_per_objfile, &m_index_storage); + process_type_units (m_per_objfile, &m_index_storage); if (!per_bfd->debug_aranges.empty ()) read_addrmap_from_aranges (m_per_objfile, &per_bfd->debug_aranges, @@ -3671,7 +3603,8 @@ cooked_index_worker_debug_info::do_reading () gdb_assert (iter != last); workers.add_task ([this, task_count, iter, last] () { - process_cus (task_count, iter, last); + scoped_time_it time_it ("DWARF indexing worker", m_per_command_time); + process_units (task_count, iter, last); }); ++task_count; @@ -3688,10 +3621,11 @@ read_comp_units_from_section (dwarf2_per_objfile *per_objfile, struct dwarf2_section_info *abbrev_section, unsigned int is_dwz, signatured_type_set &sig_types, - rcuh_kind section_kind) + ruh_kind section_kind) { const gdb_byte *info_ptr; struct objfile *objfile = per_objfile->objfile; + dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; dwarf_read_debug_printf ("Reading %s for %s", section->get_name (), @@ -3707,23 +3641,22 @@ read_comp_units_from_section (dwarf2_per_objfile *per_objfile, sect_offset sect_off = (sect_offset) (info_ptr - section->buffer); - comp_unit_head cu_header; - read_and_check_comp_unit_head (per_objfile, &cu_header, section, - abbrev_section, info_ptr, - section_kind); + unit_head cu_header; + read_and_check_unit_head (&cu_header, section, abbrev_section, info_ptr, + section_kind); unsigned int length = cu_header.get_length_with_initial (); /* Save the compilation unit for later lookup. */ if (cu_header.unit_type != DW_UT_type) - this_cu - = per_objfile->per_bfd->allocate_per_cu (section, sect_off, length, is_dwz); + this_cu = per_bfd->allocate_per_cu (section, sect_off, length, is_dwz); else { - auto sig_type = per_objfile->per_bfd->allocate_signatured_type - (section, sect_off, length, is_dwz, cu_header.signature); + auto sig_type + = per_bfd->allocate_signatured_type (section, sect_off, length, + is_dwz, cu_header.signature); signatured_type *sig_ptr = sig_type.get (); - sig_type->type_offset_in_tu = cu_header.type_cu_offset_in_tu; + sig_type->type_offset_in_tu = cu_header.type_offset_in_tu; this_cu.reset (sig_type.release ()); auto inserted = sig_types.emplace (sig_ptr).second; @@ -3737,20 +3670,22 @@ read_comp_units_from_section (dwarf2_per_objfile *per_objfile, } info_ptr = info_ptr + this_cu->length (); - per_objfile->per_bfd->all_units.push_back (std::move (this_cu)); + per_bfd->all_units.push_back (std::move (this_cu)); } } -/* Initialize the views on all_units. */ +/* See read.h. */ void finalize_all_units (dwarf2_per_bfd *per_bfd) { - size_t nr_tus = per_bfd->tu_stats.nr_tus; - size_t nr_cus = per_bfd->all_units.size () - nr_tus; - gdb::array_view<dwarf2_per_cu_up> tmp = per_bfd->all_units; - per_bfd->all_comp_units = tmp.slice (0, nr_cus); - per_bfd->all_type_units = tmp.slice (nr_cus, nr_tus); + /* Ensure that the all_units vector is in the expected order for + dwarf2_find_containing_unit to be able to perform a binary search. */ + std::sort (per_bfd->all_units.begin (), per_bfd->all_units.end (), + [] (const dwarf2_per_cu_up &a, const dwarf2_per_cu_up &b) + { + return all_units_less_than (*a, { b->section, b->sect_off }); + }); } /* See read.h. */ @@ -3765,17 +3700,17 @@ create_all_units (dwarf2_per_objfile *per_objfile) for (dwarf2_section_info §ion : per_objfile->per_bfd->infos) read_comp_units_from_section (per_objfile, §ion, &per_objfile->per_bfd->abbrev, 0, sig_types, - rcuh_kind::COMPILE); + ruh_kind::COMPILE); for (dwarf2_section_info §ion : per_objfile->per_bfd->types) read_comp_units_from_section (per_objfile, §ion, &per_objfile->per_bfd->abbrev, 0, sig_types, - rcuh_kind::TYPE); + ruh_kind::TYPE); dwz_file *dwz = per_objfile->per_bfd->get_dwz_file (); if (dwz != NULL) { read_comp_units_from_section (per_objfile, &dwz->info, &dwz->abbrev, 1, - sig_types, rcuh_kind::COMPILE); + sig_types, ruh_kind::COMPILE); if (!dwz->types.empty ()) { @@ -3896,11 +3831,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 +3850,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: @@ -5003,6 +4941,21 @@ process_full_type_unit (dwarf2_cu *cu) cu->reset_builder (); } +/* See read.h. */ + +const dwarf2_section_info & +get_section_for_ref (const attribute &attr, dwarf2_cu *cu) +{ + gdb_assert (attr.form_is_ref ()); + + if (attr.form_is_alt ()) + return cu->per_cu->per_bfd->get_dwz_file (true)->info; + + /* If the source is already in the supplementary (dwz) file, then CU->SECTION + already represents the section in the supplementary file. */ + return cu->section (); +} + /* Process an imported unit DIE. */ static void @@ -5022,12 +4975,11 @@ process_imported_unit_die (struct die_info *die, struct dwarf2_cu *cu) attr = dwarf2_attr (die, DW_AT_import, cu); if (attr != NULL) { + const dwarf2_section_info §ion = get_section_for_ref (*attr, cu); sect_offset sect_off = attr->get_ref_die_offset (); - bool is_dwz = (attr->form == DW_FORM_GNU_ref_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, - per_objfile->per_bfd); + = dwarf2_find_containing_unit ({ §ion, sect_off }, per_objfile); /* We're importing a C++ compilation unit with tag DW_TAG_compile_unit into another compilation unit, at root level. Regard this as a hint, @@ -5952,7 +5904,7 @@ find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu) && res.get_name () != nullptr && IS_ABSOLUTE_PATH (res.get_name ())) { - res.set_comp_dir (ldirname (res.get_name ())); + res.set_comp_dir (gdb_ldirname (res.get_name ())); res.set_name (make_unique_xstrdup (lbasename (res.get_name ()))); } @@ -6148,6 +6100,20 @@ read_file_scope (struct die_info *die, struct dwarf2_cu *cu) } } +/* See cu.h. + + This function is defined in this file (instead of cu.c) because it needs + to see the definition of struct dwo_unit. */ + +const dwarf2_section_info & +dwarf2_cu::section () const +{ + if (this->dwo_unit != nullptr) + return *this->dwo_unit->section; + else + return *this->per_cu->section; +} + void dwarf2_cu::setup_type_unit_groups (struct die_info *die) { @@ -6299,86 +6265,158 @@ static dwo_file * lookup_dwo_file (dwarf2_per_bfd *per_bfd, const char *dwo_name, const char *comp_dir) { +#if CXX_STD_THREAD + std::lock_guard<std::mutex> guard (per_bfd->dwo_files_lock); +#endif + auto it = per_bfd->dwo_files.find (dwo_file_search {dwo_name, comp_dir}); return it != per_bfd->dwo_files.end () ? it->get() : nullptr; } -/* Create the dwo_units for the CUs in a DWO_FILE. - Note: This function processes DWO files only, not DWP files. */ +/* Add DWO_FILE to the per-BFD DWO file hash table. -static void -create_dwo_cus_hash_table (dwarf2_cu *cu, dwo_file &dwo_file) + Return the dwo_file actually kept in the hash table. + + If another thread raced with this one, opening the exact same DWO file and + inserting it first in the hash table, then keep that other thread's copy + and DWO_FILE gets freed. */ + +static dwo_file * +add_dwo_file (dwarf2_per_bfd *per_bfd, dwo_file_up dwo_file) { - dwarf2_per_objfile *per_objfile = cu->per_objfile; - struct objfile *objfile = per_objfile->objfile; - dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; - const gdb_byte *info_ptr, *end_ptr; - auto §ion = dwo_file.sections.info; +#if CXX_STD_THREAD + std::lock_guard<std::mutex> lock (per_bfd->dwo_files_lock); +#endif + + return per_bfd->dwo_files.emplace (std::move (dwo_file)).first->get (); +} + +void +cutu_reader::create_dwo_unit_hash_tables (dwo_file &dwo_file, + dwarf2_cu &skeleton_cu, + dwarf2_section_info §ion, + ruh_kind section_kind) +{ + dwarf2_per_objfile &per_objfile = *skeleton_cu.per_objfile; + dwarf2_per_bfd &per_bfd = *per_objfile.per_bfd; - section.read (objfile); - info_ptr = section.buffer; + const gdb_byte *info_ptr = section.buffer; if (info_ptr == NULL) return; - dwarf_read_debug_printf ("Reading %s for %s:", - section.get_name (), + dwarf_read_debug_printf ("Reading %s for %s:", section.get_name (), section.get_file_name ()); - end_ptr = info_ptr + section.size; + const gdb_byte *end_ptr = info_ptr + section.size; + while (info_ptr < end_ptr) { sect_offset sect_off = (sect_offset) (info_ptr - section.buffer); + unit_head header; + dwarf2_section_info *abbrev_section = &dwo_file.sections.abbrev; + const gdb_byte *info_ptr_post_header + = read_and_check_unit_head (&header, §ion, abbrev_section, + info_ptr, section_kind); - /* The length of the CU gets set by the cutu_reader just below. */ - dwarf2_per_cu per_cu (per_bfd, §ion, sect_off, 0 /* length */, - false /* is_dwz */); - cutu_reader reader (per_cu, *per_objfile, language_minimal, - *cu, dwo_file); - - info_ptr += per_cu.length (); + unsigned int length = header.get_length_with_initial (); + info_ptr += length; - if (reader.is_dummy()) + /* Skip dummy units. */ + if (info_ptr_post_header >= info_ptr + || peek_abbrev_code (section.get_bfd_owner (), + info_ptr_post_header) == 0) continue; - /* DWARF 5 .debug_info.dwo sections may contain some type units. Skip - everything that is not a compile unit. */ - if (const auto ut = reader.cu ()->header.unit_type; - ut != DW_UT_compile && ut != DW_UT_split_compile) + if (header.unit_type != DW_UT_compile + && header.unit_type != DW_UT_split_compile + && header.unit_type != DW_UT_type + && header.unit_type != DW_UT_split_type) continue; - std::optional<ULONGEST> signature - = lookup_dwo_id (reader.cu (), reader.top_level_die ()); - if (!signature.has_value ()) + ULONGEST signature; + + /* For type units (all DWARF versions) and DWARF 5 compile units, the + signature/DWO ID is already available in the header. For compile + units in DWARF < 5, we need to read the DW_AT_GNU_dwo_id attribute + from the top-level DIE. + + For DWARF < 5 compile units, the unit type will be set to DW_UT_compile + by read_and_check_comp_unit_head. */ + if (header.version < 5 && header.unit_type == DW_UT_compile) { - complaint (_(DWARF_ERROR_PREFIX - "debug entry at offset %s is missing its dwo_id" - " [in module %s]"), - sect_offset_str (sect_off), - dwo_file.dwo_name.c_str ()); - continue; + /* The length of the CU is not necessary. */ + dwarf2_per_cu per_cu (&per_bfd, §ion, sect_off, length, + false /* is_dwz */); + cutu_reader reader (per_cu, per_objfile, language_minimal, + skeleton_cu, dwo_file); + + std::optional<ULONGEST> opt_signature + = lookup_dwo_id (reader.cu (), reader.top_level_die ()); + + if (!opt_signature.has_value ()) + { + complaint (_ (DWARF_ERROR_PREFIX + "debug entry at offset %s is missing its dwo_id" + " [in module %s]"), + sect_offset_str (sect_off), + dwo_file.dwo_name.c_str ()); + continue; + } + + signature = *opt_signature; } + else + signature = header.signature; - dwo_unit *dwo_unit = OBSTACK_ZALLOC (&per_bfd->obstack, struct dwo_unit); + auto dwo_unit = std::make_unique<struct dwo_unit> (); + /* Set the fields common to compile and type units. */ dwo_unit->dwo_file = &dwo_file; - dwo_unit->signature = *signature; + dwo_unit->signature = signature; dwo_unit->section = §ion; dwo_unit->sect_off = sect_off; - dwo_unit->length = per_cu.length (); + dwo_unit->length = length; - dwarf_read_debug_printf (" offset %s, dwo_id %s", - sect_offset_str (sect_off), - hex_string (dwo_unit->signature)); + switch (header.unit_type) + { + case DW_UT_compile: + case DW_UT_split_compile: + { + dwarf_read_debug_printf (" compile unit at offset %s, dwo_id %s", + sect_offset_str (sect_off), + hex_string (dwo_unit->signature)); - auto [it, inserted] = dwo_file.cus.emplace (dwo_unit); - if (!inserted) - complaint (_("debug cu entry at offset %s is duplicate to" - " the entry at offset %s, signature %s"), - sect_offset_str (sect_off), - sect_offset_str ((*it)->sect_off), - hex_string (dwo_unit->signature)); + auto [it, inserted] = dwo_file.cus.emplace (std::move (dwo_unit)); + if (!inserted) + complaint (_("debug cu entry at offset %s is duplicate to" + " the entry at offset %s, signature %s"), + sect_offset_str (sect_off), + sect_offset_str ((*it)->sect_off), + hex_string (dwo_unit->signature)); + break; + } + + case DW_UT_type: + case DW_UT_split_type: + { + dwo_unit->type_offset_in_tu = header.type_offset_in_tu; + + dwarf_read_debug_printf (" type unit at offset %s, signature %s", + sect_offset_str (sect_off), + hex_string (dwo_unit->signature)); + + auto [it, inserted] = dwo_file.tus.emplace (std::move (dwo_unit)); + if (!inserted) + complaint (_("debug type entry at offset %s is duplicate to" + " the entry at offset %s, signature %s"), + sect_offset_str (sect_off), + sect_offset_str ((*it)->sect_off), + hex_string (header.signature)); + break; + } + } } } @@ -6536,27 +6574,18 @@ create_dwo_cus_hash_table (dwarf2_cu *cu, dwo_file &dwo_file) Note: This function processes DWP files only, not DWO files. */ static struct dwp_hash_table * -create_dwp_hash_table (dwarf2_per_objfile *per_objfile, - struct dwp_file *dwp_file, int is_debug_types) +create_dwp_hash_table (dwarf2_per_bfd *per_bfd, struct dwp_file *dwp_file, + dwarf2_section_info &index) { - struct objfile *objfile = per_objfile->objfile; bfd *dbfd = dwp_file->dbfd.get (); - const gdb_byte *index_ptr, *index_end; - struct dwarf2_section_info *index; uint32_t version, nr_columns, nr_units, nr_slots; struct dwp_hash_table *htab; - if (is_debug_types) - index = &dwp_file->sections.tu_index; - else - index = &dwp_file->sections.cu_index; - - if (index->empty ()) + if (index.empty ()) return NULL; - index->read (objfile); - index_ptr = index->buffer; - index_end = index_ptr + index->size; + const gdb_byte *index_ptr = index.buffer; + const gdb_byte *index_end = index_ptr + index.size; /* For Version 5, the version is really 2 bytes of data & 2 bytes of padding. For now it's safe to just read 4 bytes (particularly as it's difficult to @@ -6587,7 +6616,7 @@ create_dwp_hash_table (dwarf2_per_objfile *per_objfile, pulongest (nr_slots), dwp_file->name); } - htab = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack, struct dwp_hash_table); + htab = OBSTACK_ZALLOC (&per_bfd->obstack, struct dwp_hash_table); htab->version = version; htab->nr_columns = nr_columns; htab->nr_units = nr_units; @@ -6859,7 +6888,7 @@ locate_v1_virtual_dwo_sections (asection *sectp, COMP_DIR is the DW_AT_comp_dir attribute of the referencing CU. This is for DWP version 1 files. */ -static struct dwo_unit * +static dwo_unit_up create_dwo_unit_in_dwp_v1 (dwarf2_per_bfd *per_bfd, struct dwp_file *dwp_file, uint32_t unit_index, @@ -6982,19 +7011,17 @@ create_dwo_unit_in_dwp_v1 (dwarf2_per_bfd *per_bfd, types we'll grow the vector and eventually have to reallocate space for it, invalidating all copies of pointers into the previous contents. */ - auto [it, inserted] - = per_bfd->dwo_files.emplace (std::move (new_dwo_file)); - gdb_assert (inserted); - dwo_file = it->get (); + dwo_file = add_dwo_file (per_bfd, std::move (new_dwo_file)); } else dwarf_read_debug_printf ("Using existing virtual DWO: %s", virtual_dwo_name.c_str ()); - dwo_unit *dwo_unit = OBSTACK_ZALLOC (&per_bfd->obstack, struct dwo_unit); + auto dwo_unit = std::make_unique<struct dwo_unit> (); dwo_unit->dwo_file = dwo_file; dwo_unit->signature = signature; - dwo_unit->section = XOBNEW (&per_bfd->obstack, struct dwarf2_section_info); + dwo_unit->section_holder = std::make_unique<dwarf2_section_info> (); + dwo_unit->section = dwo_unit->section_holder.get (); *dwo_unit->section = sections.info_or_types; /* dwo_unit->{offset,length,type_offset_in_tu} are set later. */ @@ -7052,7 +7079,7 @@ create_dwp_v2_or_v5_section (dwarf2_per_bfd *per_bfd, COMP_DIR is the DW_AT_comp_dir attribute of the referencing CU. This is for DWP version 2 files. */ -static struct dwo_unit * +static dwo_unit_up create_dwo_unit_in_dwp_v2 (dwarf2_per_bfd *per_bfd, struct dwp_file *dwp_file, uint32_t unit_index, @@ -7187,19 +7214,17 @@ create_dwo_unit_in_dwp_v2 (dwarf2_per_bfd *per_bfd, types we'll grow the vector and eventually have to reallocate space for it, invalidating all copies of pointers into the previous contents. */ - auto [it, inserted] - = per_bfd->dwo_files.emplace (std::move (new_dwo_file)); - gdb_assert (inserted); - dwo_file = it->get (); + dwo_file = add_dwo_file (per_bfd, std::move (new_dwo_file)); } else dwarf_read_debug_printf ("Using existing virtual DWO: %s", virtual_dwo_name.c_str ()); - dwo_unit *dwo_unit = OBSTACK_ZALLOC (&per_bfd->obstack, struct dwo_unit); + auto dwo_unit = std::make_unique<struct dwo_unit> (); dwo_unit->dwo_file = dwo_file; dwo_unit->signature = signature; - dwo_unit->section = XOBNEW (&per_bfd->obstack, struct dwarf2_section_info); + dwo_unit->section_holder = std::make_unique<dwarf2_section_info> (); + dwo_unit->section = dwo_unit->section_holder.get (); *dwo_unit->section = create_dwp_v2_or_v5_section (per_bfd, is_debug_types @@ -7217,7 +7242,7 @@ create_dwo_unit_in_dwp_v2 (dwarf2_per_bfd *per_bfd, COMP_DIR is the DW_AT_comp_dir attribute of the referencing CU. This is for DWP version 5 files. */ -static struct dwo_unit * +static dwo_unit_up create_dwo_unit_in_dwp_v5 (dwarf2_per_bfd *per_bfd, struct dwp_file *dwp_file, uint32_t unit_index, @@ -7357,16 +7382,13 @@ create_dwo_unit_in_dwp_v5 (dwarf2_per_bfd *per_bfd, types we'll grow the vector and eventually have to reallocate space for it, invalidating all copies of pointers into the previous contents. */ - auto [it, inserted] - = per_bfd->dwo_files.emplace (std::move (new_dwo_file)); - gdb_assert (inserted); - dwo_file = it->get (); + dwo_file = add_dwo_file (per_bfd, std::move (new_dwo_file)); } else dwarf_read_debug_printf ("Using existing virtual DWO: %s", virtual_dwo_name.c_str ()); - dwo_unit *dwo_unit = OBSTACK_ZALLOC (&per_bfd->obstack, struct dwo_unit); + auto dwo_unit = std::make_unique<struct dwo_unit> (); dwo_unit->dwo_file = dwo_file; dwo_unit->signature = signature; dwo_unit->section @@ -7397,9 +7419,15 @@ lookup_dwo_unit_in_dwp (dwarf2_per_bfd *per_bfd, auto &dwo_unit_set = is_debug_types ? dwp_file->loaded_tus : dwp_file->loaded_cus; - if (auto it = dwo_unit_set.find (signature); - it != dwo_unit_set.end ()) - return *it; + { +#if CXX_STD_THREAD + std::lock_guard<std::mutex> guard (dwp_file->loaded_cutus_lock); +#endif + + if (auto it = dwo_unit_set.find (signature); + it != dwo_unit_set.end ()) + return it->get (); + } /* Use a for loop so that we don't loop forever on bad debug info. */ for (unsigned int i = 0; i < dwp_htab->nr_slots; ++i) @@ -7413,7 +7441,7 @@ lookup_dwo_unit_in_dwp (dwarf2_per_bfd *per_bfd, uint32_t unit_index = read_4_bytes (dbfd, dwp_htab->unit_table + hash * sizeof (uint32_t)); - dwo_unit *dwo_unit; + dwo_unit_up dwo_unit; if (dwp_file->version == 1) dwo_unit @@ -7428,9 +7456,14 @@ lookup_dwo_unit_in_dwp (dwarf2_per_bfd *per_bfd, = create_dwo_unit_in_dwp_v5 (per_bfd, dwp_file, unit_index, comp_dir, signature, is_debug_types); - auto [it, inserted] = dwo_unit_set.emplace (dwo_unit); - gdb_assert (inserted); - return *it; + /* If another thread raced with this one, opening the exact same + DWO unit, then we'll keep that other thread's copy. */ +#if CXX_STD_THREAD + std::lock_guard<std::mutex> guard (dwp_file->loaded_cutus_lock); +#endif + + auto it = dwo_unit_set.emplace (std::move (dwo_unit)).first; + return it->get (); } if (signature_in_table == 0) @@ -7486,7 +7519,7 @@ try_open_dwop_file (dwarf2_per_bfd *per_bfd, const char *file_name, int is_dwp, search_path = per_bfd->captured_debug_dir.c_str (); /* Add the path for the executable binary to the list of search paths. */ - std::string objfile_dir = ldirname (per_bfd->filename ()); + std::string objfile_dir = gdb_ldirname (per_bfd->filename ()); search_path_holder.reset (concat (objfile_dir.c_str (), dirname_separator_string, search_path, nullptr)); @@ -7507,14 +7540,23 @@ try_open_dwop_file (dwarf2_per_bfd *per_bfd, const char *file_name, int is_dwp, if (sym_bfd == NULL) return NULL; - if (!bfd_check_format (sym_bfd.get (), bfd_object)) - return NULL; + { +#if CXX_STD_THREAD + /* The operations below are not thread-safe, use a lock to synchronize + concurrent accesses. */ + static std::mutex mutex; + std::lock_guard<std::mutex> lock (mutex); +#endif - /* Success. Record the bfd as having been included by the objfile's bfd. + if (!bfd_check_format (sym_bfd.get (), bfd_object)) + return NULL; + + /* Success. Record the bfd as having been included by the objfile's bfd. This is important because things like demangled_names_hash lives in the objfile's per_bfd space and may have references to things like symbol names that live in the DWO/DWP file's per_bfd space. PR 16426. */ - gdb_bfd_record_inclusion (per_bfd->obfd, sym_bfd.get ()); + gdb_bfd_record_inclusion (per_bfd->obfd, sym_bfd.get ()); + } return sym_bfd; } @@ -7526,9 +7568,9 @@ try_open_dwop_file (dwarf2_per_bfd *per_bfd, const char *file_name, int is_dwp, Upon success, the canonicalized path of the file is stored in the bfd, same as symfile_bfd_open. */ -static gdb_bfd_ref_ptr -open_dwo_file (dwarf2_per_bfd *per_bfd, const char *file_name, - const char *comp_dir) +gdb_bfd_ref_ptr +cutu_reader::open_dwo_file (dwarf2_per_bfd *per_bfd, const char *file_name, + const char *comp_dir) { if (IS_ABSOLUTE_PATH (file_name)) return try_open_dwop_file (per_bfd, file_name, @@ -7563,48 +7605,67 @@ open_dwo_file (dwarf2_per_bfd *per_bfd, const char *file_name, /* This function is mapped across the sections and remembers the offset and size of each of the DWO debugging sections we are interested in. */ -static void -dwarf2_locate_dwo_sections (struct objfile *objfile, bfd *abfd, - asection *sectp, dwo_sections *dwo_sections) +void +cutu_reader::locate_dwo_sections (objfile *objfile, dwo_file &dwo_file) { const struct dwop_section_names *names = &dwop_section_names; + dwo_sections &dwo_sections = dwo_file.sections; + bool complained_about_macro_already = false; + + for (asection *sec : gdb_bfd_sections (dwo_file.dbfd)) + { + struct dwarf2_section_info *dw_sect = nullptr; + + if (names->abbrev_dwo.matches (sec->name)) + dw_sect = &dwo_sections.abbrev; + else if (names->info_dwo.matches (sec->name)) + dw_sect = &dwo_sections.infos.emplace_back (dwarf2_section_info {}); + else if (names->line_dwo.matches (sec->name)) + dw_sect = &dwo_sections.line; + else if (names->loc_dwo.matches (sec->name)) + dw_sect = &dwo_sections.loc; + else if (names->loclists_dwo.matches (sec->name)) + dw_sect = &dwo_sections.loclists; + else if (names->macinfo_dwo.matches (sec->name)) + dw_sect = &dwo_sections.macinfo; + else if (names->macro_dwo.matches (sec->name)) + { + /* gcc versions <= 13 generate multiple .debug_macro.dwo sections with + some unresolved links between them. It's not usable, so do as if + there were not there. */ + if (!complained_about_macro_already) + { + if (dwo_sections.macro.s.section == nullptr) + dw_sect = &dwo_sections.macro; + else + { + warning (_("Multiple .debug_macro.dwo sections found in " + "%s, ignoring them."), dwo_file.dbfd->filename); - struct dwarf2_section_info *dw_sect = nullptr; - - if (names->abbrev_dwo.matches (sectp->name)) - dw_sect = &dwo_sections->abbrev; - else if (names->info_dwo.matches (sectp->name)) - dw_sect = &dwo_sections->info; - else if (names->line_dwo.matches (sectp->name)) - dw_sect = &dwo_sections->line; - else if (names->loc_dwo.matches (sectp->name)) - dw_sect = &dwo_sections->loc; - else if (names->loclists_dwo.matches (sectp->name)) - dw_sect = &dwo_sections->loclists; - else if (names->macinfo_dwo.matches (sectp->name)) - dw_sect = &dwo_sections->macinfo; - else if (names->macro_dwo.matches (sectp->name)) - dw_sect = &dwo_sections->macro; - else if (names->rnglists_dwo.matches (sectp->name)) - dw_sect = &dwo_sections->rnglists; - else if (names->str_dwo.matches (sectp->name)) - dw_sect = &dwo_sections->str; - else if (names->str_offsets_dwo.matches (sectp->name)) - dw_sect = &dwo_sections->str_offsets; - else if (names->types_dwo.matches (sectp->name)) - { - struct dwarf2_section_info type_section; - - memset (&type_section, 0, sizeof (type_section)); - dwo_sections->types.push_back (type_section); - dw_sect = &dwo_sections->types.back (); - } + dwo_sections.macro = dwarf2_section_info {}; + complained_about_macro_already = true; + } + } + } + else if (names->rnglists_dwo.matches (sec->name)) + dw_sect = &dwo_sections.rnglists; + else if (names->str_dwo.matches (sec->name)) + dw_sect = &dwo_sections.str; + else if (names->str_offsets_dwo.matches (sec->name)) + dw_sect = &dwo_sections.str_offsets; + else if (names->types_dwo.matches (sec->name)) + dw_sect = &dwo_sections.types.emplace_back (dwarf2_section_info {}); + + if (dw_sect != nullptr) + { + /* Make sure we don't overwrite a section info that has been filled in + already. */ + gdb_assert (!dw_sect->readin); - if (dw_sect != nullptr) - { - dw_sect->s.section = sectp; - dw_sect->size = bfd_section_size (sectp); - dw_sect->read (objfile); + dw_sect->s.section = sec; + dw_sect->size = bfd_section_size (sec); + dw_sect->read (objfile); + } } } @@ -7612,9 +7673,9 @@ dwarf2_locate_dwo_sections (struct objfile *objfile, bfd *abfd, by PER_CU. This is for the non-DWP case. The result is NULL if DWO_NAME can't be found. */ -static dwo_file_up -open_and_init_dwo_file (dwarf2_cu *cu, const char *dwo_name, - const char *comp_dir) +dwo_file_up +cutu_reader::open_and_init_dwo_file (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir) { dwarf2_per_objfile *per_objfile = cu->per_objfile; @@ -7632,19 +7693,13 @@ open_and_init_dwo_file (dwarf2_cu *cu, const char *dwo_name, dwo_file->comp_dir = comp_dir; dwo_file->dbfd = std::move (dbfd); - for (asection *sec : gdb_bfd_sections (dwo_file->dbfd)) - dwarf2_locate_dwo_sections (per_objfile->objfile, dwo_file->dbfd.get (), - sec, &dwo_file->sections); + this->locate_dwo_sections (per_objfile->objfile, *dwo_file); - create_dwo_cus_hash_table (cu, *dwo_file); + for (dwarf2_section_info §ion : dwo_file->sections.infos) + create_dwo_unit_hash_tables (*dwo_file, *cu, section, ruh_kind::COMPILE); - if (cu->header.version < 5) - create_dwo_debug_types_hash_table (per_objfile, dwo_file.get (), - dwo_file->sections.types); - else - create_dwo_debug_type_hash_table (per_objfile, dwo_file.get (), - &dwo_file->sections.info, - rcuh_kind::COMPILE); + for (dwarf2_section_info §ion : dwo_file->sections.types) + create_dwo_unit_hash_tables (*dwo_file, *cu, section, ruh_kind::TYPE); dwarf_read_debug_printf ("DWO file found: %s", dwo_name); @@ -7680,6 +7735,10 @@ dwarf2_locate_common_dwp_sections (struct objfile *objfile, bfd *abfd, if (dw_sect != nullptr) { + /* Make sure we don't overwrite a section info that has been filled in + already. */ + gdb_assert (!dw_sect->readin); + dw_sect->s.section = sectp; dw_sect->size = bfd_section_size (sectp); dw_sect->read (objfile); @@ -7725,6 +7784,10 @@ dwarf2_locate_v2_dwp_sections (struct objfile *objfile, bfd *abfd, if (dw_sect != nullptr) { + /* Make sure we don't overwrite a section info that has been filled in + already. */ + gdb_assert (!dw_sect->readin); + dw_sect->s.section = sectp; dw_sect->size = bfd_section_size (sectp); dw_sect->read (objfile); @@ -7768,6 +7831,10 @@ dwarf2_locate_v5_dwp_sections (struct objfile *objfile, bfd *abfd, if (dw_sect != nullptr) { + /* Make sure we don't overwrite a section info that has been filled in + already. */ + gdb_assert (!dw_sect->readin); + dw_sect->s.section = sectp; dw_sect->size = bfd_section_size (sectp); dw_sect->read (objfile); @@ -7810,10 +7877,9 @@ open_dwp_file (dwarf2_per_bfd *per_bfd, const char *file_name) } /* Initialize the use of the DWP file for the current objfile. - By convention the name of the DWP file is ${objfile}.dwp. - The result is NULL if it can't be found. */ + By convention the name of the DWP file is ${objfile}.dwp. */ -static dwp_file_up +static void open_and_init_dwp_file (dwarf2_per_objfile *per_objfile) { struct objfile *objfile = per_objfile->objfile; @@ -7830,7 +7896,7 @@ open_and_init_dwp_file (dwarf2_per_objfile *per_objfile) struct objfile *backlink = objfile->separate_debug_objfile_backlink; const char *backlink_basename = lbasename (backlink->original_name); - dwp_name = ldirname (objfile->original_name) + SLASH_STRING + backlink_basename; + dwp_name = gdb_ldirname (objfile->original_name) + SLASH_STRING + backlink_basename; } else dwp_name = objfile->original_name; @@ -7851,7 +7917,7 @@ open_and_init_dwp_file (dwarf2_per_objfile *per_objfile) { dwarf_read_debug_printf ("DWP file not found: %s", dwp_name.c_str ()); - return dwp_file_up (); + return; } const char *name = bfd_get_filename (dbfd.get ()); @@ -7865,9 +7931,10 @@ open_and_init_dwp_file (dwarf2_per_objfile *per_objfile) dwarf2_locate_common_dwp_sections (objfile, dwp_file->dbfd.get (), sec, dwp_file.get ()); - dwp_file->cus = create_dwp_hash_table (per_objfile, dwp_file.get (), 0); - - dwp_file->tus = create_dwp_hash_table (per_objfile, dwp_file.get (), 1); + dwp_file->cus = create_dwp_hash_table (per_bfd, dwp_file.get (), + dwp_file->sections.cu_index); + dwp_file->tus = create_dwp_hash_table (per_bfd, dwp_file.get (), + dwp_file->sections.tu_index); /* The DWP file version is stored in the hash table. Oh well. */ if (dwp_file->cus && dwp_file->tus @@ -7907,20 +7974,8 @@ open_and_init_dwp_file (dwarf2_per_objfile *per_objfile) bfd_cache_close (dwp_file->dbfd.get ()); - return dwp_file; -} - -/* Wrapper around open_and_init_dwp_file, only open it once. */ - -static struct dwp_file * -get_dwp_file (dwarf2_per_objfile *per_objfile) -{ - if (!per_objfile->per_bfd->dwp_checked) - { - per_objfile->per_bfd->dwp_file = open_and_init_dwp_file (per_objfile); - per_objfile->per_bfd->dwp_checked = 1; - } - return per_objfile->per_bfd->dwp_file.get (); + /* Everything worked, install this dwp_file in the per_bfd. */ + per_objfile->per_bfd->dwp_file = std::move (dwp_file); } /* Subroutine of lookup_dwo_comp_unit, lookup_dwo_type_unit. @@ -7939,22 +7994,23 @@ get_dwp_file (dwarf2_per_objfile *per_objfile) The result is a pointer to the dwo_unit object or NULL if we didn't find it (dwo_id mismatch or couldn't find the DWO/DWP file). */ -static struct dwo_unit * -lookup_dwo_cutu (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir, - ULONGEST signature, int is_debug_types) +dwo_unit * +cutu_reader::lookup_dwo_cutu (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir, ULONGEST signature, + int is_debug_types) { dwarf2_per_objfile *per_objfile = cu->per_objfile; dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; struct objfile *objfile = per_objfile->objfile; const char *kind = is_debug_types ? "TU" : "CU"; - struct dwp_file *dwp_file; /* First see if there's a DWP file. If we have a DWP file but didn't find the DWO inside it, don't look for the original DWO file. It makes gdb behave differently depending on whether one is debugging in the build tree. */ - dwp_file = get_dwp_file (per_objfile); + dwp_file *dwp_file = per_objfile->per_bfd->dwp_file.get (); + if (dwp_file != NULL) { const struct dwp_hash_table *dwp_htab = @@ -7990,12 +8046,7 @@ lookup_dwo_cutu (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir, = open_and_init_dwo_file (cu, dwo_name, comp_dir); if (new_dwo_file != nullptr) - { - auto [it, inserted] - = per_bfd->dwo_files.emplace (std::move (new_dwo_file)); - gdb_assert (inserted); - dwo_file = (*it).get (); - } + dwo_file = add_dwo_file (per_bfd, std::move (new_dwo_file)); } if (dwo_file != NULL) @@ -8006,13 +8057,13 @@ lookup_dwo_cutu (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir, { if (auto it = dwo_file->tus.find (signature); it != dwo_file->tus.end ()) - dwo_cutu = *it; + dwo_cutu = it->get (); } else if (!is_debug_types && !dwo_file->cus.empty ()) { if (auto it = dwo_file->cus.find (signature); it != dwo_file->cus.end ()) - dwo_cutu = *it; + dwo_cutu = it->get (); } if (dwo_cutu != NULL) @@ -8055,9 +8106,9 @@ lookup_dwo_cutu (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir, /* Lookup the DWO CU DWO_NAME/SIGNATURE referenced from THIS_CU. See lookup_dwo_cutu_unit for details. */ -static struct dwo_unit * -lookup_dwo_comp_unit (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir, - ULONGEST signature) +dwo_unit * +cutu_reader::lookup_dwo_comp_unit (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir, ULONGEST signature) { gdb_assert (!cu->per_cu->is_debug_types); @@ -8067,8 +8118,9 @@ lookup_dwo_comp_unit (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir, /* Lookup the DWO TU DWO_NAME/SIGNATURE referenced from THIS_TU. See lookup_dwo_cutu_unit for details. */ -static struct dwo_unit * -lookup_dwo_type_unit (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir) +dwo_unit * +cutu_reader::lookup_dwo_type_unit (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir) { gdb_assert (cu->per_cu->is_debug_types); @@ -8111,15 +8163,15 @@ queue_and_load_all_dwo_tus (dwarf2_cu *cu) gdb_assert (cu != nullptr); gdb_assert (!cu->per_cu->is_debug_types); - gdb_assert (get_dwp_file (cu->per_objfile) == nullptr); + gdb_assert (cu->per_objfile->per_bfd->dwp_file == nullptr); dwo_unit = cu->dwo_unit; gdb_assert (dwo_unit != NULL); dwo_file = dwo_unit->dwo_file; - for (struct dwo_unit *unit : dwo_file->tus) - queue_and_load_dwo_tu (unit, cu); + for (const dwo_unit_up &unit : dwo_file->tus) + queue_and_load_dwo_tu (unit.get (), cu); } /* Read in various DIEs. */ @@ -8795,7 +8847,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) struct dwarf2_locexpr_baton *dlbaton; struct dwarf_block *block = attr->as_block (); - dlbaton = XOBNEW (&objfile->objfile_obstack, struct dwarf2_locexpr_baton); + dlbaton = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwarf2_locexpr_baton); dlbaton->data = block->data; dlbaton->size = block->size; dlbaton->per_objfile = per_objfile; @@ -8894,7 +8947,7 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) parameter->kind = CALL_SITE_PARAMETER_PARAM_OFFSET; sect_offset sect_off = origin->get_ref_die_offset (); - if (!cu->header.offset_in_cu_p (sect_off)) + if (!cu->header.offset_in_unit_p (sect_off)) { /* As DW_OP_GNU_parameter_ref uses CU-relative offset this binding can be done only inside one CU. Such referenced DIE @@ -9262,7 +9315,7 @@ dwarf2_ranges_process (unsigned offset, struct dwarf2_cu *cu, dwarf_tag tag, { dwarf2_per_objfile *per_objfile = cu->per_objfile; struct objfile *objfile = per_objfile->objfile; - struct comp_unit_head *cu_header = &cu->header; + unit_head *cu_header = &cu->header; bfd *obfd = objfile->obfd.get (); unsigned int addr_size = cu_header->addr_size; CORE_ADDR mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1)); @@ -9918,69 +9971,44 @@ dwarf2_access_attribute (struct die_info *die, struct dwarf2_cu *cu) } } -/* Look for DW_AT_data_member_location or DW_AT_data_bit_offset. Set - *OFFSET to the byte offset. If the attribute was not found return - 0, otherwise return 1. If it was found but could not properly be - handled, set *OFFSET to 0. */ +/* Look for DW_AT_data_member_location or DW_AT_data_bit_offset and + store the results in FIELD. */ -static int +static void handle_member_location (struct die_info *die, struct dwarf2_cu *cu, - LONGEST *offset) + struct field *field) { - struct attribute *attr; + const auto data_member_location_attr + = dwarf2_attr (die, DW_AT_data_member_location, cu); - attr = dwarf2_attr (die, DW_AT_data_member_location, cu); - if (attr != NULL) + if (data_member_location_attr != nullptr) { - *offset = 0; - CORE_ADDR temp; + bool has_bit_offset = false; + LONGEST bit_offset = 0; + LONGEST anonymous_size = 0; + const auto bit_offset_attr = dwarf2_attr (die, DW_AT_bit_offset, cu); - /* Note that we do not check for a section offset first here. - This is because DW_AT_data_member_location is new in DWARF 4, - so if we see it, we can assume that a constant form is really - a constant and not a section offset. */ - if (attr->form_is_constant ()) - *offset = attr->constant_value (0); - else if (attr->form_is_section_offset ()) - dwarf2_complex_location_expr_complaint (); - else if (attr->form_is_block () - && decode_locdesc (attr->as_block (), cu, &temp)) + if (bit_offset_attr != nullptr && bit_offset_attr->form_is_constant ()) { - *offset = temp; - } - else - dwarf2_complex_location_expr_complaint (); - - return 1; - } - else - { - attr = dwarf2_attr (die, DW_AT_data_bit_offset, cu); - if (attr != nullptr) - { - *offset = attr->constant_value (0); - return 1; - } - } - - return 0; -} + has_bit_offset = true; + bit_offset = bit_offset_attr->confused_constant ().value_or (0); -/* Look for DW_AT_data_member_location or DW_AT_data_bit_offset and - store the results in FIELD. */ + const auto byte_size_attr = dwarf2_attr (die, DW_AT_byte_size, cu); -static void -handle_member_location (struct die_info *die, struct dwarf2_cu *cu, - struct field *field) -{ - struct attribute *attr; + if (byte_size_attr != nullptr && byte_size_attr->form_is_constant ()) + { + /* The size of the anonymous object containing + the bit field is explicit, so use the + indicated size (in bytes). */ + anonymous_size + = byte_size_attr->unsigned_constant ().value_or (0); + } + } - attr = dwarf2_attr (die, DW_AT_data_member_location, cu); - if (attr != NULL) - { - if (attr->form_is_constant ()) + if (data_member_location_attr->form_is_constant ()) { - LONGEST offset = attr->constant_value (0); + LONGEST offset + = data_member_location_attr->confused_constant ().value_or (0); /* Work around this GCC 11 bug, where it would erroneously use -1 data member locations, instead of 0: @@ -9995,23 +10023,40 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu, } field->set_loc_bitpos (offset * bits_per_byte); + if (has_bit_offset) + apply_bit_offset_to_field (*field, bit_offset, anonymous_size); } - else if (attr->form_is_section_offset ()) - dwarf2_complex_location_expr_complaint (); - else if (attr->form_is_block ()) + else if (data_member_location_attr->form_is_block ()) { CORE_ADDR offset; - if (decode_locdesc (attr->as_block (), cu, &offset)) - field->set_loc_bitpos (offset * bits_per_byte); + if (decode_locdesc (data_member_location_attr->as_block (), cu, + &offset)) + { + field->set_loc_bitpos (offset * bits_per_byte); + + if (has_bit_offset) + apply_bit_offset_to_field (*field, bit_offset, anonymous_size); + } else { dwarf2_per_objfile *per_objfile = cu->per_objfile; struct objfile *objfile = per_objfile->objfile; - struct dwarf2_locexpr_baton *dlbaton - = XOBNEW (&objfile->objfile_obstack, - struct dwarf2_locexpr_baton); - dlbaton->data = attr->as_block ()->data; - dlbaton->size = attr->as_block ()->size; + struct dwarf2_locexpr_baton *dlbaton; + if (has_bit_offset) + { + dwarf2_field_location_baton *flbaton + = OBSTACK_ZALLOC (&objfile->objfile_obstack, + dwarf2_field_location_baton); + flbaton->is_field_location = true; + flbaton->bit_offset = bit_offset; + flbaton->explicit_byte_size = anonymous_size; + dlbaton = flbaton; + } + else + dlbaton = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwarf2_locexpr_baton); + dlbaton->data = data_member_location_attr->as_block ()->data; + dlbaton->size = data_member_location_attr->as_block ()->size; /* When using this baton, we want to compute the address of the field, not the value. This is why is_reference is set to false here. */ @@ -10019,28 +10064,74 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu, dlbaton->per_objfile = per_objfile; dlbaton->per_cu = cu->per_cu; - field->set_loc_dwarf_block (dlbaton); + field->set_loc_dwarf_block_addr (dlbaton); } } else - dwarf2_complex_location_expr_complaint (); + complaint (_("Unsupported form %s for DW_AT_data_member_location"), + dwarf_form_name (data_member_location_attr->form)); } else { - attr = dwarf2_attr (die, DW_AT_data_bit_offset, cu); - if (attr != nullptr) - field->set_loc_bitpos (attr->constant_value (0)); + const auto data_bit_offset_attr + = dwarf2_attr (die, DW_AT_data_bit_offset, cu); + + if (data_bit_offset_attr != nullptr) + { + if (data_bit_offset_attr->form_is_constant ()) + field->set_loc_bitpos (data_bit_offset_attr->unsigned_constant () + .value_or (0)); + else if (data_bit_offset_attr->form_is_block ()) + { + /* This is a DWARF extension. See + https://dwarfstd.org/issues/250501.1.html. */ + dwarf2_per_objfile *per_objfile = cu->per_objfile; + dwarf2_locexpr_baton *dlbaton + = OBSTACK_ZALLOC (&per_objfile->objfile->objfile_obstack, + dwarf2_locexpr_baton); + dlbaton->data = data_bit_offset_attr->as_block ()->data; + dlbaton->size = data_bit_offset_attr->as_block ()->size; + dlbaton->per_objfile = per_objfile; + dlbaton->per_cu = cu->per_cu; + + field->set_loc_dwarf_block_bitpos (dlbaton); + } + else + complaint (_("Unsupported form %s for DW_AT_data_bit_offset"), + dwarf_form_name (data_bit_offset_attr->form)); + } } } +/* A helper that computes the location of a field. The CU and the + DW_TAG_member DIE are passed in. The results are stored in + *FP. */ + +static void +compute_field_location (dwarf2_cu *cu, die_info *die, field *fp) +{ + /* Get type of field. */ + fp->set_type (die_type (die, cu)); + + fp->set_loc_bitpos (0); + + /* Get bit size of field (zero if none). */ + attribute *attr = dwarf2_attr (die, DW_AT_bit_size, cu); + if (attr != nullptr) + fp->set_bitsize (attr->unsigned_constant ().value_or (0)); + else + fp->set_bitsize (0); + + /* Get bit offset of field. */ + handle_member_location (die, cu, fp); +} + /* Add an aggregate field to the field list. */ static void dwarf2_add_field (struct field_info *fip, struct die_info *die, struct dwarf2_cu *cu) { - struct objfile *objfile = cu->per_objfile->objfile; - struct gdbarch *gdbarch = objfile->arch (); struct nextfield *new_field; struct attribute *attr; struct field *fp; @@ -10090,64 +10181,7 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die, } /* Data member other than a C++ static data member. */ - /* Get type of field. */ - fp->set_type (die_type (die, cu)); - - fp->set_loc_bitpos (0); - - /* Get bit size of field (zero if none). */ - attr = dwarf2_attr (die, DW_AT_bit_size, cu); - if (attr != nullptr) - fp->set_bitsize (attr->constant_value (0)); - else - fp->set_bitsize (0); - - /* Get bit offset of field. */ - handle_member_location (die, cu, fp); - attr = dwarf2_attr (die, DW_AT_bit_offset, cu); - if (attr != nullptr && attr->form_is_constant ()) - { - if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) - { - /* For big endian bits, the DW_AT_bit_offset gives the - additional bit offset from the MSB of the containing - anonymous object to the MSB of the field. We don't - have to do anything special since we don't need to - know the size of the anonymous object. */ - fp->set_loc_bitpos (fp->loc_bitpos () + attr->constant_value (0)); - } - else - { - /* For little endian bits, compute the bit offset to the - MSB of the anonymous object, subtract off the number of - bits from the MSB of the field to the MSB of the - object, and then subtract off the number of bits of - the field itself. The result is the bit offset of - the LSB of the field. */ - int anonymous_size; - int bit_offset = attr->constant_value (0); - - attr = dwarf2_attr (die, DW_AT_byte_size, cu); - if (attr != nullptr && attr->form_is_constant ()) - { - /* The size of the anonymous object containing - the bit field is explicit, so use the - indicated size (in bytes). */ - anonymous_size = attr->constant_value (0); - } - else - { - /* The size of the anonymous object containing - the bit field must be inferred from the type - attribute of the data member containing the - bit field. */ - anonymous_size = fp->type ()->length (); - } - fp->set_loc_bitpos (fp->loc_bitpos () - + anonymous_size * bits_per_byte - - bit_offset - fp->bitsize ()); - } - } + compute_field_location (cu, die, fp); /* Get name of field. */ fieldname = dwarf2_name (die, cu); @@ -10286,13 +10320,19 @@ convert_variant_range (struct obstack *obstack, const variant_field &variant, { std::vector<discriminant_range> ranges; - if (variant.default_branch) + if (variant.is_default ()) return {}; if (variant.discr_list_data == nullptr) { - discriminant_range r - = {variant.discriminant_value, variant.discriminant_value}; + ULONGEST value; + + if (is_unsigned) + value = variant.discriminant_attr->unsigned_constant ().value_or (0); + else + value = variant.discriminant_attr->signed_constant ().value_or (0); + + discriminant_range r = { value, value }; ranges.push_back (r); } else @@ -11106,7 +11146,7 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu) if (attr != nullptr) { if (attr->form_is_constant ()) - type->set_length (attr->constant_value (0)); + type->set_length (attr->unsigned_constant ().value_or (0)); else { struct dynamic_prop prop; @@ -11251,12 +11291,14 @@ handle_variant (struct die_info *die, struct type *type, { discr = dwarf2_attr (die, DW_AT_discr_list, cu); if (discr == nullptr || discr->as_block ()->size == 0) - variant.default_branch = true; + { + /* Nothing to do here -- default branch. */ + } else variant.discr_list_data = discr->as_block (); } else - variant.discriminant_value = discr->constant_value (0); + variant.discriminant_attr = discr; for (die_info *variant_child : die->children ()) handle_struct_member_die (variant_child, type, fi, template_args, cu); @@ -11318,6 +11360,21 @@ handle_struct_member_die (struct die_info *child_die, struct type *type, handle_variant (child_die, type, fi, template_args, cu); } +/* Create a property baton for a field. DIE is the field's DIE. The + baton's "field" member is filled in, but the other members of the + baton are not. The new property baton is returned. */ + +static dwarf2_property_baton * +find_field_create_baton (dwarf2_cu *cu, die_info *die) +{ + dwarf2_property_baton *result + = XOBNEW (&cu->per_objfile->objfile->objfile_obstack, + struct dwarf2_property_baton); + memset (&result->field, 0, sizeof (result->field)); + compute_field_location (cu, die, &result->field); + return result; +} + /* Finish creating a structure or union type, including filling in its members and creating a symbol for it. This function also handles Fortran namelist variables, their items or members and creating a symbol for @@ -11582,25 +11639,30 @@ die_byte_order (die_info *die, dwarf2_cu *cu, enum bfd_endian *byte_order) /* Assuming DIE is an enumeration type, and TYPE is its associated type, update TYPE using some information only available in DIE's - children. In particular, the fields are computed. */ + children. In particular, the fields are computed. If IS_UNSIGNED + is set, the enumeration type's sign is already known (a true value + means unsigned), and so examining the constants to determine the + sign isn't needed; when this is unset, the enumerator constants are + read as signed values. */ static void update_enumeration_type_from_children (struct die_info *die, struct type *type, - struct dwarf2_cu *cu) + struct dwarf2_cu *cu, + std::optional<bool> is_unsigned) { - int unsigned_enum = 1; - int flag_enum = 1; + /* This is used to check whether the enum is signed or unsigned; for + simplicity, it is always correct regardless of whether + IS_UNSIGNED is set. */ + bool unsigned_enum = is_unsigned.value_or (true); + bool flag_enum = true; - auto_obstack obstack; std::vector<struct field> fields; for (die_info *child_die : die->children ()) { struct attribute *attr; LONGEST value; - const gdb_byte *bytes; - struct dwarf2_locexpr_baton *baton; const char *name; if (child_die->tag != DW_TAG_enumerator) @@ -11614,19 +11676,26 @@ update_enumeration_type_from_children (struct die_info *die, if (name == NULL) name = "<anonymous enumerator>"; - dwarf2_const_value_attr (attr, type, name, &obstack, cu, - &value, &bytes, &baton); - if (value < 0) - { - unsigned_enum = 0; - flag_enum = 0; - } + /* Can't check UNSIGNED_ENUM here because that is + optimistic. */ + if (is_unsigned.has_value () && *is_unsigned) + value = attr->unsigned_constant ().value_or (0); else { - if (count_one_bits_ll (value) >= 2) - flag_enum = 0; + /* Read as signed, either because we don't know the sign or + because we know it is definitely signed. */ + value = attr->signed_constant ().value_or (0); + + if (value < 0) + { + unsigned_enum = false; + flag_enum = false; + } } + if (flag_enum && count_one_bits_ll (value) >= 2) + flag_enum = false; + struct field &field = fields.emplace_back (); field.set_name (dwarf2_physname (name, child_die, cu)); field.set_loc_enumval (value); @@ -11635,13 +11704,10 @@ update_enumeration_type_from_children (struct die_info *die, if (!fields.empty ()) type->copy_fields (fields); else - flag_enum = 0; + flag_enum = false; - if (unsigned_enum) - type->set_is_unsigned (true); - - if (flag_enum) - type->set_is_flag_enum (true); + type->set_is_unsigned (unsigned_enum); + type->set_is_flag_enum (flag_enum); } /* Given a DW_AT_enumeration_type die, set its type. We do not @@ -11685,7 +11751,7 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu) attr = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr != nullptr) - type->set_length (attr->constant_value (0)); + type->set_length (attr->unsigned_constant ().value_or (0)); else type->set_length (0); @@ -11699,6 +11765,11 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu) if (die_is_declaration (die, cu)) type->set_is_stub (true); + /* If the underlying type is known, and is unsigned, then we'll + assume the enumerator constants are unsigned. Otherwise we have + to assume they are signed. */ + std::optional<bool> is_unsigned; + /* If this type has an underlying type that is not a stub, then we may use its attributes. We always use the "unsigned" attribute in this situation, because ordinarily we guess whether the type @@ -11711,7 +11782,8 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu) struct type *underlying_type = type->target_type (); underlying_type = check_typedef (underlying_type); - type->set_is_unsigned (underlying_type->is_unsigned ()); + is_unsigned = underlying_type->is_unsigned (); + type->set_is_unsigned (*is_unsigned); if (type->length () == 0) type->set_length (underlying_type->length ()); @@ -11731,7 +11803,7 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu) Note that, as usual, this must come after set_die_type to avoid infinite recursion when trying to compute the names of the enumerators. */ - update_enumeration_type_from_children (die, type, cu); + update_enumeration_type_from_children (die, type, cu, is_unsigned); return type; } @@ -12081,7 +12153,7 @@ read_array_type (struct die_info *die, struct dwarf2_cu *cu) attr = dwarf2_attr (die, DW_AT_bit_stride, cu); if (attr != NULL) - bit_stride = attr->constant_value (0); + bit_stride = attr->unsigned_constant ().value_or (0); /* Irix 6.2 native cc creates array types without children for arrays with unspecified length. */ @@ -12296,7 +12368,8 @@ mark_common_block_symbol_computed (struct symbol *sym, gdb_assert (member_loc->form_is_block () || member_loc->form_is_constant ()); - baton = XOBNEW (&objfile->objfile_obstack, struct dwarf2_locexpr_baton); + baton = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwarf2_locexpr_baton); baton->per_objfile = per_objfile; baton->per_cu = cu->per_cu; gdb_assert (baton->per_cu); @@ -12305,7 +12378,7 @@ mark_common_block_symbol_computed (struct symbol *sym, if (member_loc->form_is_constant ()) { - offset = member_loc->constant_value (0); + offset = member_loc->unsigned_constant ().value_or (0); baton->size += 1 /* DW_OP_addr */ + cu->header.addr_size; } else @@ -12602,7 +12675,7 @@ static struct type * read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *cu) { struct gdbarch *gdbarch = cu->per_objfile->objfile->arch (); - struct comp_unit_head *cu_header = &cu->header; + unit_head *cu_header = &cu->header; struct type *type; struct attribute *attr_byte_size; struct attribute *attr_address_class; @@ -12620,7 +12693,8 @@ read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *cu) attr_byte_size = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr_byte_size) - byte_size = attr_byte_size->constant_value (cu_header->addr_size); + byte_size = (attr_byte_size->unsigned_constant () + .value_or (cu_header->addr_size)); else byte_size = cu_header->addr_size; @@ -12716,7 +12790,7 @@ static struct type * read_tag_reference_type (struct die_info *die, struct dwarf2_cu *cu, enum type_code refcode) { - struct comp_unit_head *cu_header = &cu->header; + unit_head *cu_header = &cu->header; struct type *type, *target_type; struct attribute *attr; @@ -12732,7 +12806,8 @@ read_tag_reference_type (struct die_info *die, struct dwarf2_cu *cu, type = lookup_reference_type (target_type, refcode); attr = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr != nullptr) - type->set_length (attr->constant_value (cu_header->addr_size)); + type->set_length (attr->unsigned_constant () + .value_or (cu_header->addr_size)); else type->set_length (cu_header->addr_size); @@ -12896,9 +12971,7 @@ read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu) len = dwarf2_attr (die, DW_AT_byte_size, cu); if (len != nullptr && len->form_is_constant ()) { - /* Pass 0 as the default as we know this attribute is constant - and the default value will not be returned. */ - LONGEST sz = len->constant_value (0); + LONGEST sz = len->unsigned_constant ().value_or (0); prop_type = objfile_int_type (objfile, sz, true); } else @@ -12917,15 +12990,14 @@ read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu) else if (attr != nullptr) { /* This DW_AT_string_length just contains the length with no - indirection. There's no need to create a dynamic property in this - case. Pass 0 for the default value as we know it will not be - returned in this case. */ - length = attr->constant_value (0); + indirection. There's no need to create a dynamic property in + this case. */ + length = attr->unsigned_constant ().value_or (0); } else if ((attr = dwarf2_attr (die, DW_AT_byte_size, cu)) != nullptr) { /* We don't currently support non-constant byte sizes for strings. */ - length = attr->constant_value (1); + length = attr->unsigned_constant ().value_or (1); } else { @@ -13200,7 +13272,7 @@ read_typedef (struct die_info *die, struct dwarf2_cu *cu) a given gmp_mpz given an attribute. */ static void -get_mpz (struct dwarf2_cu *cu, gdb_mpz *value, struct attribute *attr) +get_mpz_for_rational (dwarf2_cu *cu, gdb_mpz *value, attribute *attr) { /* GCC will sometimes emit a 16-byte constant value as a DWARF location expression that pushes an implicit value. */ @@ -13234,10 +13306,11 @@ get_mpz (struct dwarf2_cu *cu, gdb_mpz *value, struct attribute *attr) ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE, true); } - else if (attr->form_is_unsigned ()) - *value = gdb_mpz (attr->as_unsigned ()); else - *value = gdb_mpz (attr->constant_value (1)); + { + /* Rational constants for Ada are always unsigned. */ + *value = gdb_mpz (attr->unsigned_constant ().value_or (1)); + } } /* Assuming DIE is a rational DW_TAG_constant, read the DIE's @@ -13266,8 +13339,8 @@ get_dwarf2_rational_constant (struct die_info *die, struct dwarf2_cu *cu, if (num_attr == nullptr || denom_attr == nullptr) return; - get_mpz (cu, numerator, num_attr); - get_mpz (cu, denominator, denom_attr); + get_mpz_for_rational (cu, numerator, num_attr); + get_mpz_for_rational (cu, denominator, denom_attr); } /* Same as get_dwarf2_rational_constant, but extracting an unsigned @@ -13416,14 +13489,14 @@ finish_fixed_point_type (struct type *type, const char *suffix, } else if (attr->name == DW_AT_binary_scale) { - LONGEST scale_exp = attr->constant_value (0); + LONGEST scale_exp = attr->signed_constant ().value_or (0); gdb_mpz &num_or_denom = scale_exp > 0 ? scale_num : scale_denom; num_or_denom <<= std::abs (scale_exp); } else if (attr->name == DW_AT_decimal_scale) { - LONGEST scale_exp = attr->constant_value (0); + LONGEST scale_exp = attr->signed_constant ().value_or (0); gdb_mpz &num_or_denom = scale_exp > 0 ? scale_num : scale_denom; num_or_denom = gdb_mpz::pow (10, std::abs (scale_exp)); @@ -13623,7 +13696,6 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu) struct type *type; struct attribute *attr; ULONGEST encoding = 0; - int bits = 0; const char *name; attr = dwarf2_attr (die, DW_AT_encoding, cu); @@ -13633,9 +13705,33 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu) if (value.has_value ()) encoding = *value; } + attr = dwarf2_attr (die, DW_AT_byte_size, cu); + std::optional<ULONGEST> byte_size; + if (attr != nullptr) + byte_size = attr->unsigned_constant (); + attr = dwarf2_attr (die, DW_AT_bit_size, cu); + std::optional<ULONGEST> bit_size; + if (attr != nullptr) + bit_size = attr->unsigned_constant (); + + attr = dwarf2_attr (die, DW_AT_data_bit_offset, cu); + std::optional<ULONGEST> bit_offset; if (attr != nullptr) - bits = attr->constant_value (0) * TARGET_CHAR_BIT; + bit_offset = attr->unsigned_constant (); + + int bits = 0; + if (byte_size.has_value ()) + bits = TARGET_CHAR_BIT * *byte_size; + else if (bit_size.has_value ()) + bits = align_up (*bit_size, 8); + else + { + /* No size, so arrange for an error type. */ + complaint (_("DW_TAG_base_type has neither bit- nor byte-size")); + encoding = (ULONGEST) -1; + } + name = dwarf2_full_name (nullptr, die, cu); if (!name) complaint (_("DW_AT_name missing from DW_TAG_base_type")); @@ -13781,29 +13877,21 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu) type->set_endianity_is_not_default (not_default); - if (TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_INT) + /* If both a byte size and bit size were provided, then that means + that not every bit in the object contributes to the value. */ + if (TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_INT + && byte_size.has_value () + && bit_size.has_value ()) { - attr = dwarf2_attr (die, DW_AT_bit_size, cu); - if (attr != nullptr && attr->form_is_constant ()) + /* DWARF says: If this attribute is omitted a default data bit + offset of zero is assumed. */ + ULONGEST offset = bit_offset.value_or (0); + + /* Only use the attributes if they make sense together. */ + if (*bit_size + offset <= 8 * type->length ()) { - unsigned real_bit_size = attr->constant_value (0); - if (real_bit_size >= 0 && real_bit_size <= 8 * type->length ()) - { - attr = dwarf2_attr (die, DW_AT_data_bit_offset, cu); - /* Only use the attributes if they make sense together. */ - if (attr == nullptr - || (attr->form_is_constant () - && attr->constant_value (0) >= 0 - && (attr->constant_value (0) + real_bit_size - <= 8 * type->length ()))) - { - TYPE_MAIN_TYPE (type)->type_specific.int_stuff.bit_size - = real_bit_size; - if (attr != nullptr) - TYPE_MAIN_TYPE (type)->type_specific.int_stuff.bit_offset - = attr->constant_value (0); - } - } + TYPE_MAIN_TYPE (type)->type_specific.int_stuff.bit_size = *bit_size; + TYPE_MAIN_TYPE (type)->type_specific.int_stuff.bit_offset = offset; } } @@ -13944,17 +14032,13 @@ attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die, case DW_AT_data_member_location: case DW_AT_data_bit_offset: { - LONGEST offset; - - if (!handle_member_location (target_die, target_cu, &offset)) + baton = find_field_create_baton (cu, target_die); + if (baton == nullptr) return 0; - baton = XOBNEW (obstack, struct dwarf2_property_baton); baton->property_type = read_type_die (target_die->parent, - target_cu); - baton->offset_info.offset = offset; - baton->offset_info.type = die_type (target_die, target_cu); - prop->set_addr_offset (baton); + target_cu); + prop->set_field (baton); break; } } @@ -14114,8 +14198,13 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) LONGEST bias = 0; struct attribute *bias_attr = dwarf2_attr (die, DW_AT_GNU_bias, cu); - if (bias_attr != nullptr && bias_attr->form_is_constant ()) - bias = bias_attr->constant_value (0); + if (bias_attr != nullptr) + { + if (base_type->is_unsigned ()) + bias = (LONGEST) bias_attr->unsigned_constant ().value_or (0); + else + bias = bias_attr->signed_constant ().value_or (0); + } /* Normally, the DWARF producers are expected to use a signed constant form (Eg. DW_FORM_sdata) to express negative bounds. @@ -14202,7 +14291,7 @@ read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) attr = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr != nullptr) - range_type->set_length (attr->constant_value (0)); + range_type->set_length (attr->unsigned_constant ().value_or (0)); maybe_set_alignment (cu, die, range_type); @@ -14883,7 +14972,7 @@ cutu_reader::read_attribute_value (attribute *attr, unsigned form, { dwarf2_per_objfile *per_objfile = m_cu->per_objfile; struct objfile *objfile = per_objfile->objfile; - struct comp_unit_head *cu_header = &m_cu->header; + unit_head *cu_header = &m_cu->header; unsigned int bytes_read; struct dwarf_block *blk; @@ -14934,10 +15023,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; @@ -14989,6 +15080,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 @@ -15188,8 +15280,7 @@ read_indirect_string_at_offset (dwarf2_per_objfile *per_objfile, static const char * read_indirect_string (dwarf2_per_objfile *per_objfile, bfd *abfd, - const gdb_byte *buf, - const struct comp_unit_head *cu_header, + const gdb_byte *buf, const unit_head *cu_header, unsigned int *bytes_read_ptr) { LONGEST str_offset = cu_header->read_offset (abfd, buf, bytes_read_ptr); @@ -15213,7 +15304,7 @@ dwarf2_per_objfile::read_line_string (const gdb_byte *buf, const char * dwarf2_per_objfile::read_line_string (const gdb_byte *buf, - const struct comp_unit_head *cu_header, + const unit_head *cu_header, unsigned int *bytes_read_ptr) { bfd *abfd = objfile->obfd.get (); @@ -15346,9 +15437,16 @@ read_str_index (struct dwarf2_cu *cu, " in CU at offset %s [in module %s]"), form_name, str_section->get_name (), sect_offset_str (cu->header.sect_off), objf_name); - info_ptr = (str_offsets_section->buffer - + str_offsets_base - + str_index * offset_size); + + ULONGEST str_offsets_offset = str_offsets_base + str_index * offset_size; + if (str_offsets_offset >= str_offsets_section->size) + error (_(DWARF_ERROR_PREFIX + "Offset from %s pointing outside of %s section in CU at offset %s" + " [in module %s]"), + form_name, str_offsets_section->get_name (), + sect_offset_str (cu->header.sect_off), objf_name); + info_ptr = str_offsets_section->buffer + str_offsets_offset; + if (offset_size == 4) str_offset = bfd_get_32 (abfd, info_ptr); else @@ -16545,7 +16643,7 @@ var_decode_location (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu) { struct objfile *objfile = cu->per_objfile->objfile; - struct comp_unit_head *cu_header = &cu->header; + unit_head *cu_header = &cu->header; /* NOTE drow/2003-01-30: There used to be a comment and some special code here to turn a symbol with DW_AT_external and a @@ -17178,40 +17276,6 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, return (sym); } -/* Given an attr with a DW_FORM_dataN value in host byte order, - zero-extend it as appropriate for the symbol's type. The DWARF - standard (v4) is not entirely clear about the meaning of using - DW_FORM_dataN for a constant with a signed type, where the type is - wider than the data. The conclusion of a discussion on the DWARF - list was that this is unspecified. We choose to always zero-extend - because that is the interpretation long in use by GCC. */ - -static gdb_byte * -dwarf2_const_value_data (const struct attribute *attr, struct obstack *obstack, - struct dwarf2_cu *cu, LONGEST *value, int bits) -{ - struct objfile *objfile = cu->per_objfile->objfile; - enum bfd_endian byte_order = bfd_big_endian (objfile->obfd.get ()) ? - BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE; - LONGEST l = attr->constant_value (0); - - if (bits < sizeof (*value) * 8) - { - l &= ((LONGEST) 1 << bits) - 1; - *value = l; - } - else if (bits == sizeof (*value) * 8) - *value = l; - else - { - gdb_byte *bytes = (gdb_byte *) obstack_alloc (obstack, bits / 8); - store_unsigned_integer (bytes, bits / 8, byte_order, l); - return bytes; - } - - return NULL; -} - /* Read a constant value from an attribute. Either set *VALUE, or if the value does not fit in *VALUE, set *BYTES - either already allocated on the objfile obstack, or newly allocated on OBSTACK, @@ -17227,7 +17291,7 @@ dwarf2_const_value_attr (const struct attribute *attr, struct type *type, { dwarf2_per_objfile *per_objfile = cu->per_objfile; struct objfile *objfile = per_objfile->objfile; - struct comp_unit_head *cu_header = &cu->header; + unit_head *cu_header = &cu->header; struct dwarf_block *blk; enum bfd_endian byte_order = (bfd_big_endian (objfile->obfd.get ()) ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE); @@ -17251,7 +17315,7 @@ dwarf2_const_value_attr (const struct attribute *attr, struct type *type, /* Symbols of this form are reasonably rare, so we just piggyback on the existing location code rather than writing a new implementation of symbol_computed_ops. */ - *baton = XOBNEW (obstack, struct dwarf2_locexpr_baton); + *baton = OBSTACK_ZALLOC (obstack, struct dwarf2_locexpr_baton); (*baton)->per_objfile = per_objfile; (*baton)->per_cu = cu->per_cu; gdb_assert ((*baton)->per_cu); @@ -17271,6 +17335,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 (); @@ -17294,25 +17359,13 @@ dwarf2_const_value_attr (const struct attribute *attr, struct type *type, converted to host endianness, so we just need to sign- or zero-extend it as appropriate. */ case DW_FORM_data1: - *bytes = dwarf2_const_value_data (attr, obstack, cu, value, 8); - break; case DW_FORM_data2: - *bytes = dwarf2_const_value_data (attr, obstack, cu, value, 16); - break; case DW_FORM_data4: - *bytes = dwarf2_const_value_data (attr, obstack, cu, value, 32); - break; case DW_FORM_data8: - *bytes = dwarf2_const_value_data (attr, obstack, cu, value, 64); - break; - case DW_FORM_sdata: case DW_FORM_implicit_const: - *value = attr->as_signed (); - break; - case DW_FORM_udata: - *value = attr->as_unsigned (); + *value = attr->confused_constant ().value_or (0); break; default: @@ -17477,11 +17530,12 @@ 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 ()) { + const auto §ion = get_section_for_ref (*attr, cu); sect_offset sect_off = attr->get_ref_die_offset (); dwarf2_per_cu *per_cu - = dwarf2_find_containing_comp_unit (sect_off, 1, per_objfile->per_bfd); + = dwarf2_find_containing_unit ({ §ion, sect_off }, per_objfile); this_type = get_die_type_at_offset (sect_off, per_cu, per_objfile); } @@ -18182,14 +18236,13 @@ follow_die_ref_or_sig (struct die_info *src_die, const struct attribute *attr, return die; } -/* Follow reference OFFSET. - On entry *REF_CU is the CU of the source die referencing OFFSET. +/* Follow reference TARGET. + On entry *REF_CU is the CU of the source die referencing TARGET. On exit *REF_CU is the CU of the result. - Returns NULL if OFFSET is invalid. */ + Returns nullptr if TARGET is invalid. */ -static struct die_info * -follow_die_offset (sect_offset sect_off, int offset_in_dwz, - struct dwarf2_cu **ref_cu) +static die_info * +follow_die_offset (const section_and_offset &target, dwarf2_cu **ref_cu) { dwarf2_cu *source_cu = *ref_cu; dwarf2_cu *target_cu = source_cu; @@ -18201,23 +18254,23 @@ follow_die_offset (sect_offset sect_off, int offset_in_dwz, dwarf_read_debug_printf_v ("source CU offset: %s, target offset: %s, " "source CU contains target offset: %d", sect_offset_str (source_cu->per_cu->sect_off), - sect_offset_str (sect_off), - source_cu->header.offset_in_cu_p (sect_off)); + sect_offset_str (target.offset), + (target.section == &source_cu->section () + && source_cu->header.offset_in_unit_p (target.offset))); if (source_cu->per_cu->is_debug_types) { /* .debug_types CUs cannot reference anything outside their CU. If they need to, they have to reference a signatured type via DW_FORM_ref_sig8. */ - if (!source_cu->header.offset_in_cu_p (sect_off)) + if (!source_cu->header.offset_in_unit_p (target.offset)) return NULL; } - else if (offset_in_dwz != source_cu->per_cu->is_dwz - || !source_cu->header.offset_in_cu_p (sect_off)) + else if (target.section != &source_cu->section () + || !source_cu->header.offset_in_unit_p (target.offset)) { dwarf2_per_cu *target_per_cu - = dwarf2_find_containing_comp_unit (sect_off, offset_in_dwz, - per_objfile->per_bfd); + = dwarf2_find_containing_unit (target, per_objfile); dwarf_read_debug_printf_v ("target CU offset: %s, " "target CU DIEs loaded: %d", @@ -18239,14 +18292,13 @@ follow_die_offset (sect_offset sect_off, int offset_in_dwz, error (_(DWARF_ERROR_PREFIX "cannot follow reference to DIE at %s" " [in module %s]"), - sect_offset_str (sect_off), + sect_offset_str (target.offset), objfile_name (per_objfile->objfile)); } *ref_cu = target_cu; - auto it = target_cu->die_hash.find (sect_off); - return it != target_cu->die_hash.end () ? *it : nullptr; + return target_cu->find_die (target.offset); } /* Follow reference attribute ATTR of SRC_DIE. @@ -18258,24 +18310,21 @@ follow_die_ref (struct die_info *src_die, const struct attribute *attr, struct dwarf2_cu **ref_cu) { sect_offset sect_off = attr->get_ref_die_offset (); - struct dwarf2_cu *cu = *ref_cu; - struct die_info *die; + struct dwarf2_cu *src_cu = *ref_cu; - 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), - ref_cu); - if (!die) + const dwarf2_section_info §ion = get_section_for_ref (*attr, src_cu); + die_info *die = follow_die_offset ({ §ion, sect_off }, ref_cu); + if (die == nullptr) error (_(DWARF_ERROR_PREFIX "Cannot find DIE at %s referenced from DIE at %s [in module %s]"), sect_offset_str (sect_off), sect_offset_str (src_die->sect_off), - objfile_name (cu->per_objfile->objfile)); + objfile_name (src_cu->per_objfile->objfile)); return die; } @@ -18288,7 +18337,6 @@ dwarf2_fetch_die_loc_sect_off (sect_offset sect_off, dwarf2_per_cu *per_cu, gdb::function_view<CORE_ADDR ()> get_frame_pc, bool resolve_abstract_p) { - struct die_info *die; struct attribute *attr; struct dwarf2_locexpr_baton retval; struct objfile *objfile = per_objfile->objfile; @@ -18306,8 +18354,8 @@ dwarf2_fetch_die_loc_sect_off (sect_offset sect_off, dwarf2_per_cu *per_cu, sect_offset_str (sect_off), objfile_name (objfile)); } - die = follow_die_offset (sect_off, per_cu->is_dwz, &cu); - if (!die) + die_info *die = follow_die_offset ({ &cu->section (), sect_off }, &cu); + if (die == nullptr) error (_(DWARF_ERROR_PREFIX "Cannot find DIE at %s referenced [in module %s]"), sect_offset_str (sect_off), objfile_name (objfile)); @@ -18323,8 +18371,8 @@ dwarf2_fetch_die_loc_sect_off (sect_offset sect_off, dwarf2_per_cu *per_cu, : per_objfile->per_bfd->abstract_to_concrete[die->sect_off]) { struct dwarf2_cu *cand_cu = cu; - struct die_info *cand - = follow_die_offset (cand_off, per_cu->is_dwz, &cand_cu); + die_info *cand + = follow_die_offset ({ &cu->section (), cand_off }, &cand_cu); if (!cand || !cand->parent || cand->parent->tag != DW_TAG_subprogram) @@ -18426,7 +18474,6 @@ dwarf2_fetch_constant_bytes (sect_offset sect_off, obstack *obstack, LONGEST *len) { - struct die_info *die; struct attribute *attr; const gdb_byte *result = NULL; struct type *type; @@ -18447,7 +18494,7 @@ dwarf2_fetch_constant_bytes (sect_offset sect_off, sect_offset_str (sect_off), objfile_name (objfile)); } - die = follow_die_offset (sect_off, per_cu->is_dwz, &cu); + die_info *die = follow_die_offset ({ &cu->section (), sect_off }, &cu); if (!die) error (_(DWARF_ERROR_PREFIX "Cannot find DIE at %s referenced [in module %s]"), @@ -18480,6 +18527,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. */ { @@ -18505,47 +18553,19 @@ dwarf2_fetch_constant_bytes (sect_offset sect_off, symbol's value "represented as it would be on the target architecture." By the time we get here, it's already been converted to host endianness, so we just need to sign- or - zero-extend it as appropriate. */ + zero-extend it as appropriate. + + Both GCC and LLVM agree that these are always signed, though. */ case DW_FORM_data1: - type = die_type (die, cu); - result = dwarf2_const_value_data (attr, obstack, cu, &value, 8); - if (result == NULL) - result = write_constant_as_bytes (obstack, byte_order, - type, value, len); - break; case DW_FORM_data2: - type = die_type (die, cu); - result = dwarf2_const_value_data (attr, obstack, cu, &value, 16); - if (result == NULL) - result = write_constant_as_bytes (obstack, byte_order, - type, value, len); - break; case DW_FORM_data4: - type = die_type (die, cu); - result = dwarf2_const_value_data (attr, obstack, cu, &value, 32); - if (result == NULL) - result = write_constant_as_bytes (obstack, byte_order, - type, value, len); - break; case DW_FORM_data8: - type = die_type (die, cu); - result = dwarf2_const_value_data (attr, obstack, cu, &value, 64); - if (result == NULL) - result = write_constant_as_bytes (obstack, byte_order, - type, value, len); - break; - case DW_FORM_sdata: case DW_FORM_implicit_const: - type = die_type (die, cu); - result = write_constant_as_bytes (obstack, byte_order, - type, attr->as_signed (), len); - break; - case DW_FORM_udata: type = die_type (die, cu); - result = write_constant_as_bytes (obstack, byte_order, - type, attr->as_unsigned (), len); + value = attr->confused_constant ().value_or (0); + result = write_constant_as_bytes (obstack, byte_order, type, value, len); break; default: @@ -18564,8 +18584,6 @@ dwarf2_fetch_die_type_sect_off (sect_offset sect_off, dwarf2_per_cu *per_cu, dwarf2_per_objfile *per_objfile, const char **var_name) { - struct die_info *die; - dwarf2_cu *cu = per_objfile->get_cu (per_cu); if (cu == nullptr) cu = load_cu (per_cu, per_objfile, false); @@ -18573,7 +18591,7 @@ dwarf2_fetch_die_type_sect_off (sect_offset sect_off, dwarf2_per_cu *per_cu, if (cu == nullptr) return nullptr; - die = follow_die_offset (sect_off, per_cu->is_dwz, &cu); + die_info *die = follow_die_offset ({ &cu->section (), sect_off }, &cu); if (!die) return NULL; @@ -18622,8 +18640,8 @@ follow_die_sig_1 (struct die_info *src_die, struct signatured_type *sig_type, gdb_assert (sig_cu != NULL); gdb_assert (to_underlying (sig_type->type_offset_in_section) != 0); - if (auto die_it = sig_cu->die_hash.find (sig_type->type_offset_in_section); - die_it != sig_cu->die_hash.end ()) + if (die_info *die = sig_cu->find_die (sig_type->type_offset_in_section); + die != nullptr) { /* For .gdb_index version 7 keep track of included TUs. http://sourceware.org/bugzilla/show_bug.cgi?id=15021. */ @@ -18632,7 +18650,7 @@ follow_die_sig_1 (struct die_info *src_die, struct signatured_type *sig_type, (*ref_cu)->per_cu->imported_symtabs.push_back (sig_cu->per_cu); *ref_cu = sig_cu; - return *die_it; + return die; } return NULL; @@ -19189,7 +19207,7 @@ dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym, /* .debug_loc{,.dwo} may not exist at all, or the offset may be outside the section. If so, fall through to the complaint in the other branch. */ - && attr->as_unsigned () < section->get_size (objfile)) + && attr->as_unsigned () < section->size) { struct dwarf2_loclist_baton *baton; @@ -19210,7 +19228,8 @@ dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym, { struct dwarf2_locexpr_baton *baton; - baton = XOBNEW (&objfile->objfile_obstack, struct dwarf2_locexpr_baton); + baton = OBSTACK_ZALLOC (&objfile->objfile_obstack, + struct dwarf2_locexpr_baton); baton->per_objfile = per_objfile; baton->per_cu = cu->per_cu; gdb_assert (baton->per_cu); @@ -19242,7 +19261,7 @@ dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym, /* See read.h. */ -const comp_unit_head * +const unit_head * dwarf2_per_cu::get_header () const { if (!m_header_read_in) @@ -19250,8 +19269,7 @@ dwarf2_per_cu::get_header () const const gdb_byte *info_ptr = this->section->buffer + to_underlying (this->sect_off); - read_comp_unit_head (&m_header, info_ptr, this->section, - rcuh_kind::COMPILE); + read_unit_head (&m_header, info_ptr, this->section, ruh_kind::COMPILE); m_header_read_in = true; } @@ -19280,7 +19298,7 @@ dwarf2_per_cu::offset_size () const int dwarf2_per_cu::ref_addr_size () const { - const comp_unit_head *header = this->get_header (); + const unit_head *header = this->get_header (); if (header->version == 2) return header->addr_size; @@ -19323,69 +19341,115 @@ dwarf2_per_cu::ensure_lang (dwarf2_per_objfile *per_objfile) true, language_minimal, nullptr); } -/* A helper function for dwarf2_find_containing_comp_unit that returns - the index of the result, and that searches a vector. It will - return a result even if the offset in question does not actually - occur in any CU. This is separate so that it can be unit - tested. */ +/* Return the unit from ALL_UNITS that potentially contains TARGET. -static int -dwarf2_find_containing_comp_unit - (sect_offset sect_off, - unsigned int offset_in_dwz, - const std::vector<dwarf2_per_cu_up> &all_units) + Since the unit lengths may not be known yet, this function doesn't check that + TARGET.OFFSET actually falls within the range of the returned unit. The + caller is responsible for this. + + If no units possibly match TARGET, return nullptr. */ + +static dwarf2_per_cu * +dwarf2_find_containing_unit (const section_and_offset &target, + const std::vector<dwarf2_per_cu_up> &all_units) { - int low, high; + auto it = std::lower_bound (all_units.begin (), all_units.end (), target, + [] (const dwarf2_per_cu_up &per_cu, + const section_and_offset &key) + { + return all_units_less_than (*per_cu, key); + }); - low = 0; - high = all_units.size () - 1; - while (high > low) + if (it == all_units.begin ()) { - int mid = low + (high - low) / 2; - dwarf2_per_cu *mid_cu = all_units[mid].get (); - - if (mid_cu->is_dwz > offset_in_dwz - || (mid_cu->is_dwz == offset_in_dwz - && mid_cu->sect_off + mid_cu->length () > sect_off)) - high = mid; + /* TARGET falls before the first unit of the first section, or is an + exact match with the first. */ + if ((*it)->section == target.section && (*it)->sect_off == target.offset) + return it->get (); else - low = mid + 1; + return nullptr; } - gdb_assert (low == high); - return low; + + if (it != all_units.end () + && (*it)->section == target.section + && (*it)->sect_off == target.offset) + { + /* TARGET is an exact match with the start of *IT, so *IT is what we're + looking for. */ + return it->get (); + } + + /* Otherwise, the match is the one just before, as long as it matches the + section we're looking for. */ + --it; + + if ((*it)->section == target.section) + return it->get (); + + return nullptr; } /* See read.h. */ dwarf2_per_cu * -dwarf2_find_containing_comp_unit (sect_offset sect_off, - unsigned int offset_in_dwz, - dwarf2_per_bfd *per_bfd) +dwarf2_find_containing_unit (const section_and_offset &target, + dwarf2_per_objfile *per_objfile) { - int low = dwarf2_find_containing_comp_unit - (sect_off, offset_in_dwz, per_bfd->all_units); - dwarf2_per_cu *this_cu = per_bfd->all_units[low].get (); - - if (this_cu->is_dwz != offset_in_dwz || this_cu->sect_off > sect_off) + dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; + dwarf2_per_cu *per_cu + = dwarf2_find_containing_unit (target, per_bfd->all_units); + auto error_out = [&target, per_bfd] () { - if (low == 0 || this_cu->is_dwz != offset_in_dwz) - error (_(DWARF_ERROR_PREFIX - "could not find CU containing offset %s [in module %s]"), - sect_offset_str (sect_off), - per_bfd->filename ()); + error (_(DWARF_ERROR_PREFIX + "could not find unit containing offset %s [in module %s]"), + sect_offset_str (target.offset), per_bfd->filename ()); + }; - gdb_assert (per_bfd->all_units[low-1]->sect_off - <= sect_off); - return per_bfd->all_units[low - 1].get (); - } - else - { - if (low == per_bfd->all_units.size () - 1 - && sect_off >= this_cu->sect_off + this_cu->length ()) - error (_("invalid dwarf2 offset %s"), sect_offset_str (sect_off)); - gdb_assert (sect_off < this_cu->sect_off + this_cu->length ()); - return this_cu; - } + if (per_cu == nullptr) + error_out (); + + gdb_assert (per_cu->section == target.section); + + /* Some producers of dwarf2_per_cu objects (thinking of the .gdb_index reader) + do not set the length ahead of time. The length is needed to check if + the target is truly within PER_CU's range, so compute it now. Constructing + the cutu_reader object has the side-effect of setting PER_CU's length. + Even though it should happen too often, it could be replaced with + something more lightweight that has the same effect. */ + if (!per_cu->length_is_set ()) + cutu_reader (*per_cu, *per_objfile, nullptr, nullptr, false, + language_minimal); + + /* Now we can check if the target section offset is within PER_CU's range. */ + if (target.offset < per_cu->sect_off + || target.offset >= per_cu->sect_off + per_cu->length ()) + error_out (); + + return per_cu; +} + +/* See read.h. */ + +dwarf2_per_cu * +dwarf2_find_unit (const section_and_offset &start, dwarf2_per_bfd *per_bfd) +{ + auto it = std::lower_bound (per_bfd->all_units.begin (), + per_bfd->all_units.end (), start, + [] (const dwarf2_per_cu_up &per_cu, + const section_and_offset &key) + { + return all_units_less_than (*per_cu, key); + }); + + if (it == per_bfd->all_units.end ()) + return nullptr; + + dwarf2_per_cu *per_cu = it->get (); + + if (per_cu->section != start.section || per_cu->sect_off != start.offset) + return nullptr; + + return per_cu; } #if GDB_SELF_TEST @@ -19396,59 +19460,55 @@ namespace find_containing_comp_unit { static void run_test () { - char dummy_per_bfd; - char dummy_section; - - const auto create_dummy_per_cu = [&] (sect_offset sect_off, - unsigned int length, - bool is_dwz) - { - auto per_bfd = reinterpret_cast<dwarf2_per_bfd *> (&dummy_per_bfd); - auto section = reinterpret_cast<dwarf2_section_info *> (&dummy_section); + auto dummy_per_bfd = reinterpret_cast<dwarf2_per_bfd *> (0x3000); + auto &main_section = *reinterpret_cast<dwarf2_section_info *> (0x4000); + auto &dwz_section = *reinterpret_cast<dwarf2_section_info *> (0x5000); + std::vector<dwarf2_per_cu_up> units; - return dwarf2_per_cu_up (new dwarf2_per_cu (per_bfd, section, sect_off, - length, is_dwz)); + /* Create one dummy unit, append it to UNITS, return a non-owning + reference. */ + auto create_dummy_per_unit = [&] (dwarf2_section_info §ion, + unsigned int sect_off, bool is_dwz) + -> dwarf2_per_cu & + { + /* Omit the length, because dwarf2_find_containing_unit does not consider + it. */ + return *units.emplace_back (new dwarf2_per_cu (dummy_per_bfd, §ion, + sect_offset (sect_off), + 0, is_dwz)); }; - /* Units in the main file. */ - dwarf2_per_cu_up one = create_dummy_per_cu (sect_offset (0), 5, false); - dwarf2_per_cu *one_ptr = one.get (); - dwarf2_per_cu_up two - = create_dummy_per_cu (sect_offset (one->length ()), 7, false); - dwarf2_per_cu *two_ptr = two.get (); - - /* Units in the supplementary (dwz) file. */ - dwarf2_per_cu_up three = create_dummy_per_cu (sect_offset (0), 5, true); - dwarf2_per_cu *three_ptr = three.get (); - dwarf2_per_cu_up four - = create_dummy_per_cu (sect_offset (three->length ()), 7, true); - dwarf2_per_cu *four_ptr = four.get (); - - std::vector<dwarf2_per_cu_up> units; - units.push_back (std::move (one)); - units.push_back (std::move (two)); - units.push_back (std::move (three)); - units.push_back (std::move (four)); - - int result; + /* Create 2 units in the main file and 2 units in the supplementary (dwz) + file. */ + auto &main1 = create_dummy_per_unit (main_section, 10, false); + auto &main2 = create_dummy_per_unit (main_section, 20, false); + auto &dwz1 = create_dummy_per_unit (dwz_section, 10, false); + auto &dwz2 = create_dummy_per_unit (dwz_section, 20, false); + + /* Check that looking up a unit at all offsets in the range [START,END[ in + section SECTION finds EXPECTED. */ + auto check_range = [&units] (dwarf2_section_info §ion, unsigned int start, + unsigned int end, dwarf2_per_cu *expected) + { + for (unsigned int sect_off = start; sect_off < end; ++sect_off) + { + section_and_offset target { §ion, sect_offset (sect_off) }; + dwarf2_per_cu *result = dwarf2_find_containing_unit (target, units); - result = dwarf2_find_containing_comp_unit (sect_offset (0), 0, units); - SELF_CHECK (units[result].get () == one_ptr); - result = dwarf2_find_containing_comp_unit (sect_offset (3), 0, units); - SELF_CHECK (units[result].get () == one_ptr); - result = dwarf2_find_containing_comp_unit (sect_offset (5), 0, units); - SELF_CHECK (units[result].get () == two_ptr); + SELF_CHECK (result == expected); + } + }; - result = dwarf2_find_containing_comp_unit (sect_offset (0), 1, units); - SELF_CHECK (units[result].get () == three_ptr); - result = dwarf2_find_containing_comp_unit (sect_offset (3), 1, units); - SELF_CHECK (units[result].get () == three_ptr); - result = dwarf2_find_containing_comp_unit (sect_offset (5), 1, units); - SELF_CHECK (units[result].get () == four_ptr); -} + check_range (main_section, 0, 10, nullptr); + check_range (main_section, 10, 20, &main1); + check_range (main_section, 20, 30, &main2); + check_range (dwz_section, 0, 10, nullptr); + check_range (dwz_section, 10, 20, &dwz1); + check_range (dwz_section, 20, 30, &dwz2); } -} +} /* namespace find_containing_comp_unit */ +} /* namespace selftests */ #endif /* GDB_SELF_TEST */ @@ -19743,9 +19803,7 @@ show_check_physname (struct ui_file *file, int from_tty, value); } -void _initialize_dwarf2_read (); -void -_initialize_dwarf2_read () +INIT_GDB_FILE (dwarf2_read) { add_setshow_prefix_cmd ("dwarf", class_maintenance, _("\ diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index 3177b19..4e3f8d7 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -20,9 +20,12 @@ #ifndef GDB_DWARF2_READ_H #define GDB_DWARF2_READ_H +#if CXX_STD_THREAD +#include <mutex> +#endif #include <queue> #include "dwarf2/abbrev.h" -#include "dwarf2/comp-unit-head.h" +#include "dwarf2/unit-head.h" #include "dwarf2/file-and-dir.h" #include "dwarf2/index-cache.h" #include "dwarf2/mapped-index.h" @@ -44,7 +47,6 @@ struct tu_stats int nr_symtab_sharers = 0; int nr_stmt_less_type_units = 0; int nr_all_type_units_reallocs = 0; - int nr_tus = 0; }; struct abbrev_table_cache; @@ -233,14 +235,14 @@ public: /* Backlink to the owner of this. */ dwarf2_per_bfd *per_bfd; - /* DWARF header of this CU. Note that dwarf2_cu reads its own version of the - header, which may differ from this one, since it may pass rcuh_kind::TYPE - to read_comp_unit_head, whereas for dwarf2_per_cu we always pass - rcuh_kind::COMPILE. + /* DWARF header of this unit. Note that dwarf2_cu reads its own version of + the header, which may differ from this one, since it may pass + rch_kind::TYPE to read_unit_head, whereas for dwarf2_per_cu we always pass + ruh_kind::COMPILE. Don't access this field directly, use the get_header method instead. It should be private, but we can't make it private at the moment. */ - mutable comp_unit_head m_header; + mutable unit_head m_header; /* The file and directory for this CU. This is cached so that we don't need to re-examine the DWO in some situations. This may be @@ -271,7 +273,7 @@ public: std::vector<dwarf2_per_cu *> imported_symtabs; /* Get the header of this per_cu, reading it if necessary. */ - const comp_unit_head *get_header () const; + const unit_head *get_header () const; /* Return the address size given in the compilation unit header for this CU. */ @@ -293,6 +295,10 @@ public: return m_length; } + /* Return true if the length of this CU has been set. */ + bool length_is_set () const + { return m_length != 0; } + void set_length (unsigned int length, bool strict_p = true) { if (m_length == 0) @@ -512,30 +518,16 @@ struct dwarf2_per_bfd const char *filename () const { return bfd_get_filename (this->obfd); } - /* Return the CU given its index. */ - dwarf2_per_cu *get_cu (int index) const + /* Return the unit given its index. */ + dwarf2_per_cu *get_unit (int index) const { return this->all_units[index].get (); } - /* Return the CU given its index in the CU table in the index. */ - dwarf2_per_cu *get_index_cu (int index) const - { - if (this->all_comp_units_index_cus.empty ()) - return get_cu (index); - - return this->all_comp_units_index_cus[index]; - } - - dwarf2_per_cu *get_index_tu (int index) const - { - return this->all_comp_units_index_tus[index]; - } - /* 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 +538,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; @@ -616,13 +608,9 @@ public: the target compilation unit of a particular reference. */ std::vector<dwarf2_per_cu_up> all_units; - /* The all_units vector contains both CUs and TUs. Provide views on the - vector that are limited to either the CU part or the TU part. */ - gdb::array_view<dwarf2_per_cu_up> all_comp_units; - gdb::array_view<dwarf2_per_cu_up> all_type_units; - - std::vector<dwarf2_per_cu *> all_comp_units_index_cus; - std::vector<dwarf2_per_cu *> all_comp_units_index_tus; + /* Number of compilation and type units in the ALL_UNITS vector. */ + unsigned int num_comp_units = 0; + unsigned int num_type_units = 0; /* Set of signatured_types, used to look up by signature. */ signatured_type_set signatured_types; @@ -634,8 +622,10 @@ public: /* Set of dwo_file objects. */ dwo_file_up_set dwo_files; - /* True if we've checked for whether there is a DWP file. */ - bool dwp_checked = false; +#if CXX_STD_THREAD + /* Mutex to synchronize access to DWO_FILES. */ + std::mutex dwo_files_lock; +#endif /* The DWP file if there is one, or NULL. */ dwp_file_up dwp_file; @@ -705,7 +695,7 @@ public: dwarf2_per_cu *operator* () const { - return m_per_bfd->get_cu (m_index); + return m_per_bfd->get_unit (m_index); } bool operator== (const all_units_iterator &other) const @@ -815,7 +805,7 @@ struct dwarf2_per_objfile BUF is assumed to be in a compilation unit described by CU_HEADER. Return *BYTES_READ_PTR count of bytes read from BUF. */ const char *read_line_string (const gdb_byte *buf, - const struct comp_unit_head *cu_header, + const struct unit_head *unit_header, unsigned int *bytes_read_ptr); /* Return pointer to string at .debug_line_str offset as read from BUF. @@ -937,8 +927,6 @@ public: DISABLE_COPY_AND_ASSIGN (cutu_reader); - cutu_reader (cutu_reader &&) = default; - /* Return true if either: - the unit is empty (just a header without any DIE) @@ -1028,6 +1016,31 @@ private: const char *read_dwo_str_index (ULONGEST str_index); + gdb_bfd_ref_ptr open_dwo_file (dwarf2_per_bfd *per_bfd, const char *file_name, + const char *comp_dir); + + dwo_file_up open_and_init_dwo_file (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir); + + void locate_dwo_sections (objfile *objfile, dwo_file &dwo_file); + + void create_dwo_unit_hash_tables (dwo_file &dwo_file, dwarf2_cu &skeleton_cu, + dwarf2_section_info §ion, + ruh_kind section_kind); + + dwo_unit *lookup_dwo_cutu (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir, ULONGEST signature, + int is_debug_types); + + dwo_unit *lookup_dwo_comp_unit (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir, ULONGEST signature); + + dwo_unit *lookup_dwo_type_unit (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir); + + dwo_unit *lookup_dwo_unit (dwarf2_cu *cu, die_info *comp_unit_die, + const char *dwo_name); + /* The bfd of die_section. */ bfd *m_abfd; @@ -1204,7 +1217,7 @@ extern void dw_expand_symtabs_matching_file_matcher extern const char *read_indirect_string_at_offset (dwarf2_per_objfile *per_objfile, LONGEST str_offset); -/* Initialize the views on all_units. */ +/* Finalize the all_units vector. */ extern void finalize_all_units (dwarf2_per_bfd *per_bfd); @@ -1249,14 +1262,17 @@ extern pc_bounds_kind dwarf2_get_pc_bounds (die_info *die, dwarf2_cu *cu, addrmap_mutable *map, void *datum); -/* Locate the .debug_info compilation unit from CU's objfile which contains - the DIE at OFFSET. Raises an error on failure. */ +/* Locate the unit in PER_OBJFILE which contains the DIE at TARGET. Raises an + error on failure. */ -extern dwarf2_per_cu *dwarf2_find_containing_comp_unit (sect_offset sect_off, - unsigned int - offset_in_dwz, - dwarf2_per_bfd - *per_bfd); +extern dwarf2_per_cu *dwarf2_find_containing_unit + (const section_and_offset &target, dwarf2_per_objfile *per_objfile); + +/* Locate the unit starting at START in PER_BFD. Return nullptr if not + found. */ + +extern dwarf2_per_cu *dwarf2_find_unit (const section_and_offset &start, + dwarf2_per_bfd *per_bfd); /* Decode simple location descriptions. @@ -1299,4 +1315,10 @@ extern int dwarf2_ranges_read (unsigned offset, unrelocated_addr *low_return, extern file_and_directory &find_file_and_directory (die_info *die, dwarf2_cu *cu); + +/* Return the section that ATTR, an attribute with ref form, references. */ + +extern const dwarf2_section_info &get_section_for_ref + (const attribute &attr, dwarf2_cu *cu); + #endif /* GDB_DWARF2_READ_H */ diff --git a/gdb/dwarf2/section.h b/gdb/dwarf2/section.h index 85da485..fbdb025 100644 --- a/gdb/dwarf2/section.h +++ b/gdb/dwarf2/section.h @@ -43,6 +43,8 @@ the real section this "virtual" section is contained in, and BUFFER,SIZE describe the virtual section. */ +#include "dwarf2/types.h" + struct dwarf2_section_info { /* Return the name of this section. */ @@ -81,19 +83,6 @@ struct dwarf2_section_info If the section is compressed, uncompress it before returning. */ void read (struct objfile *objfile); - /* A helper function that returns the size of a section in a safe way. - If you are positive that the section has been read before using the - size, then it is safe to refer to the dwarf2_section_info object's - "size" field directly. In other cases, you must call this - function, because for compressed sections the size field is not set - correctly until the section has been read. */ - bfd_size_type get_size (struct objfile *objfile) - { - if (!readin) - read (objfile); - return size; - } - /* Issue a complaint that something was outside the bounds of this buffer. */ void overflow_complaint () const; @@ -125,4 +114,14 @@ struct dwarf2_section_info bool is_virtual; }; +using dwarf2_section_info_up = std::unique_ptr<dwarf2_section_info>; + +/* A pair-like structure to represent an offset into a section. */ + +struct section_and_offset +{ + const dwarf2_section_info *section; + sect_offset offset; +}; + #endif /* GDB_DWARF2_SECTION_H */ diff --git a/gdb/dwarf2/comp-unit-head.c b/gdb/dwarf2/unit-head.c index 8ec8897..0c7614f 100644 --- a/gdb/dwarf2/comp-unit-head.c +++ b/gdb/dwarf2/unit-head.c @@ -24,119 +24,117 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "dwarf2/comp-unit-head.h" +#include "dwarf2/unit-head.h" #include "dwarf2/leb.h" -#include "dwarf2/read.h" #include "dwarf2/section.h" #include "dwarf2/stringify.h" #include "dwarf2/error.h" -/* See comp-unit-head.h. */ +/* See unit-head.h. */ const gdb_byte * -read_comp_unit_head (struct comp_unit_head *cu_header, - const gdb_byte *info_ptr, - struct dwarf2_section_info *section, - rcuh_kind section_kind) +read_unit_head (struct unit_head *header, const gdb_byte *info_ptr, + struct dwarf2_section_info *section, ruh_kind section_kind) { int signed_addr; unsigned int bytes_read; const char *filename = section->get_file_name (); bfd *abfd = section->get_bfd_owner (); - cu_header->set_length (read_initial_length (abfd, info_ptr, &bytes_read)); - cu_header->initial_length_size = bytes_read; - cu_header->offset_size = (bytes_read == 4) ? 4 : 8; + header->set_length (read_initial_length (abfd, info_ptr, &bytes_read)); + header->initial_length_size = bytes_read; + header->offset_size = (bytes_read == 4) ? 4 : 8; info_ptr += bytes_read; unsigned version = read_2_bytes (abfd, info_ptr); if (version < 2 || version > 5) error (_(DWARF_ERROR_PREFIX - "wrong version in compilation unit header " + "wrong version in unit header " "(is %d, should be 2, 3, 4 or 5) [in module %s]"), version, filename); - cu_header->version = version; + header->version = version; info_ptr += 2; - if (cu_header->version < 5) + if (header->version < 5) switch (section_kind) { - case rcuh_kind::COMPILE: - cu_header->unit_type = DW_UT_compile; + case ruh_kind::COMPILE: + header->unit_type = DW_UT_compile; break; - case rcuh_kind::TYPE: - cu_header->unit_type = DW_UT_type; + case ruh_kind::TYPE: + header->unit_type = DW_UT_type; break; default: - internal_error (_("read_comp_unit_head: invalid section_kind")); + internal_error (_("read_unit_head: invalid section_kind")); } else { - cu_header->unit_type = static_cast<enum dwarf_unit_type> - (read_1_byte (abfd, info_ptr)); + header->unit_type + = static_cast<enum dwarf_unit_type> (read_1_byte (abfd, info_ptr)); info_ptr += 1; - switch (cu_header->unit_type) + switch (header->unit_type) { case DW_UT_compile: case DW_UT_partial: case DW_UT_skeleton: case DW_UT_split_compile: - if (section_kind != rcuh_kind::COMPILE) + if (section_kind != ruh_kind::COMPILE) error (_(DWARF_ERROR_PREFIX - "wrong unit_type in compilation unit header " + "wrong unit_type in unit header " "(is %s, should be %s) [in module %s]"), - dwarf_unit_type_name (cu_header->unit_type), + dwarf_unit_type_name (header->unit_type), dwarf_unit_type_name (DW_UT_type), filename); break; case DW_UT_type: case DW_UT_split_type: - section_kind = rcuh_kind::TYPE; + section_kind = ruh_kind::TYPE; break; default: error (_(DWARF_ERROR_PREFIX - "wrong unit_type in compilation unit header " + "wrong unit_type in unit header " "(is %#04x, should be one of: %s, %s, %s, %s or %s) " "[in module %s]"), - cu_header->unit_type, dwarf_unit_type_name (DW_UT_compile), + header->unit_type, dwarf_unit_type_name (DW_UT_compile), dwarf_unit_type_name (DW_UT_skeleton), dwarf_unit_type_name (DW_UT_split_compile), dwarf_unit_type_name (DW_UT_type), dwarf_unit_type_name (DW_UT_split_type), filename); } - cu_header->addr_size = read_1_byte (abfd, info_ptr); + header->addr_size = read_1_byte (abfd, info_ptr); info_ptr += 1; } - cu_header->abbrev_sect_off - = (sect_offset) cu_header->read_offset (abfd, info_ptr, &bytes_read); + header->abbrev_sect_off + = (sect_offset) header->read_offset (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; - if (cu_header->version < 5) + if (header->version < 5) { - cu_header->addr_size = read_1_byte (abfd, info_ptr); + header->addr_size = read_1_byte (abfd, info_ptr); info_ptr += 1; } signed_addr = bfd_get_sign_extend_vma (abfd); if (signed_addr < 0) - internal_error (_("read_comp_unit_head: dwarf from non elf file")); - cu_header->signed_addr_p = signed_addr; + internal_error (_("read_unit_head: dwarf from non elf file")); + header->signed_addr_p = signed_addr; - bool header_has_signature = section_kind == rcuh_kind::TYPE - || cu_header->unit_type == DW_UT_skeleton - || cu_header->unit_type == DW_UT_split_compile; + bool header_has_signature = + (section_kind == ruh_kind::TYPE + || header->unit_type == DW_UT_skeleton + || header->unit_type == DW_UT_split_compile); if (header_has_signature) { - cu_header->signature = read_8_bytes (abfd, info_ptr); + header->signature = read_8_bytes (abfd, info_ptr); info_ptr += 8; } - if (section_kind == rcuh_kind::TYPE) + if (section_kind == ruh_kind::TYPE) { LONGEST type_offset; - type_offset = cu_header->read_offset (abfd, info_ptr, &bytes_read); + type_offset = header->read_offset (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; - cu_header->type_cu_offset_in_tu = (cu_offset) type_offset; - if (to_underlying (cu_header->type_cu_offset_in_tu) != type_offset) + header->type_offset_in_tu = (cu_offset) type_offset; + if (to_underlying (header->type_offset_in_tu) != type_offset) error (_(DWARF_ERROR_PREFIX - "Too big type_offset in compilation unit " + "Too big type_offset in unit " "header (is %s) [in module %s]"), plongest (type_offset), filename); } @@ -144,64 +142,56 @@ read_comp_unit_head (struct comp_unit_head *cu_header, return info_ptr; } -/* Subroutine of read_and_check_comp_unit_head and - read_and_check_type_unit_head to simplify them. +/* Subroutine of read_and_check_unit_head to to simplify it. Perform various error checking on the header. */ static void -error_check_comp_unit_head (dwarf2_per_objfile *per_objfile, - struct comp_unit_head *header, - struct dwarf2_section_info *section, - struct dwarf2_section_info *abbrev_section) +error_check_unit_head (unit_head *header, dwarf2_section_info *section, + dwarf2_section_info *abbrev_section) { const char *filename = section->get_file_name (); - if (to_underlying (header->abbrev_sect_off) - >= abbrev_section->get_size (per_objfile->objfile)) + if (to_underlying (header->abbrev_sect_off) >= abbrev_section->size) error (_(DWARF_ERROR_PREFIX - "bad offset (%s) in compilation unit header " + "bad offset (%s) in unit header " "(offset %s + 6) [in module %s]"), sect_offset_str (header->abbrev_sect_off), - sect_offset_str (header->sect_off), - filename); + sect_offset_str (header->sect_off), filename); /* Cast to ULONGEST to use 64-bit arithmetic when possible to avoid potential 32-bit overflow. */ if (((ULONGEST) header->sect_off + header->get_length_with_initial ()) > section->size) error (_(DWARF_ERROR_PREFIX - "bad length (0x%x) in compilation unit header " + "bad length (0x%x) in unit header " "(offset %s + 0) [in module %s]"), header->get_length_without_initial (), sect_offset_str (header->sect_off), filename); } -/* See comp-unit-head.h. */ +/* See unit-head.h. */ const gdb_byte * -read_and_check_comp_unit_head (dwarf2_per_objfile *per_objfile, - struct comp_unit_head *header, - struct dwarf2_section_info *section, - struct dwarf2_section_info *abbrev_section, - const gdb_byte *info_ptr, - rcuh_kind section_kind) +read_and_check_unit_head (unit_head *header, dwarf2_section_info *section, + dwarf2_section_info *abbrev_section, + const gdb_byte *info_ptr, ruh_kind section_kind) { - const gdb_byte *beg_of_comp_unit = info_ptr; + const gdb_byte *beg_of_unit = info_ptr; - header->sect_off = (sect_offset) (beg_of_comp_unit - section->buffer); + header->sect_off = (sect_offset) (beg_of_unit - section->buffer); - info_ptr = read_comp_unit_head (header, info_ptr, section, section_kind); + info_ptr = read_unit_head (header, info_ptr, section, section_kind); - header->first_die_cu_offset = (cu_offset) (info_ptr - beg_of_comp_unit); + header->first_die_offset_in_unit = (cu_offset) (info_ptr - beg_of_unit); - error_check_comp_unit_head (per_objfile, header, section, abbrev_section); + error_check_unit_head (header, section, abbrev_section); return info_ptr; } unrelocated_addr -comp_unit_head::read_address (bfd *abfd, const gdb_byte *buf, - unsigned int *bytes_read) const +unit_head::read_address (bfd *abfd, const gdb_byte *buf, + unsigned int *bytes_read) const { ULONGEST retval = 0; diff --git a/gdb/dwarf2/comp-unit-head.h b/gdb/dwarf2/unit-head.h index 5134893..6272888 100644 --- a/gdb/dwarf2/comp-unit-head.h +++ b/gdb/dwarf2/unit-head.h @@ -24,18 +24,19 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef GDB_DWARF2_COMP_UNIT_HEAD_H -#define GDB_DWARF2_COMP_UNIT_HEAD_H +#ifndef GDB_DWARF2_UNIT_HEAD_H +#define GDB_DWARF2_UNIT_HEAD_H #include "dwarf2.h" #include "dwarf2/leb.h" #include "dwarf2/types.h" struct dwarf2_per_objfile; +struct dwarf2_section_info; -/* The data in a compilation unit header, after target2host - translation, looks like this. */ -struct comp_unit_head +/* The data in a unit header, after target2host translation, looks like + this. */ +struct unit_head { private: unsigned int m_length = 0; @@ -53,16 +54,16 @@ public: enum dwarf_unit_type unit_type {}; - /* Offset to first die in this cu from the start of the cu. - This will be the first byte following the compilation unit header. */ - cu_offset first_die_cu_offset {}; + /* Offset to first die in this unit from the start of the unit. + This will be the first byte following the unit header. */ + cu_offset first_die_offset_in_unit {}; - /* Offset to the first byte of this compilation unit header in the - .debug_info section, for resolving relative reference dies. */ + /* Offset to the first byte of this unit header in the containing section, + for resolving relative reference dies. */ sect_offset sect_off {}; /* For types, offset in the type's DIE of the type defined by this TU. */ - cu_offset type_cu_offset_in_tu {}; + cu_offset type_offset_in_tu {}; /* 64-bit signature of this unit. For type units, it denotes the signature of the type (DW_UT_type in DWARF 4, additionally DW_UT_split_type in DWARF 5). @@ -75,22 +76,22 @@ public: m_length = length; } - /* Return the total length of the CU described by this header, including the + /* Return the total length of the unit described by this header, including the initial length field. */ unsigned int get_length_with_initial () const { return m_length + initial_length_size; } - /* Return the total length of the CU described by this header, excluding the + /* Return the total length of the unit described by this header, excluding the initial length field. */ unsigned int get_length_without_initial () const { return m_length; } - /* Return TRUE if OFF is within this CU. */ - bool offset_in_cu_p (sect_offset off) const + /* Return TRUE if OFF is within this unit. */ + bool offset_in_unit_p (sect_offset off) const { sect_offset bottom = sect_off; sect_offset top = sect_off + get_length_with_initial (); @@ -98,7 +99,7 @@ public: } /* Read an offset from the data stream. The size of the offset is - given by cu_header->offset_size. */ + given by unit_head::offset_size. */ LONGEST read_offset (bfd *abfd, const gdb_byte *buf, unsigned int *bytes_read) const { @@ -112,28 +113,24 @@ public: unsigned int *bytes_read) const; }; -/* Expected enum dwarf_unit_type for read_comp_unit_head. */ -enum class rcuh_kind { COMPILE, TYPE }; +/* Expected enum dwarf_unit_type for read_unit_head. */ +enum class ruh_kind { COMPILE, TYPE }; -/* Read in the comp unit header information from the debug_info at info_ptr. - Use rcuh_kind::COMPILE as the default type if not known by the caller. - NOTE: This leaves members offset, first_die_offset to be filled in +/* Read in the unit header information from the debug_info at info_ptr. + Use ruh_kind::COMPILE as the default type if not known by the caller. + NOTE: This leaves members sect_off, first_die_unit_offset to be filled in by the caller. */ -extern const gdb_byte *read_comp_unit_head - (struct comp_unit_head *cu_header, - const gdb_byte *info_ptr, - struct dwarf2_section_info *section, - rcuh_kind section_kind); +extern const gdb_byte *read_unit_head (unit_head *header, + const gdb_byte *info_ptr, + dwarf2_section_info *section, + ruh_kind section_kind); -/* Read in a CU/TU header and perform some basic error checking. +/* Read in a unit header and perform some basic error checking. The contents of the header are stored in HEADER. The result is a pointer to the start of the first DIE. */ -extern const gdb_byte *read_and_check_comp_unit_head - (dwarf2_per_objfile *per_objfile, - struct comp_unit_head *header, - struct dwarf2_section_info *section, - struct dwarf2_section_info *abbrev_section, - const gdb_byte *info_ptr, - rcuh_kind section_kind); - -#endif /* GDB_DWARF2_COMP_UNIT_HEAD_H */ +extern const gdb_byte *read_and_check_unit_head + (unit_head *header, dwarf2_section_info *section, + dwarf2_section_info *abbrev_section, const gdb_byte *info_ptr, + ruh_kind section_kind); + +#endif /* GDB_DWARF2_UNIT_HEAD_H */ |