| /* Reading code for .gdb_index |
| |
| Copyright (C) 2023-2025 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-gdb-index.h" |
| |
| #include "cli/cli-cmds.h" |
| #include "cli/cli-style.h" |
| #include "complaints.h" |
| #include "dwarf2/index-common.h" |
| #include "dwz.h" |
| #include "event-top.h" |
| #include "gdb/gdb-index.h" |
| #include "gdbsupport/gdb-checked-static-cast.h" |
| #include "cooked-index.h" |
| #include "read.h" |
| #include "extract-store-integer.h" |
| #include "cp-support.h" |
| #include "symtab.h" |
| #include "gdbsupport/selftest.h" |
| #include "tag.h" |
| |
| /* When true, do not reject deprecated .gdb_index sections. */ |
| static bool use_deprecated_index_sections = false; |
| |
| struct dwarf2_gdb_index : public cooked_index_functions |
| { |
| /* This dumps minimal information about the index. |
| It is called via "mt print objfiles". |
| One use is to verify .gdb_index has been loaded by the |
| gdb.dwarf2/gdb-index.exp testcase. */ |
| void dump (struct objfile *objfile) override; |
| }; |
| |
| /* This is a cooked index as ingested from .gdb_index. */ |
| |
| class cooked_gdb_index : public cooked_index |
| { |
| public: |
| |
| cooked_gdb_index (cooked_index_worker_up worker, |
| int version) |
| : cooked_index (std::move (worker)), |
| version (version) |
| { } |
| |
| /* This can't be used to write an 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_gdb_index); } |
| |
| bool version_check () const override |
| { |
| return version >= 8; |
| } |
| |
| /* Index data format version. */ |
| int version; |
| }; |
| |
| /* See above. */ |
| |
| void |
| dwarf2_gdb_index::dump (struct objfile *objfile) |
| { |
| dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); |
| |
| cooked_gdb_index *index = (gdb::checked_static_cast<cooked_gdb_index *> |
| (per_objfile->per_bfd->index_table.get ())); |
| gdb_printf (".gdb_index: version %d\n", index->version); |
| cooked_index_functions::dump (objfile); |
| } |
| |
| /* This is a view into the index that converts from bytes to an |
| offset_type, and allows indexing. Unaligned bytes are specifically |
| allowed here, and handled via unpacking. */ |
| |
| class offset_view |
| { |
| public: |
| offset_view () = default; |
| |
| explicit offset_view (gdb::array_view<const gdb_byte> bytes) |
| : m_bytes (bytes) |
| { |
| } |
| |
| /* Extract the INDEXth offset_type from the array. */ |
| offset_type operator[] (size_t index) const |
| { |
| const gdb_byte *bytes = &m_bytes[index * sizeof (offset_type)]; |
| return (offset_type) extract_unsigned_integer (bytes, |
| sizeof (offset_type), |
| BFD_ENDIAN_LITTLE); |
| } |
| |
| /* Return the number of offset_types in this array. */ |
| size_t size () const |
| { |
| return m_bytes.size () / sizeof (offset_type); |
| } |
| |
| /* Return true if this view is empty. */ |
| bool empty () const |
| { |
| return m_bytes.empty (); |
| } |
| |
| private: |
| /* The underlying bytes. */ |
| gdb::array_view<const gdb_byte> m_bytes; |
| }; |
| |
| /* A worker for reading .gdb_index. The file format is described in |
| the manual. */ |
| |
| struct mapped_gdb_index |
| { |
| /* 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; |
| |
| /* The symbol table, implemented as a hash table. */ |
| offset_view symbol_table; |
| |
| /* A pointer to the constant pool. */ |
| gdb::array_view<const gdb_byte> constant_pool; |
| |
| /* The shortcut table data. */ |
| gdb::array_view<const gdb_byte> shortcut_table; |
| |
| /* An address map that maps from PC to dwarf2_per_cu. */ |
| addrmap_fixed *index_addrmap = nullptr; |
| |
| /* The name of 'main', or nullptr if not known. */ |
| const char *main_name = nullptr; |
| |
| /* The language of 'main', if known. */ |
| enum language main_lang = language_minimal; |
| |
| /* The result we're constructing. */ |
| cooked_index_worker_result result; |
| |
| /* Return the index into the constant pool of the name of the IDXth |
| symbol in the symbol table. */ |
| offset_type symbol_name_index (offset_type idx) const |
| { |
| return symbol_table[2 * idx]; |
| } |
| |
| /* Return the index into the constant pool of the CU vector of the |
| IDXth symbol in the symbol table. */ |
| offset_type symbol_vec_index (offset_type idx) const |
| { |
| return symbol_table[2 * idx + 1]; |
| } |
| |
| /* Return whether the name at IDX in the symbol table should be |
| ignored. */ |
| bool symbol_name_slot_invalid (offset_type idx) const |
| { |
| return symbol_name_index (idx) == 0 && symbol_vec_index (idx) == 0; |
| } |
| |
| /* Convenience method to get at the name of the symbol at IDX in the |
| symbol table. */ |
| const char *symbol_name_at (offset_type idx, |
| dwarf2_per_objfile *per_objfile) const |
| { |
| return (const char *) (this->constant_pool.data () |
| + symbol_name_index (idx)); |
| } |
| |
| size_t symbol_name_count () const |
| { return this->symbol_table.size () / 2; } |
| |
| /* Set the name and language of the main function from the shortcut |
| table. */ |
| void set_main_name (dwarf2_per_objfile *per_objfile); |
| |
| /* Build the symbol name component sorted vector, if we haven't |
| yet. */ |
| void build_name_components (dwarf2_per_objfile *per_objfile); |
| }; |
| |
| /* See declaration. */ |
| |
| void |
| mapped_gdb_index::build_name_components (dwarf2_per_objfile *per_objfile) |
| { |
| std::vector<std::pair<std::string_view, std::vector<cooked_index_entry *>>> |
| need_parents; |
| gdb::unordered_map<std::string_view, cooked_index_entry *> by_name; |
| |
| auto count = this->symbol_name_count (); |
| for (offset_type idx = 0; idx < count; idx++) |
| { |
| if (this->symbol_name_slot_invalid (idx)) |
| continue; |
| |
| const char *name = this->symbol_name_at (idx, per_objfile); |
| |
| /* This code only knows how to break apart components of C++ |
| symbol names (and other languages that use '::' as |
| namespace/module separator) and Ada symbol names. |
| |
| It's unfortunate that we need the language, but since it is |
| really only used to rebuild full names, pairing it with the |
| split method is fine. */ |
| enum language lang; |
| std::vector<std::string_view> components; |
| if (strstr (name, "::") != nullptr) |
| { |
| components = split_name (name, split_style::CXX); |
| lang = language_cplus; |
| } |
| else if (strchr (name, '<') != nullptr) |
| { |
| /* Guess that this is a template and so a C++ name. */ |
| components.emplace_back (name); |
| lang = language_cplus; |
| } |
| else if (strstr (name, "__") != nullptr) |
| { |
| /* The Ada case is handled during finalization, because gdb |
| does not write the synthesized package names into the |
| index. */ |
| components.emplace_back (name); |
| lang = language_ada; |
| } |
| else |
| { |
| components = split_name (name, split_style::DOT_STYLE); |
| /* Mark ordinary names as having an unknown language. This |
| is a hack to avoid problems with some Ada names. */ |
| lang = (components.size () == 1) ? language_unknown : language_go; |
| } |
| |
| std::vector<cooked_index_entry *> these_entries; |
| offset_view vec (constant_pool.slice (symbol_vec_index (idx))); |
| offset_type vec_len = vec[0]; |
| bool global_seen = false; |
| for (offset_type vec_idx = 0; vec_idx < vec_len; ++vec_idx) |
| { |
| offset_type cu_index_and_attrs = vec[vec_idx + 1]; |
| gdb_index_symbol_kind symbol_kind |
| = GDB_INDEX_SYMBOL_KIND_VALUE (cu_index_and_attrs); |
| /* Only use a symbol if the attributes are present. Indices |
| prior to version 7 don't record them, and indices >= 7 |
| may elide them for certain symbols (gold does this). */ |
| if (symbol_kind == GDB_INDEX_SYMBOL_KIND_NONE) |
| continue; |
| |
| int is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (cu_index_and_attrs); |
| |
| int cu_index = GDB_INDEX_CU_VALUE (cu_index_and_attrs); |
| /* Don't crash on bad data. */ |
| if (cu_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 = units[cu_index]; |
| |
| enum language this_lang = lang; |
| dwarf_tag tag; |
| switch (symbol_kind) |
| { |
| case GDB_INDEX_SYMBOL_KIND_VARIABLE: |
| tag = DW_TAG_variable; |
| break; |
| case GDB_INDEX_SYMBOL_KIND_FUNCTION: |
| tag = DW_TAG_subprogram; |
| break; |
| case GDB_INDEX_SYMBOL_KIND_TYPE: |
| if (is_static) |
| tag = (dwarf_tag) DW_TAG_GDB_INDEX_TYPE; |
| else |
| { |
| /* Work around gold/15646. */ |
| if (global_seen) |
| continue; |
| global_seen = true; |
| |
| tag = DW_TAG_structure_type; |
| this_lang = language_cplus; |
| } |
| break; |
| /* The "default" should not happen, but we mention it to |
| avoid an uninitialized warning. */ |
| default: |
| case GDB_INDEX_SYMBOL_KIND_OTHER: |
| tag = (dwarf_tag) DW_TAG_GDB_INDEX_OTHER; |
| break; |
| } |
| |
| cooked_index_flag flags = 0; |
| if (is_static) |
| flags |= IS_STATIC; |
| if (main_name != nullptr |
| && tag == DW_TAG_subprogram |
| && strcmp (name, main_name) == 0) |
| { |
| flags |= IS_MAIN; |
| this_lang = main_lang; |
| /* Don't bother looking for another. */ |
| main_name = nullptr; |
| } |
| |
| /* Note that this assumes the final component ends in \0. */ |
| cooked_index_entry *entry = result.add (per_cu->sect_off, tag, |
| flags, this_lang, |
| components.back ().data (), |
| nullptr, per_cu); |
| /* Don't bother pushing if we do not need a parent. */ |
| if (components.size () > 1) |
| these_entries.push_back (entry); |
| |
| /* We don't care exactly which entry ends up in this |
| map. */ |
| by_name[std::string_view (name)] = entry; |
| } |
| |
| if (components.size () > 1) |
| { |
| std::string_view penultimate = components[components.size () - 2]; |
| std::string_view prefix (name, &penultimate.back () + 1 - name); |
| |
| need_parents.emplace_back (prefix, std::move (these_entries)); |
| } |
| } |
| |
| for (const auto &[prefix, entries] : need_parents) |
| { |
| auto iter = by_name.find (prefix); |
| /* If we can't find the parent entry, just lose. It should |
| always be there. We could synthesize it from the components, |
| if we kept those, but that seems like overkill. */ |
| if (iter != by_name.end ()) |
| { |
| for (cooked_index_entry *entry : entries) |
| entry->set_parent (iter->second); |
| } |
| } |
| } |
| |
| /* The worker that reads a mapped index and fills in a |
| cooked_index_worker_result. */ |
| |
| class gdb_index_worker : public cooked_index_worker |
| { |
| public: |
| |
| gdb_index_worker (dwarf2_per_objfile *per_objfile, |
| std::unique_ptr<mapped_gdb_index> map) |
| : cooked_index_worker (per_objfile), |
| map (std::move (map)) |
| { } |
| |
| void do_reading () override; |
| |
| /* The map we're reading. */ |
| std::unique_ptr<mapped_gdb_index> map; |
| }; |
| |
| void |
| gdb_index_worker::do_reading () |
| { |
| complaint_interceptor complaint_handler; |
| map->build_name_components (m_per_objfile); |
| |
| m_results.push_back (std::move (map->result)); |
| m_results[0].done_reading (complaint_handler.release ()); |
| |
| /* No longer needed. */ |
| map.reset (); |
| |
| done_reading (); |
| |
| bfd_thread_cleanup (); |
| } |
| |
| /* A helper function that reads the .gdb_index from BUFFER and fills |
| in MAP. FILENAME is the name of the file containing the data; |
| it is used for error reporting. DEPRECATED_OK is true if it is |
| ok to use deprecated sections. |
| |
| CU_LIST, CU_LIST_ELEMENTS, TYPES_LIST, and TYPES_LIST_ELEMENTS are |
| out parameters that are filled in with information about the CU and |
| TU lists in the section. |
| |
| Returns true if all went well, false otherwise. */ |
| |
| static bool |
| read_gdb_index_from_buffer (const char *filename, |
| bool deprecated_ok, |
| gdb::array_view<const gdb_byte> buffer, |
| mapped_gdb_index *map, |
| const gdb_byte **cu_list, |
| offset_type *cu_list_elements, |
| const gdb_byte **types_list, |
| offset_type *types_list_elements) |
| { |
| const gdb_byte *addr = &buffer[0]; |
| offset_view metadata (buffer); |
| |
| /* Version check. */ |
| offset_type version = metadata[0]; |
| /* GDB now requires the symbol attributes, which were added in |
| version 7. */ |
| if (version < 7) |
| { |
| static int warning_printed = 0; |
| if (!warning_printed) |
| { |
| warning (_("Skipping obsolete .gdb_index section in %s."), |
| filename); |
| warning_printed = 1; |
| } |
| return 0; |
| } |
| /* Version 7 indices generated by gold refer to the CU for a symbol instead |
| of the TU (for symbols coming from TUs), |
| http://sourceware.org/bugzilla/show_bug.cgi?id=15021. |
| Plus gold-generated indices can have duplicate entries for global symbols, |
| http://sourceware.org/bugzilla/show_bug.cgi?id=15646. |
| These are just performance bugs, and we can't distinguish gdb-generated |
| indices from gold-generated ones, so issue no warning here. */ |
| |
| /* Indexes with higher version than the one supported by GDB may be no |
| longer backward compatible. */ |
| if (version > 9) |
| return 0; |
| |
| map->version = version; |
| |
| int i = 1; |
| *cu_list = addr + metadata[i]; |
| *cu_list_elements = (metadata[i + 1] - metadata[i]) / 8; |
| ++i; |
| |
| *types_list = addr + metadata[i]; |
| *types_list_elements = (metadata[i + 1] - metadata[i]) / 8; |
| ++i; |
| |
| const gdb_byte *address_table = addr + metadata[i]; |
| const gdb_byte *address_table_end = addr + metadata[i + 1]; |
| map->address_table |
| = gdb::array_view<const gdb_byte> (address_table, address_table_end); |
| ++i; |
| |
| const gdb_byte *symbol_table = addr + metadata[i]; |
| const gdb_byte *symbol_table_end = addr + metadata[i + 1]; |
| map->symbol_table |
| = offset_view (gdb::array_view<const gdb_byte> (symbol_table, |
| symbol_table_end)); |
| |
| ++i; |
| |
| if (version >= 9) |
| { |
| const gdb_byte *shortcut_table = addr + metadata[i]; |
| const gdb_byte *shortcut_table_end = addr + metadata[i + 1]; |
| map->shortcut_table |
| = gdb::array_view<const gdb_byte> (shortcut_table, shortcut_table_end); |
| ++i; |
| } |
| |
| map->constant_pool = buffer.slice (metadata[i]); |
| |
| if (map->constant_pool.empty () && !map->symbol_table.empty ()) |
| { |
| /* An empty constant pool implies that all symbol table entries are |
| empty. Make map->symbol_table.empty () == true. */ |
| map->symbol_table |
| = offset_view (gdb::array_view<const gdb_byte> (symbol_table, |
| symbol_table)); |
| } |
| |
| return 1; |
| } |
| |
| /* A helper for create_cus_from_gdb_index that handles a given list of |
| CUs. */ |
| |
| 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, std::vector<dwarf2_per_cu *> &units) |
| { |
| for (offset_type i = 0; i < n_elements; i += 2) |
| { |
| static_assert (sizeof (ULONGEST) >= 8); |
| |
| sect_offset sect_off |
| = (sect_offset) extract_unsigned_integer (cu_list, 8, BFD_ENDIAN_LITTLE); |
| ULONGEST length = extract_unsigned_integer (cu_list + 8, 8, BFD_ENDIAN_LITTLE); |
| cu_list += 2 * 8; |
| |
| 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)); |
| } |
| } |
| |
| /* Read the CU list from the mapped index, and use it to create all |
| the CU objects for 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, 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, units); |
| } |
| |
| /* Create the signatured type hash table from the index. */ |
| |
| 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, |
| std::vector<dwarf2_per_cu *> &units) |
| { |
| signatured_type_set sig_types_hash; |
| |
| for (offset_type i = 0; i < elements; i += 3) |
| { |
| static_assert (sizeof (ULONGEST) >= 8); |
| sect_offset sect_off |
| = (sect_offset) extract_unsigned_integer (bytes, 8, BFD_ENDIAN_LITTLE); |
| cu_offset type_offset_in_tu |
| = (cu_offset) extract_unsigned_integer (bytes + 8, 8, |
| BFD_ENDIAN_LITTLE); |
| ULONGEST signature |
| = extract_unsigned_integer (bytes + 16, 8, BFD_ENDIAN_LITTLE); |
| bytes += 3 * 8; |
| |
| /* The length of the type unit is unknown at this time. It gets |
| (presumably) set by a cutu_reader when it gets expanded later. */ |
| signatured_type_up sig_type |
| = per_bfd->allocate_signatured_type (section, sect_off, 0 /* length */, |
| false /* is_dwz */, signature); |
| 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 ()); |
| } |
| |
| per_bfd->signatured_types = std::move (sig_types_hash); |
| } |
| |
| /* Read the address map data from the mapped GDB index. Return true if no |
| errors were found, otherwise return false. */ |
| |
| static bool |
| create_addrmap_from_gdb_index (dwarf2_per_objfile *per_objfile, |
| mapped_gdb_index *index) |
| { |
| const gdb_byte *iter, *end; |
| |
| addrmap_mutable mutable_map; |
| |
| iter = index->address_table.data (); |
| end = iter + index->address_table.size (); |
| |
| while (iter < end) |
| { |
| ULONGEST hi, lo, cu_index; |
| lo = extract_unsigned_integer (iter, 8, BFD_ENDIAN_LITTLE); |
| iter += 8; |
| hi = extract_unsigned_integer (iter, 8, BFD_ENDIAN_LITTLE); |
| iter += 8; |
| cu_index = extract_unsigned_integer (iter, 4, BFD_ENDIAN_LITTLE); |
| iter += 4; |
| |
| if (lo >= hi) |
| { |
| warning (_(".gdb_index address table has invalid range (%s - %s)," |
| " ignoring .gdb_index"), |
| hex_string (lo), hex_string (hi)); |
| return false; |
| } |
| |
| if (cu_index >= index->units.size ()) |
| { |
| warning (_(".gdb_index address table has invalid CU number %u," |
| " ignoring .gdb_index"), |
| (unsigned) cu_index); |
| return false; |
| } |
| |
| bool full_range_p |
| = mutable_map.set_empty (lo, hi - 1, index->units[cu_index]); |
| if (!full_range_p) |
| { |
| warning (_(".gdb_index address table has a range (%s - %s) that" |
| " overlaps with an earlier range, ignoring .gdb_index"), |
| hex_string (lo), hex_string (hi)); |
| return false; |
| } |
| } |
| |
| index->result.set_addrmap (std::move (mutable_map)); |
| |
| return true; |
| } |
| |
| void |
| mapped_gdb_index::set_main_name (dwarf2_per_objfile *per_objfile) |
| { |
| const auto expected_size = 2 * sizeof (offset_type); |
| if (this->shortcut_table.size () < expected_size) |
| /* The data in the section is not present, is corrupted or is in a version |
| we don't know about. Regardless, we can't make use of it. */ |
| return; |
| |
| auto ptr = this->shortcut_table.data (); |
| const auto dw_lang = extract_unsigned_integer (ptr, 4, BFD_ENDIAN_LITTLE); |
| if (dw_lang >= DW_LANG_hi_user) |
| { |
| complaint (_(".gdb_index shortcut table has invalid main language %u"), |
| (unsigned) dw_lang); |
| return; |
| } |
| if (dw_lang == 0) |
| { |
| /* Don't bother if the language for the main symbol was not known or if |
| there was no main symbol at all when the index was built. */ |
| return; |
| } |
| ptr += 4; |
| |
| main_lang = dwarf_lang_to_enum_language (dw_lang); |
| const auto name_offset = extract_unsigned_integer (ptr, |
| sizeof (offset_type), |
| BFD_ENDIAN_LITTLE); |
| main_name = (const char *) (this->constant_pool.data () + name_offset); |
| } |
| |
| /* See read-gdb-index.h. */ |
| |
| bool |
| dwarf2_read_gdb_index |
| (dwarf2_per_objfile *per_objfile, |
| get_gdb_index_contents_ftype get_gdb_index_contents, |
| get_gdb_index_contents_dwz_ftype get_gdb_index_contents_dwz) |
| { |
| const gdb_byte *cu_list, *types_list, *dwz_list = NULL; |
| offset_type cu_list_elements, types_list_elements, dwz_list_elements = 0; |
| struct objfile *objfile = per_objfile->objfile; |
| dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; |
| scoped_remove_all_units remove_all_units (*per_bfd); |
| |
| gdb::array_view<const gdb_byte> main_index_contents |
| = get_gdb_index_contents (objfile, per_bfd); |
| |
| if (main_index_contents.empty ()) |
| return false; |
| |
| auto map = std::make_unique<mapped_gdb_index> (); |
| if (!read_gdb_index_from_buffer (objfile_name (objfile), |
| use_deprecated_index_sections, |
| main_index_contents, map.get (), &cu_list, |
| &cu_list_elements, &types_list, |
| &types_list_elements)) |
| return false; |
| |
| /* Don't use the index if it's empty. */ |
| if (map->symbol_table.empty ()) |
| return false; |
| |
| /* If there is a .dwz file, read it so we can get its CU list as |
| well. */ |
| dwz_file *dwz = per_bfd->get_dwz_file (); |
| if (dwz != NULL) |
| { |
| mapped_gdb_index dwz_map; |
| const gdb_byte *dwz_types_ignore; |
| offset_type dwz_types_elements_ignore; |
| |
| gdb::array_view<const gdb_byte> dwz_index_content |
| = get_gdb_index_contents_dwz (objfile, dwz); |
| |
| if (dwz_index_content.empty ()) |
| return false; |
| |
| if (!read_gdb_index_from_buffer (dwz->filename (), |
| 1, dwz_index_content, &dwz_map, |
| &dwz_list, &dwz_list_elements, |
| &dwz_types_ignore, |
| &dwz_types_elements_ignore)) |
| { |
| warning (_("could not read '.gdb_index' section from %s; skipping"), |
| dwz->filename ()); |
| return false; |
| } |
| } |
| |
| create_cus_from_gdb_index (per_bfd, cu_list, cu_list_elements, map->units, |
| dwz_list, dwz_list_elements); |
| |
| if (types_list_elements) |
| { |
| /* 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->infos[0]); |
| |
| create_signatured_type_table_from_gdb_index (per_bfd, section, types_list, |
| types_list_elements, |
| map->units); |
| } |
| |
| finalize_all_units (per_bfd); |
| |
| if (!create_addrmap_from_gdb_index (per_objfile, map.get ())) |
| return false; |
| |
| map->set_main_name (per_objfile); |
| |
| int version = map->version; |
| auto worker = std::make_unique<gdb_index_worker> (per_objfile, |
| std::move (map)); |
| auto idx = std::make_unique<cooked_gdb_index> (std::move (worker), |
| version); |
| |
| per_bfd->start_reading (std::move (idx)); |
| remove_all_units.disable (); |
| |
| return true; |
| } |
| |
| INIT_GDB_FILE (read_gdb_index) |
| { |
| add_setshow_boolean_cmd ("use-deprecated-index-sections", |
| no_class, &use_deprecated_index_sections, _("\ |
| Set whether to use deprecated gdb_index sections."), _("\ |
| Show whether to use deprecated gdb_index sections."), _("\ |
| When enabled, deprecated .gdb_index sections are used anyway.\n\ |
| Normally they are ignored either because of a missing feature or\n\ |
| performance issue.\n\ |
| Warning: This option must be enabled before gdb reads the file."), |
| NULL, |
| NULL, |
| &setlist, &showlist); |
| } |