aboutsummaryrefslogtreecommitdiff
path: root/gdb/dwarf2/read-debug-names.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/dwarf2/read-debug-names.c')
-rw-r--r--gdb/dwarf2/read-debug-names.c264
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;
}