diff options
Diffstat (limited to 'gdb/dwarf2/read-debug-names.c')
-rw-r--r-- | gdb/dwarf2/read-debug-names.c | 264 |
1 files changed, 176 insertions, 88 deletions
diff --git a/gdb/dwarf2/read-debug-names.c b/gdb/dwarf2/read-debug-names.c index eebe5a9..4b3f385 100644 --- a/gdb/dwarf2/read-debug-names.c +++ b/gdb/dwarf2/read-debug-names.c @@ -1,6 +1,6 @@ /* Reading code for .debug_names - Copyright (C) 2023-2024 Free Software Foundation, Inc. + Copyright (C) 2023-2025 Free Software Foundation, Inc. This file is part of GDB. @@ -27,6 +27,8 @@ #include "mapped-index.h" #include "read.h" #include "stringify.h" +#include "extract-store-integer.h" +#include "gdbsupport/thread-pool.h" /* This is just like cooked_index_functions, but overrides a single method so the test suite can distinguish the .debug_names case from @@ -39,7 +41,7 @@ struct dwarf2_debug_names_index : public cooked_index_functions void dump (struct objfile *objfile) override { gdb_printf (".debug_names: exists\n"); - /* This could call the superclass method if that's useful. */ + cooked_index_functions::dump (objfile); } }; @@ -73,7 +75,15 @@ struct mapped_debug_names_reader bfd *abfd = nullptr; bfd_endian dwarf5_byte_order {}; bool dwarf5_is_dwarf64 = false; + + /* True if the augmentation string indicates the index was produced by + GDB. */ bool augmentation_is_gdb = false; + + /* If AUGMENTATION_IS_GDB is true, this indicates the version. Otherwise, + this value is meaningless. */ + unsigned int gdb_augmentation_version = 0; + uint8_t offset_size = 0; uint32_t cu_count = 0; uint32_t tu_count = 0, bucket_count = 0, name_count = 0; @@ -102,10 +112,36 @@ struct mapped_debug_names_reader std::vector<attr> attr_vec; }; - std::unordered_map<ULONGEST, index_val> abbrev_map; + gdb::unordered_map<ULONGEST, index_val> abbrev_map; + + /* 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 + are filled in a round robin fashion. It's convenient to use a + result object rather than an actual shard. */ + std::vector<cooked_index_worker_result> indices; + + /* Next shard to insert an entry in. */ + int next_shard = 0; + + /* Maps entry pool offsets to cooked index entries. */ + gdb::unordered_map<ULONGEST, cooked_index_entry *> + entry_pool_offsets_to_entries; + + /* Cooked index entries for which the parent needs to be resolved. - std::unique_ptr<cooked_index_shard> shard; + The second value of the pair is the DW_IDX_parent value. Its meaning + depends on the augmentation string: + + - GDB2: an index in the name table + - GDB3: an offset offset into the entry pool */ std::vector<std::pair<cooked_index_entry *, ULONGEST>> needs_parent; + + /* All the cooked index entries created, in the same order and groups as + listed in the name table. + + The size of the outer vector is equal to the number of entries in the name + table (NAME_COUNT). */ std::vector<std::vector<cooked_index_entry *>> all_entries; }; @@ -120,6 +156,7 @@ mapped_debug_names_reader::scan_one_entry (const char *name, std::optional<ULONGEST> &parent) { unsigned int bytes_read; + const auto offset_in_entry_pool = entry - entry_pool; const ULONGEST abbrev = read_unsigned_leb128 (abfd, entry, &bytes_read); entry += bytes_read; if (abbrev == 0) @@ -138,7 +175,7 @@ mapped_debug_names_reader::scan_one_entry (const char *name, cooked_index_flag flags = 0; sect_offset die_offset {}; enum language lang = language_unknown; - dwarf2_per_cu_data *per_cu = nullptr; + dwarf2_per_cu *per_cu = nullptr; for (const auto &attr : indexval.attr_vec) { ULONGEST ull; @@ -158,6 +195,17 @@ mapped_debug_names_reader::scan_one_entry (const char *name, ull = read_offset (abfd, entry, offset_size); entry += offset_size; break; + case DW_FORM_data1: + ull = *entry++; + break; + case DW_FORM_data2: + ull = read_2_bytes (abfd, entry); + entry += 2; + break; + case DW_FORM_data4: + ull = read_4_bytes (abfd, entry); + entry += 4; + break; case DW_FORM_ref4: ull = read_4_bytes (abfd, entry); entry += 4; @@ -171,9 +219,12 @@ mapped_debug_names_reader::scan_one_entry (const char *name, entry += 8; break; default: - complaint (_("Unsupported .debug_names form %s [in module %s]"), - dwarf_form_name (attr.form), - bfd_get_filename (abfd)); + /* A warning instead of a complaint, because this one is + more like a bug in gdb. */ + warning (_("Unsupported .debug_names form %s [in module %s].\n" + "This normally should not happen, please file a bug report."), + dwarf_form_name (attr.form), + bfd_get_filename (abfd)); return nullptr; } switch (attr.dw_idx) @@ -190,7 +241,7 @@ mapped_debug_names_reader::scan_one_entry (const char *name, continue; } } - per_cu = per_objfile->per_bfd->get_cu (ull); + per_cu = per_objfile->per_bfd->get_unit (ull); break; case DW_IDX_type_unit: /* Don't crash on bad data. */ @@ -204,7 +255,7 @@ mapped_debug_names_reader::scan_one_entry (const char *name, } { int nr_cus = per_objfile->per_bfd->all_comp_units.size (); - per_cu = per_objfile->per_bfd->get_cu (nr_cus + ull); + per_cu = per_objfile->per_bfd->get_unit (nr_cus + ull); } break; case DW_IDX_die_offset: @@ -212,7 +263,7 @@ mapped_debug_names_reader::scan_one_entry (const char *name, /* 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); + per_cu = per_objfile->per_bfd->get_unit (0); break; case DW_IDX_parent: parent = ull; @@ -238,8 +289,18 @@ mapped_debug_names_reader::scan_one_entry (const char *name, /* Skip if we couldn't find a valid CU/TU index. */ if (per_cu != nullptr) - *result = shard->add (die_offset, (dwarf_tag) indexval.dwarf_tag, flags, - lang, name, nullptr, per_cu); + { + *result + = indices[next_shard].add (die_offset, (dwarf_tag) indexval.dwarf_tag, + flags, lang, name, nullptr, per_cu); + + ++next_shard; + if (next_shard == indices.size ()) + next_shard = 0; + + entry_pool_offsets_to_entries.emplace (offset_in_entry_pool, *result); + } + return entry; } @@ -295,27 +356,51 @@ mapped_debug_names_reader::scan_all_names () scan_entries (i, name, entry); } - /* Now update the parent pointers for all entries. This has to be - done in a funny way because DWARF specifies the parent entry to - point to a name -- but we don't know which specific one. */ - for (auto [entry, parent_idx] : needs_parent) + /* Resolve the parent pointers for all entries that have a parent. + + If the augmentation string is "GDB2", the DW_IDX_parent value is an index + into the name table. Since there may be multiple index entries associated + to that name, we have a little heuristic to figure out which is the right + one. + + Otherwise, the DW_IDX_parent value is an offset into the entry pool, which + is not ambiguous. */ + for (auto &[entry, parent_val] : needs_parent) { - /* Name entries are indexed from 1 in DWARF. */ - std::vector<cooked_index_entry *> &entries = all_entries[parent_idx - 1]; - for (const auto &parent : entries) - if (parent->lang == entry->lang) - { - entry->set_parent (parent); - break; - } + if (augmentation_is_gdb && gdb_augmentation_version == 2) + { + /* Name entries are indexed from 1 in DWARF. */ + std::vector<cooked_index_entry *> &entries + = all_entries[parent_val - 1]; + + for (const auto &parent : entries) + if (parent->lang == entry->lang) + { + entry->set_parent (parent); + break; + } + } + else + { + const auto parent_it + = entry_pool_offsets_to_entries.find (parent_val); + + if (parent_it == entry_pool_offsets_to_entries.cend ()) + { + complaint (_ ("Parent entry not found for .debug_names entry")); + continue; + } + + entry->set_parent (parent_it->second); + } } } /* A reader for .debug_names. */ -struct cooked_index_debug_names : public cooked_index_worker +struct cooked_index_worker_debug_names : public cooked_index_worker { - cooked_index_debug_names (dwarf2_per_objfile *per_objfile, + cooked_index_worker_debug_names (dwarf2_per_objfile *per_objfile, mapped_debug_names_reader &&map) : cooked_index_worker (per_objfile), m_map (std::move (map)) @@ -327,34 +412,30 @@ struct cooked_index_debug_names : public cooked_index_worker }; void -cooked_index_debug_names::do_reading () +cooked_index_worker_debug_names::do_reading () { complaint_interceptor complaint_handler; - std::vector<gdb_exception> exceptions; - try + + /* Arbitrarily put all exceptions into the first result. */ + m_map.indices[0].catch_error ([&] () { m_map.scan_all_names (); - } - catch (const gdb_exception &exc) + }); + + bool first = true; + for (auto &iter : m_map.indices) { - exceptions.push_back (std::move (exc)); + if (first) + { + iter.done_reading (complaint_handler.release ()); + first = false; + } + else + iter.done_reading ({}); } - dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd; - per_bfd->quick_file_names_table - = create_quick_file_names_table (per_bfd->all_units.size ()); - m_results.emplace_back (nullptr, - complaint_handler.release (), - std::move (exceptions), - parent_map ()); - std::vector<std::unique_ptr<cooked_index_shard>> indexes; - indexes.push_back (std::move (m_map.shard)); - cooked_index *table - = (gdb::checked_static_cast<cooked_index *> - (per_bfd->index_table.get ())); - /* Note that this code never uses IS_PARENT_DEFERRED, so it is safe - to pass nullptr here. */ - table->set_contents (std::move (indexes), &m_warnings, nullptr); + m_results = std::move (m_map.indices); + done_reading (); bfd_thread_cleanup (); } @@ -385,7 +466,7 @@ check_signatured_type_table_from_debug_names bool found = false; for (; j < nr_cus_tus; j++) - if (per_bfd->get_cu (j)->sect_off == sect_off) + if (per_bfd->get_unit (j)->sect_off == sect_off) { found = true; break; @@ -396,23 +477,13 @@ check_signatured_type_table_from_debug_names " ignoring .debug_names.")); return false; } - per_bfd->all_comp_units_index_tus.push_back (per_bfd->get_cu (j)); + per_bfd->all_comp_units_index_tus.push_back (per_bfd->get_unit (j)); } return true; } /* DWARF-5 debug_names reader. */ -/* The old, no-longer-supported GDB augmentation. */ -static const gdb_byte old_gdb_augmentation[] - = { 'G', 'D', 'B', 0 }; -static_assert (sizeof (old_gdb_augmentation) % 4 == 0); - -/* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension. This - must have a size that is a multiple of 4. */ -const gdb_byte dwarf5_augmentation[8] = { 'G', 'D', 'B', '2', 0, 0, 0, 0 }; -static_assert (sizeof (dwarf5_augmentation) % 4 == 0); - /* A helper function that reads the .debug_names section in SECTION and fills in MAP. FILENAME is the name of the file containing the section; it is used for error reporting. @@ -524,18 +595,24 @@ read_debug_names_from_section (dwarf2_per_objfile *per_objfile, addr += 4; augmentation_string_size += (-augmentation_string_size) & 3; - if (augmentation_string_size == sizeof (old_gdb_augmentation) - && memcmp (addr, old_gdb_augmentation, - sizeof (old_gdb_augmentation)) == 0) + const auto augmentation_string + = gdb::make_array_view (addr, augmentation_string_size); + + if (augmentation_string == gdb::make_array_view (dwarf5_augmentation_1)) { warning (_(".debug_names created by an old version of gdb; ignoring")); return false; } - - map.augmentation_is_gdb = ((augmentation_string_size - == sizeof (dwarf5_augmentation)) - && memcmp (addr, dwarf5_augmentation, - sizeof (dwarf5_augmentation)) == 0); + else if (augmentation_string == gdb::make_array_view (dwarf5_augmentation_2)) + { + map.augmentation_is_gdb = true; + map.gdb_augmentation_version = 2; + } + else if (augmentation_string == gdb::make_array_view (dwarf5_augmentation_3)) + { + map.augmentation_is_gdb = true; + map.gdb_augmentation_version = 3; + } if (!map.augmentation_is_gdb) { @@ -543,6 +620,7 @@ read_debug_names_from_section (dwarf2_per_objfile *per_objfile, return false; } + /* Skip past augmentation string. */ addr += augmentation_string_size; /* List of CUs */ @@ -641,7 +719,7 @@ check_cus_from_debug_names_list (dwarf2_per_bfd *per_bfd, map.dwarf5_byte_order)); bool found = false; for (; j < nr_cus; j++) - if (per_bfd->get_cu (j)->sect_off == sect_off) + if (per_bfd->get_unit (j)->sect_off == sect_off) { found = true; break; @@ -652,7 +730,7 @@ check_cus_from_debug_names_list (dwarf2_per_bfd *per_bfd, " ignoring .debug_names.")); return false; } - per_bfd->all_comp_units_index_cus.push_back (per_bfd->get_cu (j)); + per_bfd->all_comp_units_index_cus.push_back (per_bfd->get_unit (j)); } return true; } @@ -671,7 +749,7 @@ 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) + if (sect_off != per_bfd->get_unit (i)->sect_off) { warning (_("Section .debug_names has incorrect entry in CU table," " ignoring .debug_names.")); @@ -690,14 +768,14 @@ check_cus_from_debug_names (dwarf2_per_bfd *per_bfd, const mapped_debug_names_reader &map, const mapped_debug_names_reader &dwz_map) { - if (!check_cus_from_debug_names_list (per_bfd, map, per_bfd->info, + if (!check_cus_from_debug_names_list (per_bfd, map, per_bfd->infos[0], false /* is_dwz */)) return false; if (dwz_map.cu_count == 0) return true; - dwz_file *dwz = dwarf2_get_dwz_file (per_bfd); + dwz_file *dwz = per_bfd->get_dwz_file (); return check_cus_from_debug_names_list (per_bfd, dwz_map, dwz->info, true /* is_dwz */); } @@ -723,7 +801,7 @@ do_dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile) /* If there is a .dwz file, read it so we can get its CU list as well. */ - dwz_file *dwz = dwarf2_get_dwz_file (per_bfd); + dwz_file *dwz = per_bfd->get_dwz_file (); if (dwz != NULL) { if (!read_debug_names_from_section (per_objfile, @@ -742,15 +820,16 @@ do_dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile) if (map.tu_count != 0) { - /* We can only handle a single .debug_types when we have an - index. */ - if (per_bfd->types.size () > 1) + /* We can only handle a single .debug_info and .debug_types when we have + an index. */ + if (per_bfd->infos.size () > 1 + || per_bfd->types.size () > 1) return false; dwarf2_section_info *section = (per_bfd->types.size () == 1 ? &per_bfd->types[0] - : &per_bfd->info); + : &per_bfd->infos[0]); if (!check_signatured_type_table_from_debug_names (per_objfile, map, section)) @@ -758,22 +837,31 @@ do_dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile) } per_bfd->debug_aranges.read (per_objfile->objfile); - addrmap_mutable addrmap; + + /* There is a single address map for the whole index (coming from + .debug_aranges). We only need to install it into a single shard + for it to get searched by cooked_index. So, we make the first + result object here, so we can store the addrmap, then move it + into place later. */ + cooked_index_worker_result first; deferred_warnings warnings; read_addrmap_from_aranges (per_objfile, &per_bfd->debug_aranges, - &addrmap, &warnings); + first.get_addrmap (), &warnings); warnings.emit (); - map.shard = std::make_unique<cooked_index_shard> (); - map.shard->install_addrmap (&addrmap); + const auto n_workers + = std::max<std::size_t> (gdb::thread_pool::g_thread_pool->thread_count (), + 1); - cooked_index *idx - = new debug_names_index (per_objfile, - (std::make_unique<cooked_index_debug_names> - (per_objfile, std::move (map)))); - per_bfd->index_table.reset (idx); + /* Create as many index shard as there are worker threads, + preserving the first one. */ + map.indices.push_back (std::move (first)); + map.indices.resize (n_workers); - idx->start_reading (); + auto cidn = (std::make_unique<cooked_index_worker_debug_names> + (per_objfile, std::move (map))); + auto idx = std::make_unique<debug_names_index> (std::move (cidn)); + per_bfd->start_reading (std::move (idx)); return true; } |