| /* Reading code for .debug_names |
| |
| Copyright (C) 2023-2024 Free Software Foundation, Inc. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| 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 "read-debug-names.h" |
| #include "dwarf2/aranges.h" |
| #include "dwarf2/cooked-index.h" |
| |
| #include "complaints.h" |
| #include "cp-support.h" |
| #include "dwz.h" |
| #include "mapped-index.h" |
| #include "read.h" |
| #include "stringify.h" |
| |
| /* This is just like cooked_index_functions, but overrides a single |
| method so the test suite can distinguish the .debug_names case from |
| the ordinary case. */ |
| struct dwarf2_debug_names_index : public cooked_index_functions |
| { |
| /* This dumps minimal information about .debug_names. It is called |
| via "mt print objfiles". The gdb.dwarf2/gdb-index.exp testcase |
| uses this to verify that .debug_names has been loaded. */ |
| void dump (struct objfile *objfile) override |
| { |
| gdb_printf (".debug_names: exists\n"); |
| /* This could call the superclass method if that's useful. */ |
| } |
| }; |
| |
| /* This is like a cooked index, but as it has been ingested from |
| .debug_names, it can't be used to write out an index. */ |
| class debug_names_index : public cooked_index |
| { |
| public: |
| |
| using cooked_index::cooked_index; |
| |
| cooked_index *index_for_writing () override |
| { return nullptr; } |
| |
| quick_symbol_functions_up make_quick_functions () const override |
| { return quick_symbol_functions_up (new dwarf2_debug_names_index); } |
| }; |
| |
| /* A description of the mapped .debug_names. */ |
| |
| struct mapped_debug_names_reader |
| { |
| const gdb_byte *scan_one_entry (const char *name, |
| const gdb_byte *entry, |
| cooked_index_entry **result, |
| std::optional<ULONGEST> &parent); |
| void scan_entries (uint32_t index, const char *name, const gdb_byte *entry); |
| void scan_all_names (); |
| |
| dwarf2_per_objfile *per_objfile = nullptr; |
| bfd *abfd = nullptr; |
| bfd_endian dwarf5_byte_order {}; |
| bool dwarf5_is_dwarf64 = false; |
| bool augmentation_is_gdb = false; |
| uint8_t offset_size = 0; |
| uint32_t cu_count = 0; |
| uint32_t tu_count = 0, bucket_count = 0, name_count = 0; |
| const gdb_byte *cu_table_reordered = nullptr; |
| const gdb_byte *tu_table_reordered = nullptr; |
| const uint32_t *bucket_table_reordered = nullptr; |
| const uint32_t *hash_table_reordered = nullptr; |
| const gdb_byte *name_table_string_offs_reordered = nullptr; |
| const gdb_byte *name_table_entry_offs_reordered = nullptr; |
| const gdb_byte *entry_pool = nullptr; |
| |
| struct index_val |
| { |
| ULONGEST dwarf_tag; |
| struct attr |
| { |
| /* Attribute name DW_IDX_*. */ |
| ULONGEST dw_idx; |
| |
| /* Attribute form DW_FORM_*. */ |
| ULONGEST form; |
| |
| /* Value if FORM is DW_FORM_implicit_const. */ |
| LONGEST implicit_const; |
| }; |
| std::vector<attr> attr_vec; |
| }; |
| |
| std::unordered_map<ULONGEST, index_val> abbrev_map; |
| |
| std::unique_ptr<cooked_index_shard> shard; |
| std::vector<std::pair<cooked_index_entry *, ULONGEST>> needs_parent; |
| std::vector<std::vector<cooked_index_entry *>> all_entries; |
| }; |
| |
| /* Scan a single entry from the entries table. Set *RESULT and PARENT |
| (if needed) and return the updated pointer on success, or return |
| nullptr on error, or at the end of the table. */ |
| |
| const gdb_byte * |
| mapped_debug_names_reader::scan_one_entry (const char *name, |
| const gdb_byte *entry, |
| cooked_index_entry **result, |
| std::optional<ULONGEST> &parent) |
| { |
| unsigned int bytes_read; |
| const ULONGEST abbrev = read_unsigned_leb128 (abfd, entry, &bytes_read); |
| entry += bytes_read; |
| if (abbrev == 0) |
| return nullptr; |
| |
| const auto indexval_it = abbrev_map.find (abbrev); |
| if (indexval_it == abbrev_map.cend ()) |
| { |
| complaint (_("Wrong .debug_names undefined abbrev code %s " |
| "[in module %s]"), |
| pulongest (abbrev), bfd_get_filename (abfd)); |
| return nullptr; |
| } |
| |
| const auto &indexval = indexval_it->second; |
| cooked_index_flag flags = 0; |
| sect_offset die_offset {}; |
| enum language lang = language_unknown; |
| dwarf2_per_cu_data *per_cu = nullptr; |
| for (const auto &attr : indexval.attr_vec) |
| { |
| ULONGEST ull; |
| switch (attr.form) |
| { |
| case DW_FORM_implicit_const: |
| ull = attr.implicit_const; |
| break; |
| case DW_FORM_flag_present: |
| ull = 1; |
| break; |
| case DW_FORM_udata: |
| ull = read_unsigned_leb128 (abfd, entry, &bytes_read); |
| entry += bytes_read; |
| break; |
| case DW_FORM_ref_addr: |
| ull = read_offset (abfd, entry, offset_size); |
| entry += offset_size; |
| break; |
| case DW_FORM_ref4: |
| ull = read_4_bytes (abfd, entry); |
| entry += 4; |
| break; |
| case DW_FORM_ref8: |
| ull = read_8_bytes (abfd, entry); |
| entry += 8; |
| break; |
| case DW_FORM_ref_sig8: |
| ull = read_8_bytes (abfd, entry); |
| entry += 8; |
| break; |
| default: |
| complaint (_("Unsupported .debug_names form %s [in module %s]"), |
| dwarf_form_name (attr.form), |
| bfd_get_filename (abfd)); |
| return nullptr; |
| } |
| switch (attr.dw_idx) |
| { |
| case DW_IDX_compile_unit: |
| { |
| /* Don't crash on bad data. */ |
| if (ull >= per_objfile->per_bfd->all_comp_units.size ()) |
| { |
| complaint (_(".debug_names entry has bad CU index %s" |
| " [in module %s]"), |
| pulongest (ull), |
| bfd_get_filename (abfd)); |
| continue; |
| } |
| } |
| 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); |
| } |
| 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); |
| break; |
| case DW_IDX_parent: |
| parent = ull; |
| break; |
| case DW_IDX_GNU_internal: |
| if (augmentation_is_gdb && ull != 0) |
| flags |= IS_STATIC; |
| break; |
| case DW_IDX_GNU_main: |
| if (augmentation_is_gdb && ull != 0) |
| flags |= IS_MAIN; |
| break; |
| case DW_IDX_GNU_language: |
| if (augmentation_is_gdb) |
| lang = dwarf_lang_to_enum_language (ull); |
| break; |
| case DW_IDX_GNU_linkage_name: |
| if (augmentation_is_gdb && ull != 0) |
| flags |= IS_LINKAGE; |
| break; |
| } |
| } |
| |
| /* 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); |
| return entry; |
| } |
| |
| /* Scan all the entries for NAME, at name slot INDEX. */ |
| |
| void |
| mapped_debug_names_reader::scan_entries (uint32_t index, |
| const char *name, |
| const gdb_byte *entry) |
| { |
| std::vector<cooked_index_entry *> these_entries; |
| |
| while (true) |
| { |
| std::optional<ULONGEST> parent; |
| cooked_index_entry *this_entry; |
| entry = scan_one_entry (name, entry, &this_entry, parent); |
| |
| if (entry == nullptr) |
| break; |
| |
| these_entries.push_back (this_entry); |
| if (parent.has_value ()) |
| needs_parent.emplace_back (this_entry, *parent); |
| } |
| |
| all_entries[index] = std::move (these_entries); |
| } |
| |
| /* Scan the name table and create all the entries. */ |
| |
| void |
| mapped_debug_names_reader::scan_all_names () |
| { |
| all_entries.resize (name_count); |
| |
| /* In the first pass, create all the entries. */ |
| for (uint32_t i = 0; i < name_count; ++i) |
| { |
| const ULONGEST namei_string_offs |
| = extract_unsigned_integer ((name_table_string_offs_reordered |
| + i * offset_size), |
| offset_size, dwarf5_byte_order); |
| const char *name = read_indirect_string_at_offset (per_objfile, |
| namei_string_offs); |
| |
| const ULONGEST namei_entry_offs |
| = extract_unsigned_integer ((name_table_entry_offs_reordered |
| + i * offset_size), |
| offset_size, dwarf5_byte_order); |
| const gdb_byte *entry = entry_pool + namei_entry_offs; |
| |
| 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) |
| { |
| /* 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; |
| } |
| } |
| } |
| |
| /* A reader for .debug_names. */ |
| |
| struct cooked_index_debug_names : public cooked_index_worker |
| { |
| cooked_index_debug_names (dwarf2_per_objfile *per_objfile, |
| mapped_debug_names_reader &&map) |
| : cooked_index_worker (per_objfile), |
| m_map (std::move (map)) |
| { } |
| |
| void do_reading () override; |
| |
| mapped_debug_names_reader m_map; |
| }; |
| |
| void |
| cooked_index_debug_names::do_reading () |
| { |
| complaint_interceptor complaint_handler; |
| std::vector<gdb_exception> exceptions; |
| try |
| { |
| m_map.scan_all_names (); |
| } |
| catch (const gdb_exception &exc) |
| { |
| exceptions.push_back (std::move (exc)); |
| } |
| |
| 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); |
| |
| bfd_thread_cleanup (); |
| } |
| |
| /* Check the signatured type hash table from .debug_names. */ |
| |
| 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) |
| { |
| 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) |
| { |
| 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) |
| { |
| 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)); |
| } |
| 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. |
| |
| Returns true if all went well, false otherwise. */ |
| |
| static bool |
| read_debug_names_from_section (dwarf2_per_objfile *per_objfile, |
| const char *filename, |
| struct dwarf2_section_info *section, |
| mapped_debug_names_reader &map) |
| { |
| struct objfile *objfile = per_objfile->objfile; |
| |
| if (section->empty ()) |
| return false; |
| |
| /* Older elfutils strip versions could keep the section in the main |
| executable while splitting it for the separate debug info file. */ |
| if ((section->get_flags () & SEC_HAS_CONTENTS) == 0) |
| return false; |
| |
| section->read (objfile); |
| |
| map.per_objfile = per_objfile; |
| map.dwarf5_byte_order = gdbarch_byte_order (objfile->arch ()); |
| |
| const gdb_byte *addr = section->buffer; |
| |
| bfd *abfd = section->get_bfd_owner (); |
| map.abfd = abfd; |
| |
| unsigned int bytes_read; |
| LONGEST length = read_initial_length (abfd, addr, &bytes_read); |
| addr += bytes_read; |
| |
| map.dwarf5_is_dwarf64 = bytes_read != 4; |
| map.offset_size = map.dwarf5_is_dwarf64 ? 8 : 4; |
| if (bytes_read + length != section->size) |
| { |
| /* There may be multiple per-CU indices. */ |
| warning (_("Section .debug_names in %s length %s does not match " |
| "section length %s, ignoring .debug_names."), |
| filename, plongest (bytes_read + length), |
| pulongest (section->size)); |
| return false; |
| } |
| |
| /* The version number. */ |
| uint16_t version = read_2_bytes (abfd, addr); |
| addr += 2; |
| if (version != 5) |
| { |
| warning (_("Section .debug_names in %s has unsupported version %d, " |
| "ignoring .debug_names."), |
| filename, version); |
| return false; |
| } |
| |
| /* Padding. */ |
| uint16_t padding = read_2_bytes (abfd, addr); |
| addr += 2; |
| if (padding != 0) |
| { |
| warning (_("Section .debug_names in %s has unsupported padding %d, " |
| "ignoring .debug_names."), |
| filename, padding); |
| return false; |
| } |
| |
| /* comp_unit_count - The number of CUs in the CU list. */ |
| map.cu_count = read_4_bytes (abfd, addr); |
| addr += 4; |
| |
| /* local_type_unit_count - The number of TUs in the local TU |
| list. */ |
| map.tu_count = read_4_bytes (abfd, addr); |
| addr += 4; |
| |
| /* foreign_type_unit_count - The number of TUs in the foreign TU |
| list. */ |
| uint32_t foreign_tu_count = read_4_bytes (abfd, addr); |
| addr += 4; |
| if (foreign_tu_count != 0) |
| { |
| warning (_("Section .debug_names in %s has unsupported %lu foreign TUs, " |
| "ignoring .debug_names."), |
| filename, static_cast<unsigned long> (foreign_tu_count)); |
| return false; |
| } |
| |
| /* bucket_count - The number of hash buckets in the hash lookup |
| table. */ |
| map.bucket_count = read_4_bytes (abfd, addr); |
| addr += 4; |
| |
| /* name_count - The number of unique names in the index. */ |
| map.name_count = read_4_bytes (abfd, addr); |
| addr += 4; |
| |
| /* abbrev_table_size - The size in bytes of the abbreviations |
| table. */ |
| uint32_t abbrev_table_size = read_4_bytes (abfd, addr); |
| addr += 4; |
| |
| /* augmentation_string_size - The size in bytes of the augmentation |
| string. This value is rounded up to a multiple of 4. */ |
| uint32_t augmentation_string_size = read_4_bytes (abfd, addr); |
| 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) |
| { |
| 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); |
| |
| if (!map.augmentation_is_gdb) |
| { |
| warning (_(".debug_names not created by gdb; ignoring")); |
| return false; |
| } |
| |
| addr += augmentation_string_size; |
| |
| /* List of CUs */ |
| map.cu_table_reordered = addr; |
| addr += map.cu_count * map.offset_size; |
| |
| /* List of Local TUs */ |
| map.tu_table_reordered = addr; |
| addr += map.tu_count * map.offset_size; |
| |
| /* Hash Lookup Table */ |
| map.bucket_table_reordered = reinterpret_cast<const uint32_t *> (addr); |
| addr += map.bucket_count * 4; |
| map.hash_table_reordered = reinterpret_cast<const uint32_t *> (addr); |
| if (map.bucket_count != 0) |
| addr += map.name_count * 4; |
| |
| /* Name Table */ |
| map.name_table_string_offs_reordered = addr; |
| addr += map.name_count * map.offset_size; |
| map.name_table_entry_offs_reordered = addr; |
| addr += map.name_count * map.offset_size; |
| |
| const gdb_byte *abbrev_table_start = addr; |
| for (;;) |
| { |
| const ULONGEST index_num = read_unsigned_leb128 (abfd, addr, &bytes_read); |
| addr += bytes_read; |
| if (index_num == 0) |
| break; |
| |
| const auto insertpair |
| = map.abbrev_map.emplace (index_num, mapped_debug_names_reader::index_val ()); |
| if (!insertpair.second) |
| { |
| warning (_("Section .debug_names in %s has duplicate index %s, " |
| "ignoring .debug_names."), |
| filename, pulongest (index_num)); |
| return false; |
| } |
| mapped_debug_names_reader::index_val &indexval = insertpair.first->second; |
| indexval.dwarf_tag = read_unsigned_leb128 (abfd, addr, &bytes_read); |
| addr += bytes_read; |
| |
| for (;;) |
| { |
| mapped_debug_names_reader::index_val::attr attr; |
| attr.dw_idx = read_unsigned_leb128 (abfd, addr, &bytes_read); |
| addr += bytes_read; |
| attr.form = read_unsigned_leb128 (abfd, addr, &bytes_read); |
| addr += bytes_read; |
| if (attr.form == DW_FORM_implicit_const) |
| { |
| attr.implicit_const = read_signed_leb128 (abfd, addr, |
| &bytes_read); |
| addr += bytes_read; |
| } |
| if (attr.dw_idx == 0 && attr.form == 0) |
| break; |
| indexval.attr_vec.push_back (std::move (attr)); |
| } |
| } |
| if (addr != abbrev_table_start + abbrev_table_size) |
| { |
| warning (_("Section .debug_names in %s has abbreviation_table " |
| "of size %s vs. written as %u, ignoring .debug_names."), |
| filename, plongest (addr - abbrev_table_start), |
| abbrev_table_size); |
| return false; |
| } |
| map.entry_pool = addr; |
| |
| return true; |
| } |
| |
| /* A helper for check_cus_from_debug_names that handles the MAP's CU |
| 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) |
| { |
| 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; |
| } |
| |
| if (map.cu_count != nr_cus) |
| { |
| warning (_("Section .debug_names has incorrect number of CUs in CU table," |
| " ignoring .debug_names.")); |
| return false; |
| } |
| |
| 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)); |
| if (sect_off != per_bfd->get_cu (i)->sect_off) |
| { |
| warning (_("Section .debug_names has incorrect entry in CU table," |
| " ignoring .debug_names.")); |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /* Read the CU list from the mapped index, and use it to create all |
| the CU objects for this dwarf2_per_objfile. */ |
| |
| 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) |
| { |
| if (!check_cus_from_debug_names_list (per_bfd, map, per_bfd->info, |
| false /* is_dwz */)) |
| return false; |
| |
| if (dwz_map.cu_count == 0) |
| return true; |
| |
| dwz_file *dwz = dwarf2_get_dwz_file (per_bfd); |
| return check_cus_from_debug_names_list (per_bfd, dwz_map, dwz->info, |
| true /* is_dwz */); |
| } |
| |
| /* This does all the work for dwarf2_read_debug_names, but putting it |
| into a separate function makes some cleanup a bit simpler. */ |
| |
| static bool |
| do_dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile) |
| { |
| mapped_debug_names_reader map; |
| mapped_debug_names_reader dwz_map; |
| struct objfile *objfile = per_objfile->objfile; |
| dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; |
| |
| if (!read_debug_names_from_section (per_objfile, objfile_name (objfile), |
| &per_bfd->debug_names, map)) |
| return false; |
| |
| /* Don't use the index if it's empty. */ |
| if (map.name_count == 0) |
| return false; |
| |
| /* 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); |
| if (dwz != NULL) |
| { |
| if (!read_debug_names_from_section (per_objfile, |
| bfd_get_filename (dwz->dwz_bfd.get ()), |
| &dwz->debug_names, dwz_map)) |
| { |
| warning (_("could not read '.debug_names' section from %s; skipping"), |
| bfd_get_filename (dwz->dwz_bfd.get ())); |
| return false; |
| } |
| } |
| |
| create_all_units (per_objfile); |
| if (!check_cus_from_debug_names (per_bfd, map, dwz_map)) |
| return false; |
| |
| if (map.tu_count != 0) |
| { |
| /* We can only handle a single .debug_types when we have an |
| index. */ |
| if (per_bfd->types.size () > 1) |
| return false; |
| |
| dwarf2_section_info *section |
| = (per_bfd->types.size () == 1 |
| ? &per_bfd->types[0] |
| : &per_bfd->info); |
| |
| if (!check_signatured_type_table_from_debug_names (per_objfile, |
| map, section)) |
| return false; |
| } |
| |
| per_bfd->debug_aranges.read (per_objfile->objfile); |
| addrmap_mutable addrmap; |
| deferred_warnings warnings; |
| read_addrmap_from_aranges (per_objfile, &per_bfd->debug_aranges, |
| &addrmap, &warnings); |
| warnings.emit (); |
| |
| map.shard = std::make_unique<cooked_index_shard> (); |
| map.shard->install_addrmap (&addrmap); |
| |
| 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); |
| |
| idx->start_reading (); |
| |
| return true; |
| } |
| |
| /* See read-debug-names.h. */ |
| |
| bool |
| dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile) |
| { |
| bool result = do_dwarf2_read_debug_names (per_objfile); |
| if (!result) |
| per_objfile->per_bfd->all_units.clear (); |
| return result; |
| } |