diff options
Diffstat (limited to 'gdb/dwarf2')
-rw-r--r-- | gdb/dwarf2/cooked-indexer.c | 42 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-indexer.h | 4 | ||||
-rw-r--r-- | gdb/dwarf2/cu.h | 5 | ||||
-rw-r--r-- | gdb/dwarf2/index-write.c | 142 | ||||
-rw-r--r-- | gdb/dwarf2/read-debug-names.c | 148 | ||||
-rw-r--r-- | gdb/dwarf2/read-gdb-index.c | 38 | ||||
-rw-r--r-- | gdb/dwarf2/read.c | 445 | ||||
-rw-r--r-- | gdb/dwarf2/read.h | 54 | ||||
-rw-r--r-- | gdb/dwarf2/section.h | 10 |
9 files changed, 518 insertions, 370 deletions
diff --git a/gdb/dwarf2/cooked-indexer.c b/gdb/dwarf2/cooked-indexer.c index c093984..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_unit_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. */ @@ -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_is_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_is_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 69f396c..68010a0 100644 --- a/gdb/dwarf2/cu.h +++ b/gdb/dwarf2/cu.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 diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c index 0a3b9d0..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); diff --git a/gdb/dwarf2/read-debug-names.c b/gdb/dwarf2/read-debug-names.c index 4b3f385..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_unit (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_unit (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_unit (0); + if (per_cu == nullptr) + per_cu = this->comp_units[0]; break; case DW_IDX_parent: parent = ull; @@ -440,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_unit (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_unit (j)); + + map.type_units.emplace_back (per_cu); } + return true; } @@ -700,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_unit (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_unit (j)); - } - return true; - } + int nr_cus = per_bfd->num_comp_units; if (map.cu_count != nr_cus) { @@ -749,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_unit (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 @@ -815,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) @@ -831,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 464fbdd..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_unit (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_unit (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); diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 5e18e45..ec8d376 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -1690,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; } @@ -1706,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; } @@ -2370,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 @@ -2413,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 @@ -3212,10 +3241,11 @@ private: void print_tu_stats (dwarf2_per_objfile *per_objfile) { - struct tu_stats *tu_stats = &per_objfile->per_bfd->tu_stats; + 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", tu_stats->nr_tus); + 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", @@ -3365,7 +3395,7 @@ cooked_index_worker_debug_info::process_type_units 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 @@ -3392,7 +3422,7 @@ cooked_index_worker_debug_info::process_type_units /* 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) @@ -3644,16 +3674,18 @@ read_comp_units_from_section (dwarf2_per_objfile *per_objfile, } } -/* 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. */ @@ -4909,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 @@ -4928,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_is_alt () || cu->per_cu->is_dwz; dwarf2_per_objfile *per_objfile = cu->per_objfile; dwarf2_per_cu *per_cu - = dwarf2_find_containing_comp_unit (sect_off, is_dwz, - 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, @@ -6054,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) { @@ -9918,33 +9978,37 @@ static void handle_member_location (struct die_info *die, struct dwarf2_cu *cu, 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) { 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); - attribute *attr2 = dwarf2_attr (die, DW_AT_bit_offset, cu); - if (attr2 != nullptr && attr2->form_is_constant ()) + if (bit_offset_attr != nullptr && bit_offset_attr->form_is_constant ()) { has_bit_offset = true; - bit_offset = attr2->confused_constant ().value_or (0); - attr2 = dwarf2_attr (die, DW_AT_byte_size, cu); - if (attr2 != nullptr && attr2->form_is_constant ()) + bit_offset = bit_offset_attr->confused_constant ().value_or (0); + + const auto byte_size_attr = dwarf2_attr (die, DW_AT_byte_size, cu); + + 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 = attr2->unsigned_constant ().value_or (0); + anonymous_size + = byte_size_attr->unsigned_constant ().value_or (0); } } - if (attr->form_is_constant ()) + if (data_member_location_attr->form_is_constant ()) { - LONGEST offset = attr->confused_constant ().value_or (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: @@ -9962,11 +10026,17 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu, if (has_bit_offset) apply_bit_offset_to_field (*field, bit_offset, anonymous_size); } - 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; @@ -9985,8 +10055,8 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu, else dlbaton = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct dwarf2_locexpr_baton); - dlbaton->data = attr->as_block ()->data; - dlbaton->size = attr->as_block ()->size; + 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. */ @@ -9999,16 +10069,19 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu, } else complaint (_("Unsupported form %s for DW_AT_data_member_location"), - dwarf_form_name (attr->form)); + dwarf_form_name (data_member_location_attr->form)); } else { - attr = dwarf2_attr (die, DW_AT_data_bit_offset, cu); - if (attr != nullptr) + const auto data_bit_offset_attr + = dwarf2_attr (die, DW_AT_data_bit_offset, cu); + + if (data_bit_offset_attr != nullptr) { - if (attr->form_is_constant ()) - field->set_loc_bitpos (attr->unsigned_constant ().value_or (0)); - else if (attr->form_is_block ()) + 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. */ @@ -10016,8 +10089,8 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu, dwarf2_locexpr_baton *dlbaton = OBSTACK_ZALLOC (&per_objfile->objfile->objfile_obstack, dwarf2_locexpr_baton); - dlbaton->data = attr->as_block ()->data; - dlbaton->size = attr->as_block ()->size; + 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; @@ -10025,7 +10098,7 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu, } else complaint (_("Unsupported form %s for DW_AT_data_bit_offset"), - dwarf_form_name (attr->form)); + dwarf_form_name (data_bit_offset_attr->form)); } } } @@ -17459,9 +17532,10 @@ lookup_die_type (struct die_info *die, const struct attribute *attr, 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); } @@ -18162,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; @@ -18181,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_unit_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_unit_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_unit_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", @@ -18219,13 +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; - return target_cu->find_die (sect_off); + return target_cu->find_die (target.offset); } /* Follow reference attribute ATTR of SRC_DIE. @@ -18237,8 +18310,7 @@ 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_is_alt () && src_die->sect_off == sect_off) { @@ -18246,14 +18318,13 @@ follow_die_ref (struct die_info *src_die, const struct attribute *attr, return src_die; } - die = follow_die_offset (sect_off, - attr->form_is_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; } @@ -18266,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; @@ -18284,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)); @@ -18301,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) @@ -18404,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; @@ -18425,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]"), @@ -18515,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); @@ -18524,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; @@ -19274,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 @@ -19347,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 */ diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index a5cfb31..4e3f8d7 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -47,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; @@ -296,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) @@ -521,20 +524,6 @@ struct dwarf2_per_bfd 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_unit (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 or .debug_sup section in the file, then the result depends on REQUIRE: if REQUIRE is true, error out; if @@ -619,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; @@ -1232,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); @@ -1277,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_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_containing_comp_unit (sect_offset sect_off, - unsigned int - offset_in_dwz, - dwarf2_per_bfd - *per_bfd); +extern dwarf2_per_cu *dwarf2_find_unit (const section_and_offset &start, + dwarf2_per_bfd *per_bfd); /* Decode simple location descriptions. @@ -1327,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 fd6e34d..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. */ @@ -114,4 +116,12 @@ struct dwarf2_section_info 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 */ |