diff options
Diffstat (limited to 'gdb/dwarf2')
-rw-r--r-- | gdb/dwarf2/abbrev.c | 9 | ||||
-rw-r--r-- | gdb/dwarf2/abbrev.h | 8 | ||||
-rw-r--r-- | gdb/dwarf2/ada-imported.c | 2 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-index-entry.c | 10 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-index-shard.c | 18 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-index-shard.h | 7 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-index-worker.h | 15 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-index.h | 10 | ||||
-rw-r--r-- | gdb/dwarf2/cooked-indexer.c | 37 | ||||
-rw-r--r-- | gdb/dwarf2/index-common.c | 10 | ||||
-rw-r--r-- | gdb/dwarf2/index-write.c | 100 | ||||
-rw-r--r-- | gdb/dwarf2/line-program.c | 720 | ||||
-rw-r--r-- | gdb/dwarf2/line-program.h | 47 | ||||
-rw-r--r-- | gdb/dwarf2/read-debug-names.c | 20 | ||||
-rw-r--r-- | gdb/dwarf2/read-gdb-index.c | 1312 | ||||
-rw-r--r-- | gdb/dwarf2/read-gdb-index.h | 14 | ||||
-rw-r--r-- | gdb/dwarf2/read.c | 1229 | ||||
-rw-r--r-- | gdb/dwarf2/read.h | 123 | ||||
-rw-r--r-- | gdb/dwarf2/stringify.c | 6 | ||||
-rw-r--r-- | gdb/dwarf2/tag.h | 12 |
20 files changed, 1605 insertions, 2104 deletions
diff --git a/gdb/dwarf2/abbrev.c b/gdb/dwarf2/abbrev.c index 5cfff69..e3c268e 100644 --- a/gdb/dwarf2/abbrev.c +++ b/gdb/dwarf2/abbrev.c @@ -108,6 +108,8 @@ abbrev_table::read (struct dwarf2_section_info *section, cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr); abbrev_ptr += 1; + cur_abbrev->maybe_ada_import = false; + unsigned int size = 0; unsigned int sibling_offset = -1; bool is_csize = true; @@ -242,7 +244,12 @@ abbrev_table::read (struct dwarf2_section_info *section, } else if (has_hardcoded_declaration && (cur_abbrev->tag != DW_TAG_variable || !has_external)) - cur_abbrev->interesting = false; + { + cur_abbrev->interesting = false; + if (cur_abbrev->tag == DW_TAG_subprogram && has_name + && has_linkage_name) + cur_abbrev->maybe_ada_import = true; + } else if (!tag_interesting_for_index (cur_abbrev->tag)) cur_abbrev->interesting = false; else diff --git a/gdb/dwarf2/abbrev.h b/gdb/dwarf2/abbrev.h index 6fc61b1..a36bb8c 100644 --- a/gdb/dwarf2/abbrev.h +++ b/gdb/dwarf2/abbrev.h @@ -51,6 +51,14 @@ struct abbrev_info /* True if the DIE has children. */ bool has_children; bool interesting; + /* In Ada, an imported subprogram DIE will be marked as a + declaration, but will have both a name and a linkage name. This + declaration may be the only spot where that name is associated + with an object, so it has to show up in the index. But, because + abbrevs are CU-independent, we can't check the language when + computing them and instead we keep a separate flag to indicate + that the scanner should check this DIE. */ + bool maybe_ada_import; unsigned short size_if_constant; unsigned short sibling_offset; /* Number of attributes. */ diff --git a/gdb/dwarf2/ada-imported.c b/gdb/dwarf2/ada-imported.c index 1e25966..48e6fcc 100644 --- a/gdb/dwarf2/ada-imported.c +++ b/gdb/dwarf2/ada-imported.c @@ -109,7 +109,7 @@ ada_alias_get_block_value (const struct symbol *sym) if (real_symbol.symbol == nullptr) error (_("could not find alias '%s' for function '%s'"), name, sym->print_name ()); - if (real_symbol.symbol->aclass () != LOC_BLOCK) + if (real_symbol.symbol->loc_class () != LOC_BLOCK) error (_("alias '%s' for function '%s' is not a function"), name, sym->print_name ()); diff --git a/gdb/dwarf2/cooked-index-entry.c b/gdb/dwarf2/cooked-index-entry.c index 863ddd6..0482b64 100644 --- a/gdb/dwarf2/cooked-index-entry.c +++ b/gdb/dwarf2/cooked-index-entry.c @@ -19,7 +19,6 @@ #include "dwarf2/cooked-index-entry.h" #include "dwarf2/tag.h" -#include "gdbsupport/gdb-safe-ctype.h" #include "gdbsupport/selftest.h" /* See cooked-index-entry.h. */ @@ -57,7 +56,7 @@ cooked_index_entry::compare (const char *stra, const char *strb, template functions" section in the manual. */ if (c == '<') return '\0'; - return TOLOWER ((unsigned char) c); + return c_tolower (c); }; unsigned char a = munge (*stra); @@ -189,8 +188,15 @@ cooked_index_entry::full_name (struct obstack *storage, break; case language_ada: + /* If GNAT emits hierarchical names (patches not in at the time + of writing), then we need to compute the linkage name here. + However for traditional GNAT, the linkage name will be in + 'name'. Detect this by looking for "__"; see also + cooked_index_shard::finalize. */ if ((name_flags & FOR_ADA_LINKAGE_NAME) != 0) { + if (strstr (name, "__") != nullptr) + return name; sep = "__"; break; } diff --git a/gdb/dwarf2/cooked-index-shard.c b/gdb/dwarf2/cooked-index-shard.c index c717bbb..e440d85 100644 --- a/gdb/dwarf2/cooked-index-shard.c +++ b/gdb/dwarf2/cooked-index-shard.c @@ -86,7 +86,21 @@ cooked_index_shard::add (sect_offset die_offset, enum dwarf_tag tag, implicit "main" discovery. */ if ((flags & IS_MAIN) != 0) m_main = result; - else if ((flags & IS_PARENT_DEFERRED) == 0 + /* The language check here is subtle: it exists solely to work + around a bug in .gdb_index. That index does not record + languages, but it might emit an entry for "main". However, + recognizing this "main" as being the main program would be wrong + -- for example, an Ada program has a C "main" but this is not the + desired target of the "start" command. Requiring the language to + be set here avoids over-eagerly setting the "main" when using + .gdb_index. Should .gdb_index ever be removed (PR symtab/31363), + the language_unknown check here could also be removed. + + Note that this explicit check isn't truly needed (it is covered + by language_may_use_plain_main as well), but it's handy as a spot + to document. */ + else if (lang != language_unknown + && (flags & IS_PARENT_DEFERRED) == 0 && parent_entry.resolved == nullptr && m_main == nullptr && language_may_use_plain_main (lang) @@ -108,7 +122,7 @@ cooked_index_shard::handle_gnat_encoded_entry characters are left as-is. This is done to make name matching a bit simpler; and for wide characters, it means the choice of Ada source charset does not affect the indexer directly. */ - std::string canonical = ada_decode (entry->name, false, false, false); + std::string canonical = ada_decode (entry->name, false, false); if (canonical.empty ()) { entry->canonical = entry->name; diff --git a/gdb/dwarf2/cooked-index-shard.h b/gdb/dwarf2/cooked-index-shard.h index 925960b..3a8e34d 100644 --- a/gdb/dwarf2/cooked-index-shard.h +++ b/gdb/dwarf2/cooked-index-shard.h @@ -48,6 +48,13 @@ public: cooked_index_entry_ref parent_entry, dwarf2_per_cu *per_cu); + /* Add a copy of NAME to the index. Return a pointer to the + copy. */ + const char *add (std::string_view name) + { + return m_names.insert (name); + } + /* Install a new fixed addrmap from the given mutable addrmap. */ void install_addrmap (addrmap_mutable *map) { diff --git a/gdb/dwarf2/cooked-index-worker.h b/gdb/dwarf2/cooked-index-worker.h index 8b9766c..433515b 100644 --- a/gdb/dwarf2/cooked-index-worker.h +++ b/gdb/dwarf2/cooked-index-worker.h @@ -87,6 +87,13 @@ public: name, parent_entry, per_cu); } + /* Add a copy of NAME to the index. Return a pointer to the + copy. */ + const char *add (std::string_view name) + { + return m_shard->add (name); + } + /* Install the current addrmap into the shard being constructed, then transfer ownership of the index to the caller. */ cooked_index_shard_up release_shard () @@ -103,6 +110,12 @@ public: return &m_addrmap; } + /* Set the mutable addrmap. */ + void set_addrmap (addrmap_mutable new_map) + { + m_addrmap = std::move (new_map); + } + /* Return the parent_map that is currently being created. */ parent_map *get_parent_map () { @@ -210,7 +223,7 @@ enum class cooked_state This is an abstract base class that defines the basic behavior of scanners. Separate concrete implementations exist for scanning - .debug_names and .debug_info. */ + .debug_names, .gdb_index, and .debug_info. */ class cooked_index_worker { diff --git a/gdb/dwarf2/cooked-index.h b/gdb/dwarf2/cooked-index.h index 43b2723..42d7ec3 100644 --- a/gdb/dwarf2/cooked-index.h +++ b/gdb/dwarf2/cooked-index.h @@ -237,15 +237,15 @@ struct cooked_index_functions : public dwarf2_base_index_functions dwarf2_base_index_functions::expand_all_symtabs (objfile); } - bool expand_symtabs_matching + bool search (struct objfile *objfile, - expand_symtabs_file_matcher file_matcher, + search_symtabs_file_matcher file_matcher, const lookup_name_info *lookup_name, - expand_symtabs_symbol_matcher symbol_matcher, - expand_symtabs_expansion_listener expansion_notify, + search_symtabs_symbol_matcher symbol_matcher, + search_symtabs_expansion_listener listener, block_search_flags search_flags, domain_search_flags domain, - expand_symtabs_lang_matcher lang_matcher) override; + search_symtabs_lang_matcher lang_matcher) override; struct compunit_symtab *find_pc_sect_compunit_symtab (struct objfile *objfile, bound_minimal_symbol msymbol, diff --git a/gdb/dwarf2/cooked-indexer.c b/gdb/dwarf2/cooked-indexer.c index d4557c45..913ff77 100644 --- a/gdb/dwarf2/cooked-indexer.c +++ b/gdb/dwarf2/cooked-indexer.c @@ -20,6 +20,9 @@ #include "dwarf2/cooked-indexer.h" #include "dwarf2/cooked-index-worker.h" #include "dwarf2/error.h" +#include "dwarf2/read.h" +#include "cp-support.h" +#include "demangle.h" /* See cooked-indexer.h. */ @@ -297,7 +300,7 @@ cooked_indexer::scan_attributes (dwarf2_per_cu *scanning_per_cu, || abbrev->tag == DW_TAG_namespace) && abbrev->has_children) *flags |= IS_TYPE_DECLARATION; - else + else if (!is_ada_import_or_export (reader->cu (), *name, *linkage_name)) { *linkage_name = nullptr; *name = nullptr; @@ -506,7 +509,8 @@ cooked_indexer::index_dies (cutu_reader *reader, /* If a DIE parent is a DW_TAG_subprogram, then the DIE is only interesting if it's a DW_TAG_subprogram or a DW_TAG_entry_point. */ bool die_interesting - = (abbrev->interesting + = ((abbrev->interesting + || (m_language == language_ada && abbrev->maybe_ada_import)) && (parent_entry == nullptr || parent_entry->tag != DW_TAG_subprogram || abbrev->tag == DW_TAG_subprogram @@ -542,6 +546,11 @@ cooked_indexer::index_dies (cutu_reader *reader, flags &= ~IS_STATIC; flags |= parent_entry->flags & IS_STATIC; } + else if (abbrev->tag == DW_TAG_imported_declaration) + { + /* Match the full reader. */ + flags &= ~IS_STATIC; + } if (abbrev->tag == DW_TAG_namespace && m_language == language_cplus @@ -554,6 +563,30 @@ cooked_indexer::index_dies (cutu_reader *reader, name = nullptr; } + /* An otherwise anonymous type might be given a name (via + typedef) for linkage purposes, and gdb tries to handle this + case. See anon-struct.exp. In this case, GCC will emit a + funny thing: a linkage name for the type, but in "type" form. + That is, it will not start with _Z. */ + if ((abbrev->tag == DW_TAG_class_type + || abbrev->tag == DW_TAG_structure_type + || abbrev->tag == DW_TAG_union_type) + && m_language == language_cplus + && name == nullptr + && linkage_name != nullptr) + { + gdb::unique_xmalloc_ptr<char> dem + = gdb_demangle (linkage_name, DMGL_GNU_V3 | DMGL_TYPES); + if (dem != nullptr) + { + /* We're only interested in the last component. */ + std::vector<std::string_view> split + = split_name (dem.get (), split_style::CXX); + name = m_index_storage->add (split.back ()); + linkage_name = nullptr; + } + } + cooked_index_entry *this_entry = nullptr; if (name != nullptr) { diff --git a/gdb/dwarf2/index-common.c b/gdb/dwarf2/index-common.c index c24c8fc..a314ce7 100644 --- a/gdb/dwarf2/index-common.c +++ b/gdb/dwarf2/index-common.c @@ -31,7 +31,7 @@ mapped_index_string_hash (int index_version, const void *p) while ((c = *str++) != 0) { if (index_version >= 5) - c = tolower (c); + c = c_tolower (c); r = r * 67 + c - 113; } @@ -45,12 +45,12 @@ dwarf5_djb_hash (const char *str_) { const unsigned char *str = (const unsigned char *) str_; - /* Note: tolower here ignores UTF-8, which isn't fully compliant. + /* Note: c_tolower here ignores UTF-8, which isn't fully compliant. See http://dwarfstd.org/ShowIssue.php?issue=161027.1. */ uint32_t hash = 5381; while (int c = *str++) - hash = hash * 33 + tolower (c); + hash = hash * 33 + c_tolower (c); return hash; } @@ -59,11 +59,11 @@ dwarf5_djb_hash (const char *str_) uint32_t dwarf5_djb_hash (std::string_view str) { - /* Note: tolower here ignores UTF-8, which isn't fully compliant. + /* Note: c_tolower here ignores UTF-8, which isn't fully compliant. See http://dwarfstd.org/ShowIssue.php?issue=161027.1. */ uint32_t hash = 5381; for (char c : str) - hash = hash * 33 + tolower (c & 0xff); + hash = hash * 33 + c_tolower (c & 0xff); return hash; } diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c index d5b198b..37e66a5 100644 --- a/gdb/dwarf2/index-write.c +++ b/gdb/dwarf2/index-write.c @@ -55,7 +55,7 @@ #define DW2_GDB_INDEX_SYMBOL_KIND_SET_VALUE(cu_index, value) \ do { \ gdb_assert ((value) >= GDB_INDEX_SYMBOL_KIND_TYPE \ - && (value) <= GDB_INDEX_SYMBOL_KIND_OTHER); \ + && (value) <= GDB_INDEX_SYMBOL_KIND_UNUSED5); \ GDB_INDEX_SYMBOL_KIND_SET_VALUE((cu_index), (value)); \ } while (0) @@ -422,10 +422,47 @@ symtab_index_entry::minimize () if (name == nullptr || cu_indices.empty ()) return; - std::sort (cu_indices.begin (), cu_indices.end ()); + /* We sort the indexes in a funny way: GDB_INDEX_SYMBOL_KIND_UNUSED5 + is always sorted last; then otherwise we sort by numeric value. + This ensures that we prefer the definition when both a definition + and a declaration (stub type) are seen. */ + std::sort (cu_indices.begin (), cu_indices.end (), + [] (offset_type vala, offset_type valb) + { + auto kinda = GDB_INDEX_SYMBOL_KIND_VALUE (vala); + auto kindb = GDB_INDEX_SYMBOL_KIND_VALUE (valb); + if (kinda != kindb) + { + /* Declaration sorts last. */ + if (kinda == GDB_INDEX_SYMBOL_KIND_UNUSED5) + return false; + if (kindb == GDB_INDEX_SYMBOL_KIND_UNUSED5) + return true; + } + return vala < valb; + }); auto from = std::unique (cu_indices.begin (), cu_indices.end ()); cu_indices.erase (from, cu_indices.end ()); + /* Rewrite GDB_INDEX_SYMBOL_KIND_UNUSED5. This ensures that a type + declaration will be deleted by the subsequent squashing step, if + warranted. */ + for (auto &val : cu_indices) + { + gdb_index_symbol_kind kind = GDB_INDEX_SYMBOL_KIND_VALUE (val); + if (kind != GDB_INDEX_SYMBOL_KIND_UNUSED5) + continue; + + offset_type newval = 0; + DW2_GDB_INDEX_CU_SET_VALUE (newval, GDB_INDEX_CU_VALUE (val)); + DW2_GDB_INDEX_SYMBOL_STATIC_SET_VALUE + (newval, GDB_INDEX_SYMBOL_STATIC_VALUE (val)); + DW2_GDB_INDEX_SYMBOL_KIND_SET_VALUE (newval, + GDB_INDEX_SYMBOL_KIND_TYPE); + + val = newval; + } + /* We don't want to enter a type more than once, so remove any such duplicates from the list as well. When doing this, we want to keep the entry from the first CU -- but this is @@ -720,7 +757,7 @@ public: }); m_name_table_string_offs.push_back_reorder - (m_debugstrlookup.lookup (name.c_str ())); /* ??? */ + (m_debugstrlookup.lookup (name.c_str ())); m_name_table_entry_offs.push_back_reorder (m_entry_pool.size ()); for (const cooked_index_entry *entry : these_entries) @@ -885,10 +922,21 @@ private: { public: - /* Object constructor to be called for current DWARF2_PER_BFD. */ - debug_str_lookup (dwarf2_per_bfd *per_bfd) + /* Object constructor to be called for current DWARF2_PER_BFD. + All .debug_str section strings are automatically stored. */ + explicit debug_str_lookup (dwarf2_per_bfd *per_bfd) : m_per_bfd (per_bfd) { + gdb_assert (per_bfd->str.readin); + const gdb_byte *data = per_bfd->str.buffer; + if (data == nullptr) + return; + while (data < per_bfd->str.buffer + per_bfd->str.size) + { + const char *const s = reinterpret_cast<const char *> (data); + m_str_table.emplace (c_str_view (s), data - per_bfd->str.buffer); + data += strlen (s) + 1; + } } /* Return offset of symbol name S in the .debug_str section. Add @@ -896,13 +944,6 @@ private: yet. */ size_t lookup (const char *s) { - /* Most strings will have come from the string table - already. */ - const gdb_byte *b = (const gdb_byte *) s; - if (b >= m_per_bfd->str.buffer - && b < m_per_bfd->str.buffer + m_per_bfd->str.size) - return b - m_per_bfd->str.buffer; - const auto it = m_str_table.find (c_str_view (s)); if (it != m_str_table.end ()) return it->second; @@ -1212,6 +1253,21 @@ write_cooked_index (cooked_index *table, const cu_index_map &cu_index_htab, struct mapped_symtab *symtab) { + gdb::unordered_set<const cooked_index_entry *> required_decl_entries; + for (const cooked_index_entry *entry : table->all_entries ()) + { + /* Any type declaration that is used as a (non-trivial) parent + entry must be written out. */ + if ((entry->flags & IS_TYPE_DECLARATION) == 0) + { + for (const cooked_index_entry *parent = entry->get_parent (); + parent != nullptr; + parent = parent->get_parent ()) + if ((parent->flags & IS_TYPE_DECLARATION) != 0) + required_decl_entries.insert (parent); + } + } + for (const cooked_index_entry *entry : table->all_entries ()) { const auto it = cu_index_htab.find (entry->per_cu); @@ -1237,11 +1293,10 @@ write_cooked_index (cooked_index *table, be redundant are rare and not worth supporting. */ continue; } - else if ((entry->flags & IS_TYPE_DECLARATION) != 0) - { - /* Don't add type declarations to the index. */ - continue; - } + /* Don't add most type declarations to the index. */ + else if ((entry->flags & IS_TYPE_DECLARATION) != 0 + && !required_decl_entries.contains (entry)) + continue; gdb_index_symbol_kind kind; if (entry->tag == DW_TAG_subprogram @@ -1252,7 +1307,16 @@ write_cooked_index (cooked_index *table, || entry->tag == DW_TAG_enumerator) kind = GDB_INDEX_SYMBOL_KIND_VARIABLE; else if (tag_is_type (entry->tag)) - kind = GDB_INDEX_SYMBOL_KIND_TYPE; + { + /* If we added a type declaration, we want to note this + fact for later, because we don't want a type declaration + to cause the real definition to be omitted from the + index. GDB_INDEX_SYMBOL_KIND_UNUSED5 is used here, but + rewritten later before the index is written. */ + kind = ((entry->flags & IS_TYPE_DECLARATION) == 0 + ? GDB_INDEX_SYMBOL_KIND_TYPE + : GDB_INDEX_SYMBOL_KIND_UNUSED5); + } else kind = GDB_INDEX_SYMBOL_KIND_OTHER; diff --git a/gdb/dwarf2/line-program.c b/gdb/dwarf2/line-program.c new file mode 100644 index 0000000..c30f70d --- /dev/null +++ b/gdb/dwarf2/line-program.c @@ -0,0 +1,720 @@ +/* DWARF 2 debugging format support for GDB. + + Copyright (C) 1994-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 "dwarf2/line-program.h" +#include "dwarf2/cu.h" +#include "dwarf2/line-header.h" +#include "dwarf2/read.h" +#include "buildsym.h" +#include "complaints.h" +#include "filenames.h" +#include "gdbarch.h" + +static void +dwarf2_debug_line_missing_file_complaint () +{ + complaint (_(".debug_line section has line data without a file")); +} + +static void +dwarf2_debug_line_missing_end_sequence_complaint () +{ + complaint (_(".debug_line section has line " + "program sequence without an end")); +} + +/* State machine to track the state of the line number program. */ + +class lnp_state_machine +{ +public: + /* Initialize a machine state for the start of a line number + program. */ + lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch, line_header *lh); + + file_entry *current_file () + { + /* lh->file_names is 0-based, but the file name numbers in the + statement program are 1-based. */ + return m_line_header->file_name_at (m_file); + } + + /* Record the line in the state machine. END_SEQUENCE is true if + we're processing the end of a sequence. */ + void record_line (bool end_sequence); + + /* Check ADDRESS is -1, -2, or zero and less than UNRELOCATED_LOWPC, and if + true nop-out rest of the lines in this sequence. */ + void check_line_address (struct dwarf2_cu *cu, + const gdb_byte *line_ptr, + unrelocated_addr unrelocated_lowpc, + unrelocated_addr address); + + void handle_set_discriminator (unsigned int discriminator) + { + m_discriminator = discriminator; + m_line_has_non_zero_discriminator |= discriminator != 0; + } + + /* Handle DW_LNE_set_address. */ + void handle_set_address (unrelocated_addr address) + { + m_op_index = 0; + m_address + = (unrelocated_addr) gdbarch_adjust_dwarf2_line (m_gdbarch, + (CORE_ADDR) address, + false); + } + + /* Handle DW_LNS_advance_pc. */ + void handle_advance_pc (CORE_ADDR adjust); + + /* Handle a special opcode. */ + void handle_special_opcode (unsigned char op_code); + + /* Handle DW_LNS_advance_line. */ + void handle_advance_line (int line_delta) + { + advance_line (line_delta); + } + + /* Handle DW_LNS_set_file. */ + void handle_set_file (file_name_index file); + + /* Handle DW_LNS_negate_stmt. */ + void handle_negate_stmt () + { + m_flags ^= LEF_IS_STMT; + } + + /* Handle DW_LNS_const_add_pc. */ + void handle_const_add_pc (); + + /* Handle DW_LNS_fixed_advance_pc. */ + void handle_fixed_advance_pc (CORE_ADDR addr_adj) + { + addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); + m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); + m_op_index = 0; + } + + /* Handle DW_LNS_copy. */ + void handle_copy () + { + record_line (false); + m_discriminator = 0; + m_flags &= ~LEF_PROLOGUE_END; + m_flags &= ~LEF_EPILOGUE_BEGIN; + } + + /* Handle DW_LNE_end_sequence. */ + void handle_end_sequence () + { + m_currently_recording_lines = true; + } + + /* Handle DW_LNS_set_prologue_end. */ + void handle_set_prologue_end () + { + m_flags |= LEF_PROLOGUE_END; + } + + void handle_set_epilogue_begin () + { + m_flags |= LEF_EPILOGUE_BEGIN; + } + +private: + /* Advance the line by LINE_DELTA. */ + void advance_line (int line_delta) + { + m_line += line_delta; + + if (line_delta != 0) + m_line_has_non_zero_discriminator = m_discriminator != 0; + } + + bool record_line_p (); + void finish_line (); + void record_line_1 (unsigned int line, linetable_entry_flags flags); + + struct dwarf2_cu *m_cu; + + /* The builder associated with the CU. */ + buildsym_compunit *m_builder; + + gdbarch *m_gdbarch; + + /* The line number header. */ + line_header *m_line_header; + + /* These are part of the standard DWARF line number state machine, + and initialized according to the DWARF spec. */ + + unsigned char m_op_index = 0; + /* The line table index of the current file. */ + file_name_index m_file = 1; + unsigned int m_line = 1; + + /* These are initialized in the constructor. */ + + unrelocated_addr m_address; + linetable_entry_flags m_flags; + unsigned int m_discriminator = 0; + + /* Additional bits of state we need to track. */ + + /* The last file a line number was recorded for. */ + struct subfile *m_last_subfile = NULL; + + /* The address of the last line entry. */ + unrelocated_addr m_last_address; + + /* Set to true when a previous line at the same address (using + m_last_address) had LEF_IS_STMT set in m_flags. This is reset to false + when a line entry at a new address (m_address different to + m_last_address) is processed. */ + bool m_stmt_at_address = false; + + /* When true, record the lines we decode. */ + bool m_currently_recording_lines = true; + + /* The last line number that was recorded, used to coalesce + consecutive entries for the same line. This can happen, for + example, when discriminators are present. PR 17276. */ + unsigned int m_last_line = 0; + bool m_line_has_non_zero_discriminator = false; +}; + +void +lnp_state_machine::handle_advance_pc (CORE_ADDR adjust) +{ + CORE_ADDR addr_adj = (((m_op_index + adjust) + / m_line_header->maximum_ops_per_instruction) + * m_line_header->minimum_instruction_length); + addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); + m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); + m_op_index = ((m_op_index + adjust) + % m_line_header->maximum_ops_per_instruction); +} + +void +lnp_state_machine::handle_special_opcode (unsigned char op_code) +{ + unsigned char adj_opcode = op_code - m_line_header->opcode_base; + unsigned char adj_opcode_d = adj_opcode / m_line_header->line_range; + unsigned char adj_opcode_r = adj_opcode % m_line_header->line_range; + CORE_ADDR addr_adj = (((m_op_index + adj_opcode_d) + / m_line_header->maximum_ops_per_instruction) + * m_line_header->minimum_instruction_length); + addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); + m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); + m_op_index = ((m_op_index + adj_opcode_d) + % m_line_header->maximum_ops_per_instruction); + + int line_delta = m_line_header->line_base + adj_opcode_r; + advance_line (line_delta); + record_line (false); + m_discriminator = 0; + m_flags &= ~LEF_PROLOGUE_END; + m_flags &= ~LEF_EPILOGUE_BEGIN; +} + +void +lnp_state_machine::handle_set_file (file_name_index file) +{ + m_file = file; + + const file_entry *fe = current_file (); + if (fe == NULL) + dwarf2_debug_line_missing_file_complaint (); + else + { + m_line_has_non_zero_discriminator = m_discriminator != 0; + dwarf2_start_subfile (m_cu, *fe, *m_line_header); + } +} + +void +lnp_state_machine::handle_const_add_pc () +{ + CORE_ADDR adjust + = (255 - m_line_header->opcode_base) / m_line_header->line_range; + + CORE_ADDR addr_adj + = (((m_op_index + adjust) + / m_line_header->maximum_ops_per_instruction) + * m_line_header->minimum_instruction_length); + + addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); + m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); + m_op_index = ((m_op_index + adjust) + % m_line_header->maximum_ops_per_instruction); +} + +/* Return true if we should add LINE to the line number table. + LINE is the line to add, LAST_LINE is the last line that was added, + LAST_SUBFILE is the subfile for LAST_LINE. + LINE_HAS_NON_ZERO_DISCRIMINATOR is non-zero if LINE has ever + had a non-zero discriminator. + + We have to be careful in the presence of discriminators. + E.g., for this line: + + for (i = 0; i < 100000; i++); + + clang can emit four line number entries for that one line, + each with a different discriminator. + See gdb.dwarf2/dw2-single-line-discriminators.exp for an example. + + However, we want gdb to coalesce all four entries into one. + Otherwise the user could stepi into the middle of the line and + gdb would get confused about whether the pc really was in the + middle of the line. + + Things are further complicated by the fact that two consecutive + line number entries for the same line is a heuristic used by gcc + to denote the end of the prologue. So we can't just discard duplicate + entries, we have to be selective about it. The heuristic we use is + that we only collapse consecutive entries for the same line if at least + one of those entries has a non-zero discriminator. PR 17276. + + Note: Addresses in the line number state machine can never go backwards + within one sequence, thus this coalescing is ok. */ + +bool +lnp_state_machine::record_line_p () +{ + if (m_builder->get_current_subfile () != m_last_subfile) + return true; + if (m_line != m_last_line) + return true; + /* Same line for the same file that we've seen already. + As a last check, for pr 17276, only record the line if the line + has never had a non-zero discriminator. */ + if (!m_line_has_non_zero_discriminator) + return true; + return false; +} + +/* Use the CU's builder to record line number LINE with the given + flags. */ + +void +lnp_state_machine::record_line_1 (unsigned int line, + linetable_entry_flags flags) +{ + if (m_currently_recording_lines) + { + unrelocated_addr addr + = unrelocated_addr (gdbarch_addr_bits_remove (m_gdbarch, + (CORE_ADDR) m_address)); + + if (dwarf_line_debug) + gdb_printf (gdb_stdlog, "Recording line %u, file %s, address %s\n", + m_line, lbasename (m_last_subfile->name.c_str ()), + paddress (m_gdbarch, (CORE_ADDR) addr)); + + m_builder->record_line (m_last_subfile, line, addr, flags); + } +} + +/* Subroutine of dwarf_decode_lines_1 to simplify it. + Mark the end of a set of line number records. */ + +void +lnp_state_machine::finish_line () +{ + if (m_last_subfile == nullptr) + return; + + if (dwarf_line_debug) + { + gdb_printf (gdb_stdlog, + "Finishing current line, file %s, address %s\n", + lbasename (m_last_subfile->name.c_str ()), + paddress (m_gdbarch, (CORE_ADDR) m_address)); + } + + record_line_1 (0, LEF_IS_STMT); +} + +void +lnp_state_machine::record_line (bool end_sequence) +{ + if (dwarf_line_debug) + { + gdb_printf (gdb_stdlog, + "Processing actual line %u: file %u," + " address %s, is_stmt %u, prologue_end %u," + " epilogue_begin %u, discrim %u%s\n", + m_line, m_file, + paddress (m_gdbarch, (CORE_ADDR) m_address), + (m_flags & LEF_IS_STMT) != 0, + (m_flags & LEF_PROLOGUE_END) != 0, + (m_flags & LEF_EPILOGUE_BEGIN) != 0, + m_discriminator, + (end_sequence ? "\t(end sequence)" : "")); + } + + file_entry *fe = current_file (); + + if (fe == NULL) + dwarf2_debug_line_missing_file_complaint (); + /* For now we ignore lines not starting on an instruction boundary. + But not when processing end_sequence for compatibility with the + previous version of the code. */ + else if (m_op_index == 0 || end_sequence) + { + /* When we switch files we insert an end maker in the first file, + switch to the second file and add a new line entry. The + problem is that the end marker inserted in the first file will + discard any previous line entries at the same address. If the + line entries in the first file are marked as is-stmt, while + the new line in the second file is non-stmt, then this means + the end marker will discard is-stmt lines so we can have a + non-stmt line. This means that there are less addresses at + which the user can insert a breakpoint. + + To improve this we track the last address in m_last_address, + and whether we have seen an is-stmt at this address. Then + when switching files, if we have seen a stmt at the current + address, and we are switching to create a non-stmt line, then + discard the new line. */ + bool file_changed = m_last_subfile != m_builder->get_current_subfile (); + bool ignore_this_line + = ((file_changed && !end_sequence && m_last_address == m_address + && ((m_flags & LEF_IS_STMT) == 0) + && m_stmt_at_address) + || (!end_sequence && m_line == 0)); + + if ((file_changed && !ignore_this_line) || end_sequence) + finish_line (); + + if (!end_sequence && !ignore_this_line) + { + linetable_entry_flags lte_flags = m_flags; + if (m_cu->producer_is_codewarrior ()) + lte_flags |= LEF_IS_STMT; + + if (record_line_p ()) + { + m_last_subfile = m_builder->get_current_subfile (); + record_line_1 (m_line, lte_flags); + m_last_line = m_line; + } + } + } + + /* Track whether we have seen any IS_STMT true at m_address in case we + have multiple line table entries all at m_address. */ + if (m_last_address != m_address) + { + m_stmt_at_address = false; + m_last_address = m_address; + } + m_stmt_at_address |= (m_flags & LEF_IS_STMT) != 0; +} + +lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch, + line_header *lh) + : m_cu (cu), + m_builder (cu->get_builder ()), + m_gdbarch (arch), + m_line_header (lh), + /* Call `gdbarch_adjust_dwarf2_line' on the initial 0 address as + if there was a line entry for it so that the backend has a + chance to adjust it and also record it in case it needs it. + This is currently used by MIPS code, + cf. `mips_adjust_dwarf2_line'. */ + m_address ((unrelocated_addr) gdbarch_adjust_dwarf2_line (arch, 0, 0)), + m_flags (lh->default_is_stmt ? LEF_IS_STMT : (linetable_entry_flags) 0), + m_last_address (m_address) +{ +} + +void +lnp_state_machine::check_line_address (struct dwarf2_cu *cu, + const gdb_byte *line_ptr, + unrelocated_addr unrelocated_lowpc, + unrelocated_addr address) +{ + /* Linkers resolve a symbolic relocation referencing a GC'd function to 0, + -1 or -2 (-2 is used by certain lld versions, see + https://github.com/llvm/llvm-project/commit/e618ccbf431f6730edb6d1467a127c3a52fd57f7). + If ADDRESS is 0, ignoring the opcode will err if the text section is + located at 0x0. In this case, additionally check that if + ADDRESS < UNRELOCATED_LOWPC. */ + + if ((address == (unrelocated_addr) 0 && address < unrelocated_lowpc) + || address == (unrelocated_addr) -1 + || address == (unrelocated_addr) -2) + { + /* This line table is for a function which has been + GCd by the linker. Ignore it. PR gdb/12528 */ + + struct objfile *objfile = cu->per_objfile->objfile; + long line_offset = line_ptr - get_debug_line_section (cu)->buffer; + + complaint (_(".debug_line address at offset 0x%lx is 0 [in module %s]"), + line_offset, objfile_name (objfile)); + m_currently_recording_lines = false; + /* Note: m_currently_recording_lines is left as false until we see + DW_LNE_end_sequence. */ + } +} + +/* Subroutine of dwarf_decode_lines to simplify it. + Process the line number information in LH. */ + +static void +dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, + unrelocated_addr lowpc) +{ + const gdb_byte *line_ptr, *extended_end; + const gdb_byte *line_end; + unsigned int bytes_read, extended_len; + unsigned char op_code, extended_op; + struct objfile *objfile = cu->per_objfile->objfile; + bfd *abfd = objfile->obfd.get (); + struct gdbarch *gdbarch = objfile->arch (); + + line_ptr = lh->statement_program_start; + line_end = lh->statement_program_end; + + /* Read the statement sequences until there's nothing left. */ + while (line_ptr < line_end) + { + /* The DWARF line number program state machine. Reset the state + machine at the start of each sequence. */ + lnp_state_machine state_machine (cu, gdbarch, lh); + bool end_sequence = false; + + /* Start a subfile for the current file of the state + machine. */ + const file_entry *fe = state_machine.current_file (); + + if (fe != NULL) + dwarf2_start_subfile (cu, *fe, *lh); + + /* Decode the table. */ + while (line_ptr < line_end && !end_sequence) + { + op_code = read_1_byte (abfd, line_ptr); + line_ptr += 1; + + if (op_code >= lh->opcode_base) + { + /* Special opcode. */ + state_machine.handle_special_opcode (op_code); + } + else switch (op_code) + { + case DW_LNS_extended_op: + extended_len = read_unsigned_leb128 (abfd, line_ptr, + &bytes_read); + line_ptr += bytes_read; + extended_end = line_ptr + extended_len; + extended_op = read_1_byte (abfd, line_ptr); + line_ptr += 1; + if (DW_LNE_lo_user <= extended_op + && extended_op <= DW_LNE_hi_user) + { + /* Vendor extension, ignore. */ + line_ptr = extended_end; + break; + } + switch (extended_op) + { + case DW_LNE_end_sequence: + state_machine.handle_end_sequence (); + end_sequence = true; + break; + case DW_LNE_set_address: + { + unrelocated_addr address + = cu->header.read_address (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + + state_machine.check_line_address (cu, line_ptr, lowpc, + address); + state_machine.handle_set_address (address); + } + break; + case DW_LNE_define_file: + { + const char *cur_file; + unsigned int mod_time, length; + dir_index dindex; + + cur_file = read_direct_string (abfd, line_ptr, + &bytes_read); + line_ptr += bytes_read; + dindex = (dir_index) + read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + mod_time = + read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + length = + read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + lh->add_file_name (cur_file, dindex, mod_time, length); + } + break; + case DW_LNE_set_discriminator: + { + /* The discriminator is not interesting to the + debugger; just ignore it. We still need to + check its value though: + if there are consecutive entries for the same + (non-prologue) line we want to coalesce them. + PR 17276. */ + unsigned int discr + = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + + state_machine.handle_set_discriminator (discr); + } + break; + default: + complaint (_("mangled .debug_line section")); + return; + } + /* Make sure that we parsed the extended op correctly. If e.g. + we expected a different address size than the producer used, + we may have read the wrong number of bytes. */ + if (line_ptr != extended_end) + { + complaint (_("mangled .debug_line section")); + return; + } + break; + case DW_LNS_copy: + state_machine.handle_copy (); + break; + case DW_LNS_advance_pc: + { + CORE_ADDR adjust + = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + + state_machine.handle_advance_pc (adjust); + } + break; + case DW_LNS_advance_line: + { + int line_delta + = read_signed_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + + state_machine.handle_advance_line (line_delta); + } + break; + case DW_LNS_set_file: + { + file_name_index file + = (file_name_index) read_unsigned_leb128 (abfd, line_ptr, + &bytes_read); + line_ptr += bytes_read; + + state_machine.handle_set_file (file); + } + break; + case DW_LNS_set_column: + (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + break; + case DW_LNS_negate_stmt: + state_machine.handle_negate_stmt (); + break; + case DW_LNS_set_basic_block: + break; + /* Add to the address register of the state machine the + address increment value corresponding to special opcode + 255. I.e., this value is scaled by the minimum + instruction length since special opcode 255 would have + scaled the increment. */ + case DW_LNS_const_add_pc: + state_machine.handle_const_add_pc (); + break; + case DW_LNS_fixed_advance_pc: + { + CORE_ADDR addr_adj = read_2_bytes (abfd, line_ptr); + line_ptr += 2; + + state_machine.handle_fixed_advance_pc (addr_adj); + } + break; + case DW_LNS_set_prologue_end: + state_machine.handle_set_prologue_end (); + break; + case DW_LNS_set_epilogue_begin: + state_machine.handle_set_epilogue_begin (); + break; + default: + { + /* Unknown standard opcode, ignore it. */ + int i; + + for (i = 0; i < lh->standard_opcode_lengths[op_code]; i++) + { + (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + } + } + } + } + + if (!end_sequence) + dwarf2_debug_line_missing_end_sequence_complaint (); + + /* We got a DW_LNE_end_sequence (or we ran off the end of the buffer, + in which case we still finish recording the last line). */ + state_machine.record_line (true); + } +} + +/* See dwarf2/line-program.h. */ + +void +dwarf_decode_lines (struct line_header *lh, struct dwarf2_cu *cu, + unrelocated_addr lowpc, bool decode_mapping) +{ + if (decode_mapping) + dwarf_decode_lines_1 (lh, cu, lowpc); + + /* Make sure a symtab is created for every file, even files + which contain only variables (i.e. no code with associated + line numbers). */ + buildsym_compunit *builder = cu->get_builder (); + struct compunit_symtab *cust = builder->get_compunit_symtab (); + + for (auto &fe : lh->file_names ()) + { + dwarf2_start_subfile (cu, fe, *lh); + subfile *sf = builder->get_current_subfile (); + + if (sf->symtab == nullptr) + sf->symtab = allocate_symtab (cust, sf->name.c_str (), + sf->name_for_id.c_str ()); + + fe.symtab = sf->symtab; + } +} diff --git a/gdb/dwarf2/line-program.h b/gdb/dwarf2/line-program.h new file mode 100644 index 0000000..824f18f --- /dev/null +++ b/gdb/dwarf2/line-program.h @@ -0,0 +1,47 @@ +/* DWARF 2 debugging format support for GDB. + + Copyright (C) 1994-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/>. */ + +#ifndef GDB_DWARF2_LINE_PROGRAM_H +#define GDB_DWARF2_LINE_PROGRAM_H + +/* Decode the Line Number Program (LNP) for the given line_header + structure and CU. The actual information extracted and the type + of structures created from the LNP depends on the value of PST. + + FND holds the CU file name and directory, if known. + It is used for relative paths in the line table. + + NOTE: It is important that psymtabs have the same file name (via + strcmp) as the corresponding symtab. Since the directory is not + used in the name of the symtab we don't use it in the name of the + psymtabs we create. E.g. expand_line_sal requires this when + finding psymtabs to expand. A good testcase for this is + mb-inline.exp. + + LOWPC is the lowest address in CU (or 0 if not known). + + Boolean DECODE_MAPPING specifies we need to fully decode .debug_line + for its PC<->lines mapping information. Otherwise only the filename + table is read in. */ + +extern void dwarf_decode_lines (struct line_header *lh, + struct dwarf2_cu *cu, + unrelocated_addr lowpc, bool decode_mapping); + +#endif /* GDB_DWARF2_LINE_PROGRAM_H */ diff --git a/gdb/dwarf2/read-debug-names.c b/gdb/dwarf2/read-debug-names.c index 97677c0..ddf4935 100644 --- a/gdb/dwarf2/read-debug-names.c +++ b/gdb/dwarf2/read-debug-names.c @@ -768,12 +768,12 @@ build_and_check_cu_lists_from_debug_names (dwarf2_per_bfd *per_bfd, 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 - into a separate function makes some cleanup a bit simpler. */ +/* See read-debug-names.h. */ -static bool -do_dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile) +bool +dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile) { + scoped_remove_all_units remove_all_units (*per_objfile->per_bfd); mapped_debug_names_reader map; mapped_debug_names_reader dwz_map; struct objfile *objfile = per_objfile->objfile; @@ -850,17 +850,7 @@ do_dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile) (per_objfile, std::move (map))); auto idx = std::make_unique<debug_names_index> (std::move (cidn)); per_bfd->start_reading (std::move (idx)); + remove_all_units.disable (); 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; -} diff --git a/gdb/dwarf2/read-gdb-index.c b/gdb/dwarf2/read-gdb-index.c index 76317fe..5354263 100644 --- a/gdb/dwarf2/read-gdb-index.c +++ b/gdb/dwarf2/read-gdb-index.c @@ -27,16 +27,67 @@ #include "event-top.h" #include "gdb/gdb-index.h" #include "gdbsupport/gdb-checked-static-cast.h" -#include "mapped-index.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. */ @@ -77,43 +128,11 @@ private: gdb::array_view<const gdb_byte> m_bytes; }; -/* An index into a (C++) symbol name component in a symbol name as - recorded in the mapped_index's symbol table. For each C++ symbol - in the symbol table, we record one entry for the start of each - component in the symbol in a table of name components, and then - sort the table, in order to be able to binary search symbol names, - ignoring leading namespaces, both completion and regular look up. - For example, for symbol "A::B::C", we'll have an entry that points - to "A::B::C", another that points to "B::C", and another for "C". - Note that function symbols in GDB index have no parameter - information, just the function/method names. You can convert a - name_component to a "const char *" using the - 'mapped_index::symbol_name_at(offset_type)' method. */ - -struct name_component -{ - /* Offset in the symbol name where the component starts. Stored as - a (32-bit) offset instead of a pointer to save memory and improve - locality on 64-bit architectures. */ - offset_type name_offset; - - /* The symbol's index in the symbol and constant pool tables of a - mapped_index. */ - offset_type idx; -}; - -/* A description of .gdb_index index. The file format is described in - a comment by the code that writes the index. */ +/* A worker for reading .gdb_index. The file format is described in + the manual. */ -struct mapped_gdb_index : public dwarf_scanner_base +struct mapped_gdb_index { - /* The name_component table (a sorted vector). See name_component's - description above. */ - std::vector<name_component> name_components; - - /* How NAME_COMPONENTS is sorted. */ - enum case_sensitivity name_components_casing; - /* Index data format version. */ int version = 0; @@ -136,6 +155,15 @@ struct mapped_gdb_index : public dwarf_scanner_base /* 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 @@ -152,221 +180,41 @@ struct mapped_gdb_index : public dwarf_scanner_base /* Return whether the name at IDX in the symbol table should be ignored. */ - virtual bool symbol_name_slot_invalid (offset_type idx) const + bool symbol_name_slot_invalid (offset_type idx) const { - return (symbol_name_index (idx) == 0 - && symbol_vec_index (idx) == 0); + 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. */ - virtual const char *symbol_name_at - (offset_type idx, dwarf2_per_objfile *per_objfile) const + 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)); } - virtual size_t symbol_name_count () const + 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); - - /* Returns the lower (inclusive) and upper (exclusive) bounds of the - possible matches for LN_NO_PARAMS in the name component - vector. */ - std::pair<std::vector<name_component>::const_iterator, - std::vector<name_component>::const_iterator> - find_name_components_bounds (const lookup_name_info &ln_no_params, - enum language lang, - dwarf2_per_objfile *per_objfile) const; - - quick_symbol_functions_up make_quick_functions () const override; - - bool version_check () const override - { - return version >= 8; - } - - dwarf2_per_cu *lookup (unrelocated_addr addr) override - { - if (index_addrmap == nullptr) - return nullptr; - - void *obj = index_addrmap->find (static_cast<CORE_ADDR> (addr)); - return static_cast<dwarf2_per_cu *> (obj); - } - - cooked_index *index_for_writing () override - { return nullptr; } }; - -/* Starting from a search name, return the string that finds the upper - bound of all strings that start with SEARCH_NAME in a sorted name - list. Returns the empty string to indicate that the upper bound is - the end of the list. */ - -static std::string -make_sort_after_prefix_name (const char *search_name) -{ - /* When looking to complete "func", we find the upper bound of all - symbols that start with "func" by looking for where we'd insert - the closest string that would follow "func" in lexicographical - order. Usually, that's "func"-with-last-character-incremented, - i.e. "fund". Mind non-ASCII characters, though. Usually those - will be UTF-8 multi-byte sequences, but we can't be certain. - Especially mind the 0xff character, which is a valid character in - non-UTF-8 source character sets (e.g. Latin1 'ÿ'), and we can't - rule out compilers allowing it in identifiers. Note that - conveniently, strcmp/strcasecmp are specified to compare - characters interpreted as unsigned char. So what we do is treat - the whole string as a base 256 number composed of a sequence of - base 256 "digits" and add 1 to it. I.e., adding 1 to 0xff wraps - to 0, and carries 1 to the following more-significant position. - If the very first character in SEARCH_NAME ends up incremented - and carries/overflows, then the upper bound is the end of the - list. The string after the empty string is also the empty - string. - - Some examples of this operation: - - SEARCH_NAME => "+1" RESULT - - "abc" => "abd" - "ab\xff" => "ac" - "\xff" "a" "\xff" => "\xff" "b" - "\xff" => "" - "\xff\xff" => "" - "" => "" - - Then, with these symbols for example: - - func - func1 - fund - - completing "func" looks for symbols between "func" and - "func"-with-last-character-incremented, i.e. "fund" (exclusive), - which finds "func" and "func1", but not "fund". - - And with: - - funcÿ (Latin1 'ÿ' [0xff]) - funcÿ1 - fund - - completing "funcÿ" looks for symbols between "funcÿ" and "fund" - (exclusive), which finds "funcÿ" and "funcÿ1", but not "fund". - - And with: - - ÿÿ (Latin1 'ÿ' [0xff]) - ÿÿ1 - - completing "ÿ" or "ÿÿ" looks for symbols between between "ÿÿ" and - the end of the list. - */ - std::string after = search_name; - while (!after.empty () && (unsigned char) after.back () == 0xff) - after.pop_back (); - if (!after.empty ()) - after.back () = (unsigned char) after.back () + 1; - return after; -} - -/* See declaration. */ - -std::pair<std::vector<name_component>::const_iterator, - std::vector<name_component>::const_iterator> -mapped_gdb_index::find_name_components_bounds - (const lookup_name_info &lookup_name_without_params, language lang, - dwarf2_per_objfile *per_objfile) const -{ - auto *name_cmp - = this->name_components_casing == case_sensitive_on ? strcmp : strcasecmp; - - const char *lang_name - = lookup_name_without_params.language_lookup_name (lang); - - /* Comparison function object for lower_bound that matches against a - given symbol name. */ - auto lookup_compare_lower = [&] (const name_component &elem, - const char *name) - { - const char *elem_qualified = this->symbol_name_at (elem.idx, per_objfile); - const char *elem_name = elem_qualified + elem.name_offset; - return name_cmp (elem_name, name) < 0; - }; - - /* Comparison function object for upper_bound that matches against a - given symbol name. */ - auto lookup_compare_upper = [&] (const char *name, - const name_component &elem) - { - const char *elem_qualified = this->symbol_name_at (elem.idx, per_objfile); - const char *elem_name = elem_qualified + elem.name_offset; - return name_cmp (name, elem_name) < 0; - }; - - auto begin = this->name_components.begin (); - auto end = this->name_components.end (); - - /* Find the lower bound. */ - auto lower = [&] () - { - if (lookup_name_without_params.completion_mode () && lang_name[0] == '\0') - return begin; - else - return std::lower_bound (begin, end, lang_name, lookup_compare_lower); - } (); - - /* Find the upper bound. */ - auto upper = [&] () - { - if (lookup_name_without_params.completion_mode ()) - { - /* In completion mode, we want UPPER to point past all - symbols names that have the same prefix. I.e., with - these symbols, and completing "func": - - function << lower bound - function1 - other_function << upper bound - - We find the upper bound by looking for the insertion - point of "func"-with-last-character-incremented, - i.e. "fund". */ - std::string after = make_sort_after_prefix_name (lang_name); - if (after.empty ()) - return end; - return std::lower_bound (lower, end, after.c_str (), - lookup_compare_lower); - } - else - return std::upper_bound (lower, end, lang_name, lookup_compare_upper); - } (); - - return {lower, upper}; -} - /* See declaration. */ void mapped_gdb_index::build_name_components (dwarf2_per_objfile *per_objfile) { - if (!this->name_components.empty ()) - return; + 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; - this->name_components_casing = case_sensitivity; - auto *name_cmp - = this->name_components_casing == case_sensitive_on ? strcmp : strcasecmp; - - /* The code below only knows how to break apart components of C++ - symbol names (and other languages that use '::' as - namespace/module separator) and Ada symbol names. */ auto count = this->symbol_name_count (); for (offset_type idx = 0; idx < count; idx++) { @@ -375,813 +223,186 @@ mapped_gdb_index::build_name_components (dwarf2_per_objfile *per_objfile) const char *name = this->symbol_name_at (idx, per_objfile); - /* Add each name component to the name component table. */ - unsigned int previous_len = 0; + /* 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) { - for (unsigned int current_len = cp_find_first_component (name); - name[current_len] != '\0'; - current_len += cp_find_first_component (name + current_len)) - { - gdb_assert (name[current_len] == ':'); - this->name_components.push_back ({previous_len, idx}); - /* Skip the '::'. */ - current_len += 2; - previous_len = current_len; - } + components = split_name (name, split_style::CXX); + lang = language_cplus; } - else + else if (strchr (name, '<') != nullptr) { - /* Handle the Ada encoded (aka mangled) form here. */ - for (const char *iter = strstr (name, "__"); - iter != nullptr; - iter = strstr (iter, "__")) - { - this->name_components.push_back ({previous_len, idx}); - iter += 2; - previous_len = iter - name; - } + /* Guess that this is a template and so a C++ name. */ + components.emplace_back (name); + lang = language_cplus; } - - this->name_components.push_back ({previous_len, idx}); - } - - /* Sort name_components elements by name. */ - auto name_comp_compare = [&] (const name_component &left, - const name_component &right) - { - const char *left_qualified - = this->symbol_name_at (left.idx, per_objfile); - const char *right_qualified - = this->symbol_name_at (right.idx, per_objfile); - - const char *left_name = left_qualified + left.name_offset; - const char *right_name = right_qualified + right.name_offset; - - return name_cmp (left_name, right_name) < 0; - }; - - std::sort (this->name_components.begin (), - this->name_components.end (), - name_comp_compare); -} - -/* Helper for dw2_expand_symtabs_matching that works with a - mapped_index_base instead of the containing objfile. This is split - to a separate function in order to be able to unit test the - name_components matching using a mock mapped_index_base. For each - symbol name that matches, calls MATCH_CALLBACK, passing it the - symbol's index in the mapped_index_base symbol table. */ - -static bool -dw2_expand_symtabs_matching_symbol - (mapped_gdb_index &index, - const lookup_name_info &lookup_name_in, - expand_symtabs_symbol_matcher symbol_matcher, - gdb::function_view<bool (offset_type)> match_callback, - dwarf2_per_objfile *per_objfile, - expand_symtabs_lang_matcher lang_matcher) -{ - lookup_name_info lookup_name_without_params - = lookup_name_in.make_ignore_params (); - - /* Build the symbol name component sorted vector, if we haven't - yet. */ - index.build_name_components (per_objfile); - - /* The same symbol may appear more than once in the range though. - E.g., if we're looking for symbols that complete "w", and we have - a symbol named "w1::w2", we'll find the two name components for - that same symbol in the range. To be sure we only call the - callback once per symbol, we first collect the symbol name - indexes that matched in a temporary vector and ignore - duplicates. */ - std::vector<offset_type> matches; - - struct name_and_matcher - { - symbol_name_matcher_ftype *matcher; - const char *name; - - bool operator== (const name_and_matcher &other) const - { - return matcher == other.matcher && strcmp (name, other.name) == 0; - } - }; - - /* A vector holding all the different symbol name matchers, for all - languages. */ - std::vector<name_and_matcher> matchers; - - for (int i = 0; i < nr_languages; i++) - { - enum language lang_e = (enum language) i; - if (lang_matcher != nullptr && !lang_matcher (lang_e)) - continue; - - const language_defn *lang = language_def (lang_e); - symbol_name_matcher_ftype *name_matcher - = lang->get_symbol_name_matcher (lookup_name_without_params); - - name_and_matcher key { - name_matcher, - lookup_name_without_params.language_lookup_name (lang_e) - }; - - /* Don't insert the same comparison routine more than once. - Note that we do this linear walk. This is not a problem in - practice because the number of supported languages is - low. */ - if (std::find (matchers.begin (), matchers.end (), key) - != matchers.end ()) - continue; - matchers.push_back (std::move (key)); - - auto bounds - = index.find_name_components_bounds (lookup_name_without_params, - lang_e, per_objfile); - - /* Now for each symbol name in range, check to see if we have a name - match, and if so, call the MATCH_CALLBACK callback. */ - - for (; bounds.first != bounds.second; ++bounds.first) + else if (strstr (name, "__") != nullptr) { - const char *qualified - = index.symbol_name_at (bounds.first->idx, per_objfile); - - if (!name_matcher (qualified, lookup_name_without_params, NULL) - || (symbol_matcher != NULL && !symbol_matcher (qualified))) - continue; - - matches.push_back (bounds.first->idx); + /* 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; } - } - - std::sort (matches.begin (), matches.end ()); - - /* Finally call the callback, once per match. */ - ULONGEST prev = -1; - bool result = true; - for (offset_type idx : matches) - { - if (prev != idx) + else { - if (!match_callback (idx)) - { - result = false; - break; - } - prev = idx; + 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; } - } - - /* Above we use a type wider than idx's for 'prev', since 0 and - (offset_type)-1 are both possible values. */ - static_assert (sizeof (prev) > sizeof (offset_type), ""); - - return result; -} - -#if GDB_SELF_TEST - -namespace selftests { namespace dw2_expand_symtabs_matching { - -/* A mock .gdb_index/.debug_names-like name index table, enough to - exercise dw2_expand_symtabs_matching_symbol, which works with the - mapped_index_base interface. Builds an index from the symbol list - passed as parameter to the constructor. */ -class mock_mapped_index : public mapped_gdb_index -{ -public: - mock_mapped_index (gdb::array_view<const char *> symbols) - : m_symbol_table (symbols) - {} - - DISABLE_COPY_AND_ASSIGN (mock_mapped_index); - - bool symbol_name_slot_invalid (offset_type idx) const override - { return false; } - - /* Return the number of names in the symbol table. */ - size_t symbol_name_count () const override - { - return m_symbol_table.size (); - } - - /* Get 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 override - { - return m_symbol_table[idx]; - } - - quick_symbol_functions_up make_quick_functions () const override - { - return nullptr; - } - -private: - gdb::array_view<const char *> m_symbol_table; -}; - -/* Convenience function that converts a NULL pointer to a "<null>" - string, to pass to print routines. */ - -static const char * -string_or_null (const char *str) -{ - return str != NULL ? str : "<null>"; -} - -/* Check if a lookup_name_info built from - NAME/MATCH_TYPE/COMPLETION_MODE matches the symbols in the mock - index. EXPECTED_LIST is the list of expected matches, in expected - matching order. If no match expected, then an empty list is - specified. Returns true on success. On failure prints a warning - indicating the file:line that failed, and returns false. */ - -static bool -check_match (const char *file, int line, - mock_mapped_index &mock_index, - const char *name, symbol_name_match_type match_type, - bool completion_mode, - std::initializer_list<const char *> expected_list, - dwarf2_per_objfile *per_objfile) -{ - lookup_name_info lookup_name (name, match_type, completion_mode); - - bool matched = true; - - auto mismatch = [&] (const char *expected_str, - const char *got) - { - warning (_("%s:%d: match_type=%s, looking-for=\"%s\", " - "expected=\"%s\", got=\"%s\"\n"), - file, line, - (match_type == symbol_name_match_type::FULL - ? "FULL" : "WILD"), - name, string_or_null (expected_str), string_or_null (got)); - matched = false; - }; - - auto expected_it = expected_list.begin (); - auto expected_end = expected_list.end (); - - dw2_expand_symtabs_matching_symbol (mock_index, lookup_name, - nullptr, - [&] (offset_type idx) - { - const char *matched_name = mock_index.symbol_name_at (idx, per_objfile); - const char *expected_str - = expected_it == expected_end ? NULL : *expected_it++; - - if (expected_str == NULL || strcmp (expected_str, matched_name) != 0) - mismatch (expected_str, matched_name); - return true; - }, per_objfile, nullptr); - - const char *expected_str - = expected_it == expected_end ? NULL : *expected_it++; - if (expected_str != NULL) - mismatch (expected_str, NULL); - - return matched; -} - -/* The symbols added to the mock mapped_index for testing (in - canonical form). */ -static const char *test_symbols[] = { - "function", - "std::bar", - "std::zfunction", - "std::zfunction2", - "w1::w2", - "ns::foo<char*>", - "ns::foo<int>", - "ns::foo<long>", - "ns2::tmpl<int>::foo2", - "(anonymous namespace)::A::B::C", - - /* These are used to check that the increment-last-char in the - matching algorithm for completion doesn't match "t1_fund" when - completing "t1_func". */ - "t1_func", - "t1_func1", - "t1_fund", - "t1_fund1", - - /* A UTF-8 name with multi-byte sequences to make sure that - cp-name-parser understands this as a single identifier ("função" - is "function" in PT). */ - (const char *)u8"u8função", - - /* Test a symbol name that ends with a 0xff character, which is a - valid character in non-UTF-8 source character sets (e.g. Latin1 - 'ÿ'), and we can't rule out compilers allowing it in identifiers. - We test this because the completion algorithm finds the upper - bound of symbols by looking for the insertion point of - "func"-with-last-character-incremented, i.e. "fund", and adding 1 - to 0xff should wraparound and carry to the previous character. - See comments in make_sort_after_prefix_name. */ - "yfunc\377", - - /* Some more symbols with \377 (0xff). See above. */ - "\377", - "\377\377123", - - /* A name with all sorts of complications. Starts with "z" to make - it easier for the completion tests below. */ -#define Z_SYM_NAME \ - "z::std::tuple<(anonymous namespace)::ui*, std::bar<(anonymous namespace)::ui> >" \ - "::tuple<(anonymous namespace)::ui*, " \ - "std::default_delete<(anonymous namespace)::ui>, void>" - - Z_SYM_NAME -}; -/* Returns true if the mapped_index_base::find_name_component_bounds - method finds EXPECTED_SYMS in INDEX when looking for SEARCH_NAME, - in completion mode. */ - -static bool -check_find_bounds_finds (mapped_gdb_index &index, - const char *search_name, - gdb::array_view<const char *> expected_syms, - dwarf2_per_objfile *per_objfile) -{ - lookup_name_info lookup_name (search_name, - symbol_name_match_type::FULL, true); - - auto bounds = index.find_name_components_bounds (lookup_name, - language_cplus, - per_objfile); - - size_t distance = std::distance (bounds.first, bounds.second); - if (distance != expected_syms.size ()) - return false; - - for (size_t exp_elem = 0; exp_elem < distance; exp_elem++) - { - auto nc_elem = bounds.first + exp_elem; - const char *qualified = index.symbol_name_at (nc_elem->idx, per_objfile); - if (strcmp (qualified, expected_syms[exp_elem]) != 0) - return false; - } - - return true; -} - -/* Test the lower-level mapped_index::find_name_component_bounds - method. */ - -static void -test_mapped_index_find_name_component_bounds () -{ - mock_mapped_index mock_index (test_symbols); - - mock_index.build_name_components (NULL /* per_objfile */); - - /* Test the lower-level mapped_index::find_name_component_bounds - method in completion mode. */ - { - static const char *expected_syms[] = { - "t1_func", - "t1_func1", - }; - - SELF_CHECK (check_find_bounds_finds - (mock_index, "t1_func", expected_syms, - NULL /* per_objfile */)); - } - - /* Check that the increment-last-char in the name matching algorithm - for completion doesn't get confused with Ansi1 'ÿ' / 0xff. See - make_sort_after_prefix_name. */ - { - static const char *expected_syms1[] = { - "\377", - "\377\377123", - }; - SELF_CHECK (check_find_bounds_finds - (mock_index, "\377", expected_syms1, NULL /* per_objfile */)); - - static const char *expected_syms2[] = { - "\377\377123", - }; - SELF_CHECK (check_find_bounds_finds - (mock_index, "\377\377", expected_syms2, - NULL /* per_objfile */)); - } -} - -/* Test dw2_expand_symtabs_matching_symbol. */ - -static void -test_dw2_expand_symtabs_matching_symbol () -{ - mock_mapped_index mock_index (test_symbols); - - /* We let all tests run until the end even if some fails, for debug - convenience. */ - bool any_mismatch = false; - - /* Create the expected symbols list (an initializer_list). Needed - because lists have commas, and we need to pass them to CHECK, - which is a macro. */ -#define EXPECT(...) { __VA_ARGS__ } - - /* Wrapper for check_match that passes down the current - __FILE__/__LINE__. */ -#define CHECK_MATCH(NAME, MATCH_TYPE, COMPLETION_MODE, EXPECTED_LIST) \ - any_mismatch |= !check_match (__FILE__, __LINE__, \ - mock_index, \ - NAME, MATCH_TYPE, COMPLETION_MODE, \ - EXPECTED_LIST, NULL) - - /* Identity checks. */ - for (const char *sym : test_symbols) - { - /* Should be able to match all existing symbols. */ - CHECK_MATCH (sym, symbol_name_match_type::FULL, false, - EXPECT (sym)); - - /* Should be able to match all existing symbols with - parameters. */ - std::string with_params = std::string (sym) + "(int)"; - CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false, - EXPECT (sym)); - - /* Should be able to match all existing symbols with - parameters and qualifiers. */ - with_params = std::string (sym) + " ( int ) const"; - CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false, - EXPECT (sym)); - - /* This should really find sym, but cp-name-parser.y doesn't - know about lvalue/rvalue qualifiers yet. */ - with_params = std::string (sym) + " ( int ) &&"; - CHECK_MATCH (with_params.c_str (), symbol_name_match_type::FULL, false, - {}); - } - - /* Check that the name matching algorithm for completion doesn't get - confused with Latin1 'ÿ' / 0xff. See - make_sort_after_prefix_name. */ - { - static const char str[] = "\377"; - CHECK_MATCH (str, symbol_name_match_type::FULL, true, - EXPECT ("\377", "\377\377123")); - } - - /* Check that the increment-last-char in the matching algorithm for - completion doesn't match "t1_fund" when completing "t1_func". */ - { - static const char str[] = "t1_func"; - CHECK_MATCH (str, symbol_name_match_type::FULL, true, - EXPECT ("t1_func", "t1_func1")); - } - - /* Check that completion mode works at each prefix of the expected - symbol name. */ - { - static const char str[] = "function(int)"; - size_t len = strlen (str); - std::string lookup; - - for (size_t i = 1; i < len; i++) - { - lookup.assign (str, i); - CHECK_MATCH (lookup.c_str (), symbol_name_match_type::FULL, true, - EXPECT ("function")); - } - } - - /* While "w" is a prefix of both components, the match function - should still only be called once. */ - { - CHECK_MATCH ("w", symbol_name_match_type::FULL, true, - EXPECT ("w1::w2")); - CHECK_MATCH ("w", symbol_name_match_type::WILD, true, - EXPECT ("w1::w2")); - } - - /* Same, with a "complicated" symbol. */ - { - static const char str[] = Z_SYM_NAME; - size_t len = strlen (str); - std::string lookup; - - for (size_t i = 1; i < len; i++) - { - lookup.assign (str, i); - CHECK_MATCH (lookup.c_str (), symbol_name_match_type::FULL, true, - EXPECT (Z_SYM_NAME)); - } - } - - /* In FULL mode, an incomplete symbol doesn't match. */ - { - CHECK_MATCH ("std::zfunction(int", symbol_name_match_type::FULL, false, - {}); - } - - /* A complete symbol with parameters matches any overload, since the - index has no overload info. */ - { - CHECK_MATCH ("std::zfunction(int)", symbol_name_match_type::FULL, true, - EXPECT ("std::zfunction", "std::zfunction2")); - CHECK_MATCH ("zfunction(int)", symbol_name_match_type::WILD, true, - EXPECT ("std::zfunction", "std::zfunction2")); - CHECK_MATCH ("zfunc", symbol_name_match_type::WILD, true, - EXPECT ("std::zfunction", "std::zfunction2")); - } - - /* Check that whitespace is ignored appropriately. A symbol with a - template argument list. */ - { - static const char expected[] = "ns::foo<int>"; - CHECK_MATCH ("ns :: foo < int > ", symbol_name_match_type::FULL, false, - EXPECT (expected)); - CHECK_MATCH ("foo < int > ", symbol_name_match_type::WILD, false, - EXPECT (expected)); - } - - /* Check that whitespace is ignored appropriately. A symbol with a - template argument list that includes a pointer. */ - { - static const char expected[] = "ns::foo<char*>"; - /* Try both completion and non-completion modes. */ - static const bool completion_mode[2] = {false, true}; - for (size_t i = 0; i < 2; i++) - { - CHECK_MATCH ("ns :: foo < char * >", symbol_name_match_type::FULL, - completion_mode[i], EXPECT (expected)); - CHECK_MATCH ("foo < char * >", symbol_name_match_type::WILD, - completion_mode[i], EXPECT (expected)); - - CHECK_MATCH ("ns :: foo < char * > (int)", symbol_name_match_type::FULL, - completion_mode[i], EXPECT (expected)); - CHECK_MATCH ("foo < char * > (int)", symbol_name_match_type::WILD, - completion_mode[i], EXPECT (expected)); - } - } - - { - /* Check method qualifiers are ignored. */ - static const char expected[] = "ns::foo<char*>"; - CHECK_MATCH ("ns :: foo < char * > ( int ) const", - symbol_name_match_type::FULL, true, EXPECT (expected)); - CHECK_MATCH ("ns :: foo < char * > ( int ) &&", - symbol_name_match_type::FULL, true, EXPECT (expected)); - CHECK_MATCH ("foo < char * > ( int ) const", - symbol_name_match_type::WILD, true, EXPECT (expected)); - CHECK_MATCH ("foo < char * > ( int ) &&", - symbol_name_match_type::WILD, true, EXPECT (expected)); - } - - /* Test lookup names that don't match anything. */ - { - CHECK_MATCH ("bar2", symbol_name_match_type::WILD, false, - {}); - - CHECK_MATCH ("doesntexist", symbol_name_match_type::FULL, false, - {}); - } - - /* Some wild matching tests, exercising "(anonymous namespace)", - which should not be confused with a parameter list. */ - { - static const char *syms[] = { - "A::B::C", - "B::C", - "C", - "A :: B :: C ( int )", - "B :: C ( int )", - "C ( int )", - }; - - for (const char *s : syms) - { - CHECK_MATCH (s, symbol_name_match_type::WILD, false, - EXPECT ("(anonymous namespace)::A::B::C")); - } - } - - { - static const char expected[] = "ns2::tmpl<int>::foo2"; - CHECK_MATCH ("tmp", symbol_name_match_type::WILD, true, - EXPECT (expected)); - CHECK_MATCH ("tmpl<", symbol_name_match_type::WILD, true, - EXPECT (expected)); - } - - SELF_CHECK (!any_mismatch); - -#undef EXPECT -#undef CHECK_MATCH -} - -static void -run_test () -{ - test_mapped_index_find_name_component_bounds (); - test_dw2_expand_symtabs_matching_symbol (); -} - -}} /* namespace selftests::dw2_expand_symtabs_matching */ - -#endif /* GDB_SELF_TEST */ - -struct dwarf2_gdb_index : public dwarf2_base_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; - - bool expand_symtabs_matching - (struct objfile *objfile, - expand_symtabs_file_matcher file_matcher, - const lookup_name_info *lookup_name, - expand_symtabs_symbol_matcher symbol_matcher, - expand_symtabs_expansion_listener expansion_notify, - block_search_flags search_flags, - domain_search_flags domain, - expand_symtabs_lang_matcher lang_matcher) override; -}; - -/* 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 -dwarf2_gdb_index::dump (struct objfile *objfile) -{ - dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); - - mapped_gdb_index *index = (gdb::checked_static_cast<mapped_gdb_index *> - (per_objfile->per_bfd->index_table.get ())); - gdb_printf (".gdb_index: version %d\n", index->version); - gdb_printf ("\n"); -} - -/* Helper for dw2_expand_matching symtabs. Called on each symbol - matched, to expand corresponding CUs that were marked. IDX is the - index of the symbol name that matched. */ - -static bool -dw2_expand_marked_cus (dwarf2_per_objfile *per_objfile, offset_type idx, - expand_symtabs_file_matcher file_matcher, - expand_symtabs_expansion_listener expansion_notify, - block_search_flags search_flags, - domain_search_flags kind, - expand_symtabs_lang_matcher lang_matcher) -{ - offset_type vec_len, vec_idx; - bool global_seen = false; - mapped_gdb_index &index - = *(gdb::checked_static_cast<mapped_gdb_index *> - (per_objfile->per_bfd->index_table.get ())); - - offset_view vec (index.constant_pool.slice (index.symbol_vec_index (idx))); - vec_len = vec[0]; - for (vec_idx = 0; vec_idx < vec_len; ++vec_idx) - { - offset_type cu_index_and_attrs = vec[vec_idx + 1]; - /* This value is only valid for index versions >= 7. */ - int is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (cu_index_and_attrs); - gdb_index_symbol_kind symbol_kind = - GDB_INDEX_SYMBOL_KIND_VALUE (cu_index_and_attrs); - int cu_index = GDB_INDEX_CU_VALUE (cu_index_and_attrs); - /* Only check the symbol attributes if they're present. - Indices prior to version 7 don't record them, - and indices >= 7 may elide them for certain symbols - (gold does this). */ - int attrs_valid = - (index.version >= 7 - && symbol_kind != GDB_INDEX_SYMBOL_KIND_NONE); - - /* Work around gold/15646. */ - if (attrs_valid - && !is_static - && symbol_kind == GDB_INDEX_SYMBOL_KIND_TYPE) + 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) { - if (global_seen) + 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; - global_seen = true; - } + int is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (cu_index_and_attrs); - /* Only check the symbol's kind if it has one. */ - if (attrs_valid) - { - if (is_static) + int cu_index = GDB_INDEX_CU_VALUE (cu_index_and_attrs); + /* Don't crash on bad data. */ + if (cu_index >= units.size ()) { - if ((search_flags & SEARCH_STATIC_BLOCK) == 0) - continue; - } - else - { - if ((search_flags & SEARCH_GLOBAL_BLOCK) == 0) - continue; + 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]; - domain_search_flags mask = 0; + enum language this_lang = lang; + dwarf_tag tag; switch (symbol_kind) { case GDB_INDEX_SYMBOL_KIND_VARIABLE: - mask = SEARCH_VAR_DOMAIN; + tag = DW_TAG_variable; break; case GDB_INDEX_SYMBOL_KIND_FUNCTION: - mask = SEARCH_FUNCTION_DOMAIN; + tag = DW_TAG_subprogram; break; case GDB_INDEX_SYMBOL_KIND_TYPE: - mask = SEARCH_TYPE_DOMAIN | SEARCH_STRUCT_DOMAIN; + 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: - mask = SEARCH_MODULE_DOMAIN; + tag = (dwarf_tag) DW_TAG_GDB_INDEX_OTHER; break; } - if ((kind & mask) == 0) - continue; - } - /* Don't crash on bad data. */ - if (cu_index >= index.units.size ()) - { - complaint (_(".gdb_index entry has bad CU index" - " [in module %s]"), objfile_name (per_objfile->objfile)); - continue; + 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; } - dwarf2_per_cu *per_cu = index.units[cu_index]; + if (components.size () > 1) + { + std::string_view penultimate = components[components.size () - 2]; + std::string_view prefix (name, &penultimate.back () + 1 - name); - if (!dw2_expand_symtabs_matching_one (per_cu, per_objfile, file_matcher, - expansion_notify, lang_matcher)) - return false; + need_parents.emplace_back (prefix, std::move (these_entries)); + } } - return true; + 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); + } + } } -bool -dwarf2_gdb_index::expand_symtabs_matching - (objfile *objfile, - expand_symtabs_file_matcher file_matcher, - const lookup_name_info *lookup_name, - expand_symtabs_symbol_matcher symbol_matcher, - expand_symtabs_expansion_listener expansion_notify, - block_search_flags search_flags, - domain_search_flags domain, - expand_symtabs_lang_matcher lang_matcher) +/* The worker that reads a mapped index and fills in a + cooked_index_worker_result. */ + +class gdb_index_worker : public cooked_index_worker { - dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); +public: - dw_expand_symtabs_matching_file_matcher (per_objfile, file_matcher); + gdb_index_worker (dwarf2_per_objfile *per_objfile, + std::unique_ptr<mapped_gdb_index> map) + : cooked_index_worker (per_objfile), + map (std::move (map)) + { } - /* This invariant is documented in quick-functions.h. */ - gdb_assert (lookup_name != nullptr || symbol_matcher == nullptr); - if (lookup_name == nullptr) - { - for (dwarf2_per_cu *per_cu : all_units_range (per_objfile->per_bfd)) - { - QUIT; + void do_reading () override; - if (!dw2_expand_symtabs_matching_one (per_cu, per_objfile, - file_matcher, - expansion_notify, - lang_matcher)) - return false; - } - return true; - } + /* The map we're reading. */ + std::unique_ptr<mapped_gdb_index> map; +}; - mapped_gdb_index &index - = *(gdb::checked_static_cast<mapped_gdb_index *> - (per_objfile->per_bfd->index_table.get ())); +void +gdb_index_worker::do_reading () +{ + complaint_interceptor complaint_handler; + map->build_name_components (m_per_objfile); - bool result - = dw2_expand_symtabs_matching_symbol (index, *lookup_name, - symbol_matcher, - [&] (offset_type idx) - { - if (!dw2_expand_marked_cus (per_objfile, idx, file_matcher, - expansion_notify, search_flags, domain, - lang_matcher)) - return false; - return true; - }, per_objfile, lang_matcher); + m_results.push_back (std::move (map->result)); + m_results[0].done_reading (complaint_handler.release ()); - return result; -} + /* No longer needed. */ + map.reset (); -quick_symbol_functions_up -mapped_gdb_index::make_quick_functions () const -{ - return quick_symbol_functions_up (new dwarf2_gdb_index); + done_reading (); + + bfd_thread_cleanup (); } /* A helper function that reads the .gdb_index from BUFFER and fills @@ -1210,11 +431,9 @@ read_gdb_index_from_buffer (const char *filename, /* Version check. */ offset_type version = metadata[0]; - /* Versions earlier than 3 emitted every copy of a psymbol. This - causes the index to behave very poorly for certain requests. Version 3 - contained incomplete addrmap. So, it seems better to just ignore such - indices. */ - if (version < 4) + /* GDB now requires the symbol attributes, which were added in + version 7. */ + if (version < 7) { static int warning_printed = 0; if (!warning_printed) @@ -1225,30 +444,6 @@ read_gdb_index_from_buffer (const char *filename, } return 0; } - /* Index version 4 uses a different hash function than index version - 5 and later. - - Versions earlier than 6 did not emit psymbols for inlined - functions. Using these files will cause GDB not to be able to - set breakpoints on inlined functions by name, so we ignore these - indices unless the user has done - "set use-deprecated-index-sections on". */ - if (version < 6 && !deprecated_ok) - { - static int warning_printed = 0; - if (!warning_printed) - { - warning (_("\ -Skipping deprecated .gdb_index section in %s.\n\ -Do \"%ps\" before the file is read\n\ -to use the section anyway."), - filename, - styled_string (command_style.style (), - "set use-deprecated-index-sections on")); - 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. @@ -1395,13 +590,13 @@ create_signatured_type_table_from_gdb_index per_bfd->signatured_types = std::move (sig_types_hash); } -/* Read the address map data from the mapped GDB index. */ +/* Read the address map data from the mapped GDB index. Return true if no + errors were found, otherwise return false. */ -static void +static bool create_addrmap_from_gdb_index (dwarf2_per_objfile *per_objfile, mapped_gdb_index *index) { - dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; const gdb_byte *iter, *end; addrmap_mutable mutable_map; @@ -1419,40 +614,48 @@ create_addrmap_from_gdb_index (dwarf2_per_objfile *per_objfile, cu_index = extract_unsigned_integer (iter, 4, BFD_ENDIAN_LITTLE); iter += 4; - if (lo > hi) + if (lo >= hi) { - complaint (_(".gdb_index address table has invalid range (%s - %s)"), - hex_string (lo), hex_string (hi)); - continue; + 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 ()) { - complaint (_(".gdb_index address table has invalid CU number %u"), - (unsigned) cu_index); - continue; + warning (_(".gdb_index address table has invalid CU number %u," + " ignoring .gdb_index"), + (unsigned) cu_index); + return false; } - mutable_map.set_empty (lo, hi - 1, index->units[cu_index]); + 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->index_addrmap - = new (&per_bfd->obstack) addrmap_fixed (&per_bfd->obstack, &mutable_map); -} + index->result.set_addrmap (std::move (mutable_map)); -/* Sets the name and language of the main function from the shortcut table. */ + return true; +} -static void -set_main_name_from_gdb_index (dwarf2_per_objfile *per_objfile, - mapped_gdb_index *index) +void +mapped_gdb_index::set_main_name (dwarf2_per_objfile *per_objfile) { const auto expected_size = 2 * sizeof (offset_type); - if (index->shortcut_table.size () < expected_size) + 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 = index->shortcut_table.data (); + 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) { @@ -1468,13 +671,11 @@ set_main_name_from_gdb_index (dwarf2_per_objfile *per_objfile, } ptr += 4; - const auto lang = dwarf_lang_to_enum_language (dw_lang); + main_lang = dwarf_lang_to_enum_language (dw_lang); const auto name_offset = extract_unsigned_integer (ptr, sizeof (offset_type), BFD_ENDIAN_LITTLE); - const auto name = (const char *) (index->constant_pool.data () + name_offset); - - set_objfile_main_name (per_objfile->objfile, name, (enum language) lang); + main_name = (const char *) (this->constant_pool.data () + name_offset); } /* See read-gdb-index.h. */ @@ -1489,6 +690,7 @@ dwarf2_read_gdb_index 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); @@ -1544,10 +746,7 @@ dwarf2_read_gdb_index an index. */ if (per_bfd->infos.size () > 1 || per_bfd->types.size () > 1) - { - per_bfd->all_units.clear (); - return false; - } + return false; dwarf2_section_info *section = (per_bfd->types.size () == 1 @@ -1561,11 +760,19 @@ dwarf2_read_gdb_index finalize_all_units (per_bfd); - create_addrmap_from_gdb_index (per_objfile, map.get ()); + if (!create_addrmap_from_gdb_index (per_objfile, map.get ())) + return false; - set_main_name_from_gdb_index (per_objfile, map.get ()); + map->set_main_name (per_objfile); - per_bfd->index_table = std::move (map); + 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; } @@ -1583,9 +790,4 @@ Warning: This option must be enabled before gdb reads the file."), NULL, NULL, &setlist, &showlist); - -#if GDB_SELF_TEST - selftests::register_test ("dw2_expand_symtabs_matching", - selftests::dw2_expand_symtabs_matching::run_test); -#endif } diff --git a/gdb/dwarf2/read-gdb-index.h b/gdb/dwarf2/read-gdb-index.h index 5107d63..c8f1fd0 100644 --- a/gdb/dwarf2/read-gdb-index.h +++ b/gdb/dwarf2/read-gdb-index.h @@ -27,6 +27,20 @@ struct dwarf2_per_objfile; struct dwz_file; struct objfile; +/* .gdb_index doesn't distinguish between the various "other" symbols + -- but the symbol search machinery really wants to. For example, + an imported decl is "other" but is really a namespace and thus in + TYPE_DOMAIN; whereas a Fortran module is also "other" but is in the + MODULE_DOMAIN. We use this value internally to represent the + "other" case so that matching can work. The exact value does not + matter, all that matters here is that it won't overlap with any + symbol that gdb might create. */ +#define DW_TAG_GDB_INDEX_OTHER 0xffff + +/* Similarly, .gdb_index can't distinguish between the type and struct + domains. This is a special tag that inhabits both. */ +#define DW_TAG_GDB_INDEX_TYPE 0xfffe + /* Callback types for dwarf2_read_gdb_index. */ typedef gdb::function_view diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index ec8d376..8019179 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -38,6 +38,7 @@ #include "dwarf2/index-cache.h" #include "dwarf2/leb.h" #include "dwarf2/line-header.h" +#include "dwarf2/line-program.h" #include "dwarf2/dwz.h" #include "dwarf2/macro.h" #include "dwarf2/die.h" @@ -147,7 +148,7 @@ static const registry<bfd>::key<dwarf2_per_bfd> dwarf2_per_bfd_bfd_data_key; static const registry<objfile>::key<dwarf2_per_bfd> dwarf2_per_bfd_objfile_data_key; -/* The "aclass" indices for various kinds of computed DWARF symbols. */ +/* The "loc_class" indices for various kinds of computed DWARF symbols. */ static int dwarf2_locexpr_index; static int dwarf2_loclist_index; @@ -787,13 +788,6 @@ static line_header_up dwarf_decode_line_header (sect_offset sect_off, struct dwarf2_cu *cu, const char *comp_dir); -static void dwarf_decode_lines (struct line_header *, - struct dwarf2_cu *, - unrelocated_addr, int decode_mapping); - -static void dwarf2_start_subfile (dwarf2_cu *cu, const file_entry &fe, - const line_header &lh); - static struct symbol *new_symbol (struct die_info *, struct type *, struct dwarf2_cu *, struct symbol * = NULL); @@ -857,6 +851,11 @@ static struct dwarf2_section_info *cu_debug_loc_section (struct dwarf2_cu *cu); static struct dwarf2_section_info *cu_debug_rnglists_section (struct dwarf2_cu *cu, dwarf_tag tag); +static void dw_search_file_matcher + (dwarf2_per_objfile *per_objfile, + auto_bool_vector &cus_to_skip, + search_symtabs_file_matcher file_matcher); + static void get_scope_pc_bounds (struct die_info *, unrelocated_addr *, unrelocated_addr *, struct dwarf2_cu *); @@ -987,9 +986,6 @@ static void queue_comp_unit (dwarf2_per_cu *per_cu, static void process_queue (dwarf2_per_objfile *per_objfile); -static bool is_ada_import_or_export (dwarf2_cu *cu, const char *name, - const char *linkagename); - /* Class, the destructor of which frees all allocated queue entries. This will only have work to do if an error was thrown while processing the dwarf. If no error was thrown then the queue entries should have all @@ -1043,12 +1039,6 @@ dwarf2_per_cu_deleter::operator() (dwarf2_per_cu *data) delete data; } -static const char *compute_include_file_name - (const struct line_header *lh, - const file_entry &fe, - const file_and_directory &cu_info, - std::string &name_holder); - static struct dwo_unit *lookup_dwo_unit_in_dwp (dwarf2_per_bfd *per_bfd, struct dwp_file *dwp_file, const char *comp_dir, ULONGEST signature, int is_debug_types); @@ -1063,19 +1053,6 @@ static void process_cu_includes (dwarf2_per_objfile *per_objfile); /* Various complaints about symbol reading that don't abort the process. */ static void -dwarf2_debug_line_missing_file_complaint (void) -{ - complaint (_(".debug_line section has line data without a file")); -} - -static void -dwarf2_debug_line_missing_end_sequence_complaint (void) -{ - complaint (_(".debug_line section has line " - "program sequence without an end")); -} - -static void dwarf2_complex_location_expr_complaint (void) { complaint (_("location expression too complex")); @@ -1553,16 +1530,37 @@ struct readnow_functions : public dwarf2_base_index_functions { } - bool expand_symtabs_matching - (struct objfile *objfile, - expand_symtabs_file_matcher file_matcher, - const lookup_name_info *lookup_name, - expand_symtabs_symbol_matcher symbol_matcher, - expand_symtabs_expansion_listener expansion_notify, - block_search_flags search_flags, - domain_search_flags domain, - expand_symtabs_lang_matcher lang_matcher) override + bool search (struct objfile *objfile, + search_symtabs_file_matcher file_matcher, + const lookup_name_info *lookup_name, + search_symtabs_symbol_matcher symbol_matcher, + search_symtabs_expansion_listener listener, + block_search_flags search_flags, + domain_search_flags domain, + search_symtabs_lang_matcher lang_matcher) override { + dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); + auto_bool_vector cus_to_skip; + dw_search_file_matcher (per_objfile, cus_to_skip, file_matcher); + + for (const auto &per_cu : per_objfile->per_bfd->all_units) + { + QUIT; + + /* Skip various types of unit that should not be searched + directly: partial units and dummy units. */ + if (/* Note that we request the non-strict unit type here. If + there was an error while reading, like in + dw-form-strx-out-of-bounds.exp, then the unit type may + not be set. */ + per_cu->unit_type (false) == DW_UT_partial + || per_cu->unit_type (false) == 0 + || per_objfile->get_symtab (per_cu.get ()) == nullptr) + continue; + if (!dw2_search_one (per_cu.get (), per_objfile, cus_to_skip, + file_matcher, listener, lang_matcher)) + return false; + } return true; } }; @@ -1711,6 +1709,75 @@ dwarf2_per_bfd::allocate_signatured_type (dwarf2_section_info *section, return result; } +/* Subroutine of dw2_get_file_names_reader to simplify it. + Return the file name for the given file_entry. + CU_INFO describes the CU's DW_AT_name and DW_AT_comp_dir. + If space for the result is malloc'd, *NAME_HOLDER will be set. + Returns NULL if FILE_INDEX should be ignored, i.e., it is + equivalent to CU_INFO. */ + +static const char * +compute_include_file_name (const struct line_header *lh, const file_entry &fe, + const file_and_directory &cu_info, + std::string &name_holder) +{ + const char *include_name = fe.name; + const char *include_name_to_compare = include_name; + + const char *dir_name = fe.include_dir (lh); + + std::string hold_compare; + if (!IS_ABSOLUTE_PATH (include_name) + && (dir_name != nullptr || cu_info.get_comp_dir () != nullptr)) + { + /* Avoid creating a duplicate name for CU_INFO. + We do this by comparing INCLUDE_NAME and CU_INFO. + Before we do the comparison, however, we need to account + for DIR_NAME and COMP_DIR. + First prepend dir_name (if non-NULL). If we still don't + have an absolute path prepend comp_dir (if non-NULL). + However, the directory we record in the include-file's + psymtab does not contain COMP_DIR (to match the + corresponding symtab(s)). + + Example: + + bash$ cd /tmp + bash$ gcc -g ./hello.c + include_name = "hello.c" + dir_name = "." + DW_AT_comp_dir = comp_dir = "/tmp" + DW_AT_name = "./hello.c" + + */ + + if (dir_name != NULL) + { + name_holder = path_join (dir_name, include_name); + include_name = name_holder.c_str (); + include_name_to_compare = include_name; + } + if (!IS_ABSOLUTE_PATH (include_name) + && cu_info.get_comp_dir () != nullptr) + { + hold_compare = path_join (cu_info.get_comp_dir (), include_name); + include_name_to_compare = hold_compare.c_str (); + } + } + + std::string copied_name; + const char *cu_filename = cu_info.get_name (); + if (!IS_ABSOLUTE_PATH (cu_filename) && cu_info.get_comp_dir () != nullptr) + { + copied_name = path_join (cu_info.get_comp_dir (), cu_filename); + cu_filename = copied_name.c_str (); + } + + if (FILENAME_CMP (include_name_to_compare, cu_filename) == 0) + return nullptr; + return include_name; +} + /* die_reader_func for dw2_get_file_names. */ static void @@ -1930,14 +1997,16 @@ dwarf2_base_index_functions::expand_all_symtabs (struct objfile *objfile) /* See read.h. */ bool -dw2_expand_symtabs_matching_one +dw2_search_one (dwarf2_per_cu *per_cu, dwarf2_per_objfile *per_objfile, - expand_symtabs_file_matcher file_matcher, - expand_symtabs_expansion_listener expansion_notify, - expand_symtabs_lang_matcher lang_matcher) + auto_bool_vector &cus_to_skip, + search_symtabs_file_matcher file_matcher, + search_symtabs_expansion_listener listener, + search_symtabs_lang_matcher lang_matcher) { - if (file_matcher != nullptr && !per_cu->mark) + /* Already visited, or intentionally skipped. */ + if (cus_to_skip.is_set (per_cu->index)) return true; if (lang_matcher != nullptr) @@ -1949,22 +2018,27 @@ dw2_expand_symtabs_matching_one return true; } - bool symtab_was_null = !per_objfile->symtab_set_p (per_cu); compunit_symtab *symtab = dw2_instantiate_symtab (per_cu, per_objfile, false); gdb_assert (symtab != nullptr); - if (expansion_notify != NULL && symtab_was_null) - return expansion_notify (symtab); + if (listener != nullptr) + { + cus_to_skip.set (per_cu->index, true); + return listener (symtab); + } return true; } -/* See read.h. */ +/* If FILE_MATCHER is non-NULL, update CUS_TO_SKIP as appropriate + based on FILE_MATCHER. */ -void -dw_expand_symtabs_matching_file_matcher - (dwarf2_per_objfile *per_objfile, expand_symtabs_file_matcher file_matcher) +static void +dw_search_file_matcher + (dwarf2_per_objfile *per_objfile, + auto_bool_vector &cus_to_skip, + search_symtabs_file_matcher file_matcher) { if (file_matcher == NULL) return; @@ -1980,54 +2054,50 @@ dw_expand_symtabs_matching_file_matcher QUIT; if (per_cu->is_debug_types) - continue; - per_cu->mark = 0; - - /* We only need to look at symtabs not already expanded. */ - if (per_objfile->symtab_set_p (per_cu.get ())) - continue; + { + cus_to_skip.set (per_cu->index, true); + continue; + } if (per_cu->fnd != nullptr) { file_and_directory *fnd = per_cu->fnd.get (); if (file_matcher (fnd->get_name (), false)) - { - per_cu->mark = 1; - continue; - } + continue; /* Before we invoke realpath, which can get expensive when many files are involved, do a quick comparison of the basenames. */ if ((basenames_may_differ || file_matcher (lbasename (fnd->get_name ()), true)) && file_matcher (fnd->get_fullname (), false)) - { - per_cu->mark = 1; - continue; - } + continue; } quick_file_names *file_data = dw2_get_file_names (per_cu.get (), per_objfile); if (file_data == NULL) - continue; + { + cus_to_skip.set (per_cu->index, true); + continue; + } if (visited_not_found.contains (file_data)) - continue; - else if (visited_found.contains (file_data)) { - per_cu->mark = 1; + cus_to_skip.set (per_cu->index, true); continue; } + else if (visited_found.contains (file_data)) + continue; + bool matched = false; for (int j = 0; j < file_data->num_file_names; ++j) { const char *this_real_name; if (file_matcher (file_data->file_names[j], false)) { - per_cu->mark = 1; + matched = true; break; } @@ -2041,15 +2111,18 @@ dw_expand_symtabs_matching_file_matcher this_real_name = dw2_get_real_path (per_objfile, file_data, j); if (file_matcher (this_real_name, false)) { - per_cu->mark = 1; + matched = true; break; } } - if (per_cu->mark) + if (matched) visited_found.insert (file_data); else - visited_not_found.insert (file_data); + { + cus_to_skip.set (per_cu->index, true); + visited_not_found.insert (file_data); + } } } @@ -3679,6 +3752,10 @@ read_comp_units_from_section (dwarf2_per_objfile *per_objfile, void finalize_all_units (dwarf2_per_bfd *per_bfd) { + /* Sanity check. */ + gdb_assert (per_bfd->all_units.size () + == per_bfd->num_comp_units + per_bfd->num_type_units); + /* 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 (), @@ -3694,6 +3771,7 @@ void create_all_units (dwarf2_per_objfile *per_objfile) { gdb_assert (per_objfile->per_bfd->all_units.empty ()); + scoped_remove_all_units remove_all_units (*per_objfile->per_bfd); signatured_type_set sig_types; @@ -3714,8 +3792,6 @@ create_all_units (dwarf2_per_objfile *per_objfile) if (!dwz->types.empty ()) { - per_objfile->per_bfd->all_units.clear (); - /* See enhancement PR symtab/30838. */ error (_(DWARF_ERROR_PREFIX ".debug_types section not supported in dwz file")); @@ -3725,6 +3801,7 @@ create_all_units (dwarf2_per_objfile *per_objfile) per_objfile->per_bfd->signatured_types = std::move (sig_types); finalize_all_units (per_objfile->per_bfd); + remove_all_units.disable (); } /* Return the initial uleb128 in the die at INFO_PTR. */ @@ -4257,7 +4334,7 @@ fixup_go_packaging (struct dwarf2_cu *cu) struct symbol *sym = list->symbol[i]; if (sym->language () == language_go - && sym->aclass () == LOC_BLOCK) + && sym->loc_class () == LOC_BLOCK) { gdb::unique_xmalloc_ptr<char> this_package_name = go_symbol_package_name (sym); @@ -4294,7 +4371,7 @@ fixup_go_packaging (struct dwarf2_cu *cu) sym->set_language (language_go, &objfile->objfile_obstack); sym->compute_and_set_names (saved_package_name, false, objfile->per_bfd); sym->set_domain (TYPE_DOMAIN); - sym->set_aclass_index (LOC_TYPEDEF); + sym->set_loc_class_index (LOC_TYPEDEF); sym->set_type (type); add_symbol_to_list (sym, cu->get_builder ()->get_global_symbols ()); @@ -4504,9 +4581,9 @@ quirk_rust_enum (struct type *type, struct objfile *objfile) else { struct type *disr_type = nullptr; - for (int i = 0; i < type->num_fields (); ++i) + for (const auto &field : type->fields ()) { - disr_type = type->field (i).type (); + disr_type = field.type (); if (disr_type->code () != TYPE_CODE_STRUCT) { @@ -4545,7 +4622,7 @@ quirk_rust_enum (struct type *type, struct objfile *objfile) field *new_fields = (struct field *) TYPE_ZALLOC (type, ((type->num_fields () + 1) * sizeof (struct field))); - memcpy (new_fields + 1, type->fields (), + memcpy (new_fields + 1, type->fields ().data (), type->num_fields () * sizeof (struct field)); type->set_fields (new_fields); type->set_num_fields (type->num_fields () + 1); @@ -4559,13 +4636,12 @@ quirk_rust_enum (struct type *type, struct objfile *objfile) variant name. For convenience we build a map here. */ struct type *enum_type = disr_field->type (); gdb::unordered_map<std::string_view, ULONGEST> discriminant_map; - for (int i = 0; i < enum_type->num_fields (); ++i) + for (const auto &field : enum_type->fields ()) { - if (enum_type->field (i).loc_kind () == FIELD_LOC_KIND_ENUMVAL) + if (field.loc_kind () == FIELD_LOC_KIND_ENUMVAL) { - const char *name - = rust_last_path_segment (enum_type->field (i).name ()); - discriminant_map[name] = enum_type->field (i).loc_enumval (); + const char *name = rust_last_path_segment (field.name ()); + discriminant_map[name] = field.loc_enumval (); } } @@ -4601,7 +4677,7 @@ quirk_rust_enum (struct type *type, struct objfile *objfile) if (sub_type->num_fields () > 0) { sub_type->set_num_fields (sub_type->num_fields () - 1); - sub_type->set_fields (sub_type->fields () + 1); + sub_type->set_fields (sub_type->fields ().data () + 1); } type->field (i).set_name (variant_name); sub_type->set_name @@ -5681,7 +5757,7 @@ read_alias (struct die_info *die, struct dwarf2_cu *cu) type = die_type (d, imported_cu); struct symbol *sym = new_symbol (die, type, cu); attr = dwarf2_attr (d, DW_AT_location, imported_cu); - sym->set_aclass_index (LOC_UNRESOLVED); + sym->set_loc_class_index (LOC_UNRESOLVED); if (attr != nullptr) var_decode_location (attr, sym, cu); return true; @@ -6048,7 +6124,7 @@ read_file_scope (struct die_info *die, struct dwarf2_cu *cu) sect_offset line_offset = (sect_offset) attr->as_unsigned (); line_header_up lh = dwarf_decode_line_header (line_offset, cu, fnd.get_comp_dir ()); - if (lh->version == 5 && lh->is_valid_file_index (1)) + if (lh->version == 5 && lh->include_dir_at (1) != nullptr) { std::string dir = lh->include_dir_at (1); fnd.set_comp_dir (std::move (dir)); @@ -10629,7 +10705,6 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, smash_to_method_type (fnp->type, type, this_type->target_type (), this_type->fields (), - this_type->num_fields (), this_type->has_varargs ()); /* Handle static member functions. @@ -10851,8 +10926,7 @@ quirk_gcc_member_function_pointer (struct type *type, struct objfile *objfile) self_type = pfn_type->field (0).type ()->target_type (); new_type = type_allocator (type).new_type (); smash_to_method_type (new_type, self_type, pfn_type->target_type (), - pfn_type->fields (), pfn_type->num_fields (), - pfn_type->has_varargs ()); + pfn_type->fields (), pfn_type->has_varargs ()); smash_to_methodptr_type (type, new_type); } @@ -12411,7 +12485,7 @@ mark_common_block_symbol_computed (struct symbol *sym, gdb_assert (ptr - baton->data == baton->size); SYMBOL_LOCATION_BATON (sym) = baton; - sym->set_aclass_index (dwarf2_locexpr_index); + sym->set_loc_class_index (dwarf2_locexpr_index); } /* Create appropriate locally-scoped variables for all the @@ -12773,8 +12847,7 @@ read_tag_ptr_to_member_type (struct die_info *die, struct dwarf2_cu *cu) = type_allocator (cu->per_objfile->objfile, cu->lang ()).new_type (); smash_to_method_type (new_type, domain, to_type->target_type (), - to_type->fields (), to_type->num_fields (), - to_type->has_varargs ()); + to_type->fields (), to_type->has_varargs ()); type = lookup_methodptr_type (new_type); } else @@ -13396,7 +13469,7 @@ ada_get_gnat_encoded_number (const char *encoding, int &k, gdb_mpz *result) { /* The next character should be an underscore ('_') followed by a digit. */ - if (encoding[k] != '_' || !isdigit (encoding[k + 1])) + if (encoding[k] != '_' || !c_isdigit (encoding[k + 1])) return false; /* Skip the underscore. */ @@ -13404,7 +13477,7 @@ ada_get_gnat_encoded_number (const char *encoding, int &k, gdb_mpz *result) int start = k; /* Determine the number of digits for our number. */ - while (isdigit (encoding[k])) + while (c_isdigit (encoding[k])) k++; if (k == start) return false; @@ -14520,21 +14593,22 @@ cooked_index_functions::find_compunit_symtab_by_address } bool -cooked_index_functions::expand_symtabs_matching +cooked_index_functions::search (objfile *objfile, - expand_symtabs_file_matcher file_matcher, + search_symtabs_file_matcher file_matcher, const lookup_name_info *lookup_name, - expand_symtabs_symbol_matcher symbol_matcher, - expand_symtabs_expansion_listener expansion_notify, + search_symtabs_symbol_matcher symbol_matcher, + search_symtabs_expansion_listener listener, block_search_flags search_flags, domain_search_flags domain, - expand_symtabs_lang_matcher lang_matcher) + search_symtabs_lang_matcher lang_matcher) { dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile); cooked_index *table = wait (objfile, true); - dw_expand_symtabs_matching_file_matcher (per_objfile, file_matcher); + auto_bool_vector cus_to_skip; + dw_search_file_matcher (per_objfile, cus_to_skip, file_matcher); /* This invariant is documented in quick-functions.h. */ gdb_assert (lookup_name != nullptr || symbol_matcher == nullptr); @@ -14544,10 +14618,8 @@ cooked_index_functions::expand_symtabs_matching { QUIT; - if (!dw2_expand_symtabs_matching_one (per_cu, per_objfile, - file_matcher, - expansion_notify, - lang_matcher)) + if (!dw2_search_one (per_cu, per_objfile, cus_to_skip, file_matcher, + listener, lang_matcher)) return false; } return true; @@ -14622,13 +14694,8 @@ cooked_index_functions::expand_symtabs_matching { QUIT; - /* No need to consider symbols from expanded CUs. */ - if (per_objfile->symtab_set_p (entry->per_cu)) - continue; - - /* If file-matching was done, we don't need to consider - symbols from unmarked CUs. */ - if (file_matcher != nullptr && !entry->per_cu->mark) + /* We don't need to consider symbols from some CUs. */ + if (cus_to_skip.is_set (entry->per_cu->index)) continue; /* See if the symbol matches the type filter. */ @@ -14645,13 +14712,26 @@ cooked_index_functions::expand_symtabs_matching continue; } + /* This is a bit of a hack to support .gdb_index. Since + .gdb_index does not record languages, and since we want + to know the language to avoid excessive CU expansion due + to false matches, if we see a symbol with an unknown + language we find the CU's language. Only the .gdb_index + reader creates such symbols. */ + enum language entry_lang = entry->lang; + if (entry_lang == language_unknown) + { + entry->per_cu->ensure_lang (per_objfile); + entry_lang = entry->per_cu->lang (); + } + /* We've found the base name of the symbol; now walk its parentage chain, ensuring that each component matches. */ bool found = true; const cooked_index_entry *parent = entry->get_parent (); - const language_defn *lang_def = language_def (entry->lang); + const language_defn *lang_def = language_def (entry_lang); for (int i = name_vec.size () - 1; i > 0; --i) { /* If we ran out of entries, or if this segment doesn't @@ -14661,17 +14741,15 @@ cooked_index_functions::expand_symtabs_matching found = false; break; } - if (parent->lang != language_unknown) + + symbol_name_matcher_ftype *name_matcher + = (lang_def->get_symbol_name_matcher + (segment_lookup_names[i-1])); + if (!name_matcher (parent->canonical, + segment_lookup_names[i-1], nullptr)) { - symbol_name_matcher_ftype *name_matcher - = lang_def->get_symbol_name_matcher - (segment_lookup_names[i-1]); - if (!name_matcher (parent->canonical, - segment_lookup_names[i-1], nullptr)) - { - found = false; - break; - } + found = false; + break; } parent = parent->get_parent (); @@ -14694,27 +14772,23 @@ cooked_index_functions::expand_symtabs_matching seems like the loop above could just examine every element of the name, avoiding the need to check here; but this is hard. See PR symtab/32733. */ - if (symbol_matcher != nullptr || entry->lang != language_unknown) + auto_obstack temp_storage; + const char *full_name = entry->full_name (&temp_storage, + FOR_ADA_LINKAGE_NAME); + if (symbol_matcher == nullptr) { - auto_obstack temp_storage; - const char *full_name = entry->full_name (&temp_storage, - FOR_ADA_LINKAGE_NAME); - if (symbol_matcher == nullptr) - { - symbol_name_matcher_ftype *name_matcher - = (lang_def->get_symbol_name_matcher - (lookup_name_without_params)); - if (!name_matcher (full_name, lookup_name_without_params, - nullptr)) - continue; - } - else if (!symbol_matcher (full_name)) + symbol_name_matcher_ftype *name_matcher + = (lang_def->get_symbol_name_matcher + (lookup_name_without_params)); + if (!name_matcher (full_name, lookup_name_without_params, + nullptr)) continue; } + else if (!symbol_matcher (full_name)) + continue; - if (!dw2_expand_symtabs_matching_one (entry->per_cu, per_objfile, - file_matcher, - expansion_notify, nullptr)) + if (!dw2_search_one (entry->per_cu, per_objfile, cus_to_skip, + file_matcher, listener, nullptr)) return false; } } @@ -15759,9 +15833,9 @@ die_specification (struct die_info *die, struct dwarf2_cu **spec_cu) return follow_die_ref (die, spec_attr, spec_cu); } -/* A convenience function to find the proper .debug_line section for a CU. */ +/* See dwarf2/read.h. */ -static struct dwarf2_section_info * +struct dwarf2_section_info * get_debug_line_section (struct dwarf2_cu *cu) { struct dwarf2_section_info *section; @@ -15812,808 +15886,9 @@ dwarf_decode_line_header (sect_offset sect_off, struct dwarf2_cu *cu, comp_dir); } -/* Subroutine of dwarf_decode_lines to simplify it. - Return the file name for the given file_entry. - CU_INFO describes the CU's DW_AT_name and DW_AT_comp_dir. - If space for the result is malloc'd, *NAME_HOLDER will be set. - Returns NULL if FILE_INDEX should be ignored, i.e., it is - equivalent to CU_INFO. */ - -static const char * -compute_include_file_name (const struct line_header *lh, const file_entry &fe, - const file_and_directory &cu_info, - std::string &name_holder) -{ - const char *include_name = fe.name; - const char *include_name_to_compare = include_name; - - const char *dir_name = fe.include_dir (lh); - - std::string hold_compare; - if (!IS_ABSOLUTE_PATH (include_name) - && (dir_name != nullptr || cu_info.get_comp_dir () != nullptr)) - { - /* Avoid creating a duplicate name for CU_INFO. - We do this by comparing INCLUDE_NAME and CU_INFO. - Before we do the comparison, however, we need to account - for DIR_NAME and COMP_DIR. - First prepend dir_name (if non-NULL). If we still don't - have an absolute path prepend comp_dir (if non-NULL). - However, the directory we record in the include-file's - psymtab does not contain COMP_DIR (to match the - corresponding symtab(s)). - - Example: - - bash$ cd /tmp - bash$ gcc -g ./hello.c - include_name = "hello.c" - dir_name = "." - DW_AT_comp_dir = comp_dir = "/tmp" - DW_AT_name = "./hello.c" - - */ - - if (dir_name != NULL) - { - name_holder = path_join (dir_name, include_name); - include_name = name_holder.c_str (); - include_name_to_compare = include_name; - } - if (!IS_ABSOLUTE_PATH (include_name) - && cu_info.get_comp_dir () != nullptr) - { - hold_compare = path_join (cu_info.get_comp_dir (), include_name); - include_name_to_compare = hold_compare.c_str (); - } - } - - std::string copied_name; - const char *cu_filename = cu_info.get_name (); - if (!IS_ABSOLUTE_PATH (cu_filename) && cu_info.get_comp_dir () != nullptr) - { - copied_name = path_join (cu_info.get_comp_dir (), cu_filename); - cu_filename = copied_name.c_str (); - } - - if (FILENAME_CMP (include_name_to_compare, cu_filename) == 0) - return nullptr; - return include_name; -} - -/* State machine to track the state of the line number program. */ - -class lnp_state_machine -{ -public: - /* Initialize a machine state for the start of a line number - program. */ - lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch, line_header *lh); - - file_entry *current_file () - { - /* lh->file_names is 0-based, but the file name numbers in the - statement program are 1-based. */ - return m_line_header->file_name_at (m_file); - } - - /* Record the line in the state machine. END_SEQUENCE is true if - we're processing the end of a sequence. */ - void record_line (bool end_sequence); - - /* Check ADDRESS is -1, -2, or zero and less than UNRELOCATED_LOWPC, and if - true nop-out rest of the lines in this sequence. */ - void check_line_address (struct dwarf2_cu *cu, - const gdb_byte *line_ptr, - unrelocated_addr unrelocated_lowpc, - unrelocated_addr address); - - void handle_set_discriminator (unsigned int discriminator) - { - m_discriminator = discriminator; - m_line_has_non_zero_discriminator |= discriminator != 0; - } - - /* Handle DW_LNE_set_address. */ - void handle_set_address (unrelocated_addr address) - { - m_op_index = 0; - m_address - = (unrelocated_addr) gdbarch_adjust_dwarf2_line (m_gdbarch, - (CORE_ADDR) address, - false); - } - - /* Handle DW_LNS_advance_pc. */ - void handle_advance_pc (CORE_ADDR adjust); - - /* Handle a special opcode. */ - void handle_special_opcode (unsigned char op_code); - - /* Handle DW_LNS_advance_line. */ - void handle_advance_line (int line_delta) - { - advance_line (line_delta); - } - - /* Handle DW_LNS_set_file. */ - void handle_set_file (file_name_index file); - - /* Handle DW_LNS_negate_stmt. */ - void handle_negate_stmt () - { - m_flags ^= LEF_IS_STMT; - } - - /* Handle DW_LNS_const_add_pc. */ - void handle_const_add_pc (); - - /* Handle DW_LNS_fixed_advance_pc. */ - void handle_fixed_advance_pc (CORE_ADDR addr_adj) - { - addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); - m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); - m_op_index = 0; - } - - /* Handle DW_LNS_copy. */ - void handle_copy () - { - record_line (false); - m_discriminator = 0; - m_flags &= ~LEF_PROLOGUE_END; - m_flags &= ~LEF_EPILOGUE_BEGIN; - } - - /* Handle DW_LNE_end_sequence. */ - void handle_end_sequence () - { - m_currently_recording_lines = true; - } - - /* Handle DW_LNS_set_prologue_end. */ - void handle_set_prologue_end () - { - m_flags |= LEF_PROLOGUE_END; - } - - void handle_set_epilogue_begin () - { - m_flags |= LEF_EPILOGUE_BEGIN; - } - -private: - /* Advance the line by LINE_DELTA. */ - void advance_line (int line_delta) - { - m_line += line_delta; - - if (line_delta != 0) - m_line_has_non_zero_discriminator = m_discriminator != 0; - } - - struct dwarf2_cu *m_cu; - - gdbarch *m_gdbarch; - - /* The line number header. */ - line_header *m_line_header; - - /* These are part of the standard DWARF line number state machine, - and initialized according to the DWARF spec. */ - - unsigned char m_op_index = 0; - /* The line table index of the current file. */ - file_name_index m_file = 1; - unsigned int m_line = 1; - - /* These are initialized in the constructor. */ - - unrelocated_addr m_address; - linetable_entry_flags m_flags; - unsigned int m_discriminator = 0; - - /* Additional bits of state we need to track. */ - - /* The last file a line number was recorded for. */ - struct subfile *m_last_subfile = NULL; - - /* The address of the last line entry. */ - unrelocated_addr m_last_address; - - /* Set to true when a previous line at the same address (using - m_last_address) had LEF_IS_STMT set in m_flags. This is reset to false - when a line entry at a new address (m_address different to - m_last_address) is processed. */ - bool m_stmt_at_address = false; - - /* When true, record the lines we decode. */ - bool m_currently_recording_lines = true; - - /* The last line number that was recorded, used to coalesce - consecutive entries for the same line. This can happen, for - example, when discriminators are present. PR 17276. */ - unsigned int m_last_line = 0; - bool m_line_has_non_zero_discriminator = false; -}; - -void -lnp_state_machine::handle_advance_pc (CORE_ADDR adjust) -{ - CORE_ADDR addr_adj = (((m_op_index + adjust) - / m_line_header->maximum_ops_per_instruction) - * m_line_header->minimum_instruction_length); - addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); - m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); - m_op_index = ((m_op_index + adjust) - % m_line_header->maximum_ops_per_instruction); -} - -void -lnp_state_machine::handle_special_opcode (unsigned char op_code) -{ - unsigned char adj_opcode = op_code - m_line_header->opcode_base; - unsigned char adj_opcode_d = adj_opcode / m_line_header->line_range; - unsigned char adj_opcode_r = adj_opcode % m_line_header->line_range; - CORE_ADDR addr_adj = (((m_op_index + adj_opcode_d) - / m_line_header->maximum_ops_per_instruction) - * m_line_header->minimum_instruction_length); - addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); - m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); - m_op_index = ((m_op_index + adj_opcode_d) - % m_line_header->maximum_ops_per_instruction); - - int line_delta = m_line_header->line_base + adj_opcode_r; - advance_line (line_delta); - record_line (false); - m_discriminator = 0; - m_flags &= ~LEF_PROLOGUE_END; - m_flags &= ~LEF_EPILOGUE_BEGIN; -} - -void -lnp_state_machine::handle_set_file (file_name_index file) -{ - m_file = file; - - const file_entry *fe = current_file (); - if (fe == NULL) - dwarf2_debug_line_missing_file_complaint (); - else - { - m_line_has_non_zero_discriminator = m_discriminator != 0; - dwarf2_start_subfile (m_cu, *fe, *m_line_header); - } -} - -void -lnp_state_machine::handle_const_add_pc () -{ - CORE_ADDR adjust - = (255 - m_line_header->opcode_base) / m_line_header->line_range; - - CORE_ADDR addr_adj - = (((m_op_index + adjust) - / m_line_header->maximum_ops_per_instruction) - * m_line_header->minimum_instruction_length); - - addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); - m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); - m_op_index = ((m_op_index + adjust) - % m_line_header->maximum_ops_per_instruction); -} - -/* Return non-zero if we should add LINE to the line number table. - LINE is the line to add, LAST_LINE is the last line that was added, - LAST_SUBFILE is the subfile for LAST_LINE. - LINE_HAS_NON_ZERO_DISCRIMINATOR is non-zero if LINE has ever - had a non-zero discriminator. - - We have to be careful in the presence of discriminators. - E.g., for this line: - - for (i = 0; i < 100000; i++); - - clang can emit four line number entries for that one line, - each with a different discriminator. - See gdb.dwarf2/dw2-single-line-discriminators.exp for an example. - - However, we want gdb to coalesce all four entries into one. - Otherwise the user could stepi into the middle of the line and - gdb would get confused about whether the pc really was in the - middle of the line. - - Things are further complicated by the fact that two consecutive - line number entries for the same line is a heuristic used by gcc - to denote the end of the prologue. So we can't just discard duplicate - entries, we have to be selective about it. The heuristic we use is - that we only collapse consecutive entries for the same line if at least - one of those entries has a non-zero discriminator. PR 17276. - - Note: Addresses in the line number state machine can never go backwards - within one sequence, thus this coalescing is ok. */ - -static int -dwarf_record_line_p (struct dwarf2_cu *cu, - unsigned int line, unsigned int last_line, - int line_has_non_zero_discriminator, - struct subfile *last_subfile) -{ - if (cu->get_builder ()->get_current_subfile () != last_subfile) - return 1; - if (line != last_line) - return 1; - /* Same line for the same file that we've seen already. - As a last check, for pr 17276, only record the line if the line - has never had a non-zero discriminator. */ - if (!line_has_non_zero_discriminator) - return 1; - return 0; -} - -/* Use the CU's builder to record line number LINE beginning at - address ADDRESS in the line table of subfile SUBFILE. */ - -static void -dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile, - unsigned int line, unrelocated_addr address, - linetable_entry_flags flags, - struct dwarf2_cu *cu) -{ - unrelocated_addr addr - = unrelocated_addr (gdbarch_addr_bits_remove (gdbarch, - (CORE_ADDR) address)); - - if (cu != nullptr) - { - if (dwarf_line_debug) - gdb_printf (gdb_stdlog, "Recording line %u, file %s, address %s\n", - line, lbasename (subfile->name.c_str ()), - paddress (gdbarch, (CORE_ADDR) address)); - - cu->get_builder ()->record_line (subfile, line, addr, flags); - } -} - -/* Subroutine of dwarf_decode_lines_1 to simplify it. - Mark the end of a set of line number records. - The arguments are the same as for dwarf_record_line_1. - If SUBFILE is NULL the request is ignored. */ - -static void -dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile, - unrelocated_addr address, struct dwarf2_cu *cu) -{ - if (subfile == NULL) - return; - - if (dwarf_line_debug) - { - gdb_printf (gdb_stdlog, - "Finishing current line, file %s, address %s\n", - lbasename (subfile->name.c_str ()), - paddress (gdbarch, (CORE_ADDR) address)); - } - - dwarf_record_line_1 (gdbarch, subfile, 0, address, LEF_IS_STMT, cu); -} - -void -lnp_state_machine::record_line (bool end_sequence) -{ - if (dwarf_line_debug) - { - gdb_printf (gdb_stdlog, - "Processing actual line %u: file %u," - " address %s, is_stmt %u, prologue_end %u," - " epilogue_begin %u, discrim %u%s\n", - m_line, m_file, - paddress (m_gdbarch, (CORE_ADDR) m_address), - (m_flags & LEF_IS_STMT) != 0, - (m_flags & LEF_PROLOGUE_END) != 0, - (m_flags & LEF_EPILOGUE_BEGIN) != 0, - m_discriminator, - (end_sequence ? "\t(end sequence)" : "")); - } - - file_entry *fe = current_file (); - - if (fe == NULL) - dwarf2_debug_line_missing_file_complaint (); - /* For now we ignore lines not starting on an instruction boundary. - But not when processing end_sequence for compatibility with the - previous version of the code. */ - else if (m_op_index == 0 || end_sequence) - { - /* When we switch files we insert an end maker in the first file, - switch to the second file and add a new line entry. The - problem is that the end marker inserted in the first file will - discard any previous line entries at the same address. If the - line entries in the first file are marked as is-stmt, while - the new line in the second file is non-stmt, then this means - the end marker will discard is-stmt lines so we can have a - non-stmt line. This means that there are less addresses at - which the user can insert a breakpoint. - - To improve this we track the last address in m_last_address, - and whether we have seen an is-stmt at this address. Then - when switching files, if we have seen a stmt at the current - address, and we are switching to create a non-stmt line, then - discard the new line. */ - bool file_changed - = m_last_subfile != m_cu->get_builder ()->get_current_subfile (); - bool ignore_this_line - = ((file_changed && !end_sequence && m_last_address == m_address - && ((m_flags & LEF_IS_STMT) == 0) - && m_stmt_at_address) - || (!end_sequence && m_line == 0)); - - if ((file_changed && !ignore_this_line) || end_sequence) - { - dwarf_finish_line (m_gdbarch, m_last_subfile, m_address, - m_currently_recording_lines ? m_cu : nullptr); - } - - if (!end_sequence && !ignore_this_line) - { - linetable_entry_flags lte_flags = m_flags; - if (m_cu->producer_is_codewarrior ()) - lte_flags |= LEF_IS_STMT; - - if (dwarf_record_line_p (m_cu, m_line, m_last_line, - m_line_has_non_zero_discriminator, - m_last_subfile)) - { - buildsym_compunit *builder = m_cu->get_builder (); - dwarf_record_line_1 (m_gdbarch, - builder->get_current_subfile (), - m_line, m_address, lte_flags, - m_currently_recording_lines ? m_cu : nullptr); - - m_last_subfile = m_cu->get_builder ()->get_current_subfile (); - m_last_line = m_line; - } - } - } - - /* Track whether we have seen any IS_STMT true at m_address in case we - have multiple line table entries all at m_address. */ - if (m_last_address != m_address) - { - m_stmt_at_address = false; - m_last_address = m_address; - } - m_stmt_at_address |= (m_flags & LEF_IS_STMT) != 0; -} - -lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch, - line_header *lh) - : m_cu (cu), - m_gdbarch (arch), - m_line_header (lh), - /* Call `gdbarch_adjust_dwarf2_line' on the initial 0 address as - if there was a line entry for it so that the backend has a - chance to adjust it and also record it in case it needs it. - This is currently used by MIPS code, - cf. `mips_adjust_dwarf2_line'. */ - m_address ((unrelocated_addr) gdbarch_adjust_dwarf2_line (arch, 0, 0)), - m_flags (lh->default_is_stmt ? LEF_IS_STMT : (linetable_entry_flags) 0), - m_last_address (m_address) -{ -} +/* See dwarf2/read.h. */ void -lnp_state_machine::check_line_address (struct dwarf2_cu *cu, - const gdb_byte *line_ptr, - unrelocated_addr unrelocated_lowpc, - unrelocated_addr address) -{ - /* Linkers resolve a symbolic relocation referencing a GC'd function to 0, - -1 or -2 (-2 is used by certain lld versions, see - https://github.com/llvm/llvm-project/commit/e618ccbf431f6730edb6d1467a127c3a52fd57f7). - If ADDRESS is 0, ignoring the opcode will err if the text section is - located at 0x0. In this case, additionally check that if - ADDRESS < UNRELOCATED_LOWPC. */ - - if ((address == (unrelocated_addr) 0 && address < unrelocated_lowpc) - || address == (unrelocated_addr) -1 - || address == (unrelocated_addr) -2) - { - /* This line table is for a function which has been - GCd by the linker. Ignore it. PR gdb/12528 */ - - struct objfile *objfile = cu->per_objfile->objfile; - long line_offset = line_ptr - get_debug_line_section (cu)->buffer; - - complaint (_(".debug_line address at offset 0x%lx is 0 [in module %s]"), - line_offset, objfile_name (objfile)); - m_currently_recording_lines = false; - /* Note: m_currently_recording_lines is left as false until we see - DW_LNE_end_sequence. */ - } -} - -/* Subroutine of dwarf_decode_lines to simplify it. - Process the line number information in LH. */ - -static void -dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, - unrelocated_addr lowpc) -{ - const gdb_byte *line_ptr, *extended_end; - const gdb_byte *line_end; - unsigned int bytes_read, extended_len; - unsigned char op_code, extended_op; - struct objfile *objfile = cu->per_objfile->objfile; - bfd *abfd = objfile->obfd.get (); - struct gdbarch *gdbarch = objfile->arch (); - - line_ptr = lh->statement_program_start; - line_end = lh->statement_program_end; - - /* Read the statement sequences until there's nothing left. */ - while (line_ptr < line_end) - { - /* The DWARF line number program state machine. Reset the state - machine at the start of each sequence. */ - lnp_state_machine state_machine (cu, gdbarch, lh); - bool end_sequence = false; - - /* Start a subfile for the current file of the state - machine. */ - const file_entry *fe = state_machine.current_file (); - - if (fe != NULL) - dwarf2_start_subfile (cu, *fe, *lh); - - /* Decode the table. */ - while (line_ptr < line_end && !end_sequence) - { - op_code = read_1_byte (abfd, line_ptr); - line_ptr += 1; - - if (op_code >= lh->opcode_base) - { - /* Special opcode. */ - state_machine.handle_special_opcode (op_code); - } - else switch (op_code) - { - case DW_LNS_extended_op: - extended_len = read_unsigned_leb128 (abfd, line_ptr, - &bytes_read); - line_ptr += bytes_read; - extended_end = line_ptr + extended_len; - extended_op = read_1_byte (abfd, line_ptr); - line_ptr += 1; - if (DW_LNE_lo_user <= extended_op - && extended_op <= DW_LNE_hi_user) - { - /* Vendor extension, ignore. */ - line_ptr = extended_end; - break; - } - switch (extended_op) - { - case DW_LNE_end_sequence: - state_machine.handle_end_sequence (); - end_sequence = true; - break; - case DW_LNE_set_address: - { - unrelocated_addr address - = cu->header.read_address (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - - state_machine.check_line_address (cu, line_ptr, lowpc, - address); - state_machine.handle_set_address (address); - } - break; - case DW_LNE_define_file: - { - const char *cur_file; - unsigned int mod_time, length; - dir_index dindex; - - cur_file = read_direct_string (abfd, line_ptr, - &bytes_read); - line_ptr += bytes_read; - dindex = (dir_index) - read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - mod_time = - read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - length = - read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - lh->add_file_name (cur_file, dindex, mod_time, length); - } - break; - case DW_LNE_set_discriminator: - { - /* The discriminator is not interesting to the - debugger; just ignore it. We still need to - check its value though: - if there are consecutive entries for the same - (non-prologue) line we want to coalesce them. - PR 17276. */ - unsigned int discr - = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - - state_machine.handle_set_discriminator (discr); - } - break; - default: - complaint (_("mangled .debug_line section")); - return; - } - /* Make sure that we parsed the extended op correctly. If e.g. - we expected a different address size than the producer used, - we may have read the wrong number of bytes. */ - if (line_ptr != extended_end) - { - complaint (_("mangled .debug_line section")); - return; - } - break; - case DW_LNS_copy: - state_machine.handle_copy (); - break; - case DW_LNS_advance_pc: - { - CORE_ADDR adjust - = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - - state_machine.handle_advance_pc (adjust); - } - break; - case DW_LNS_advance_line: - { - int line_delta - = read_signed_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - - state_machine.handle_advance_line (line_delta); - } - break; - case DW_LNS_set_file: - { - file_name_index file - = (file_name_index) read_unsigned_leb128 (abfd, line_ptr, - &bytes_read); - line_ptr += bytes_read; - - state_machine.handle_set_file (file); - } - break; - case DW_LNS_set_column: - (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - break; - case DW_LNS_negate_stmt: - state_machine.handle_negate_stmt (); - break; - case DW_LNS_set_basic_block: - break; - /* Add to the address register of the state machine the - address increment value corresponding to special opcode - 255. I.e., this value is scaled by the minimum - instruction length since special opcode 255 would have - scaled the increment. */ - case DW_LNS_const_add_pc: - state_machine.handle_const_add_pc (); - break; - case DW_LNS_fixed_advance_pc: - { - CORE_ADDR addr_adj = read_2_bytes (abfd, line_ptr); - line_ptr += 2; - - state_machine.handle_fixed_advance_pc (addr_adj); - } - break; - case DW_LNS_set_prologue_end: - state_machine.handle_set_prologue_end (); - break; - case DW_LNS_set_epilogue_begin: - state_machine.handle_set_epilogue_begin (); - break; - default: - { - /* Unknown standard opcode, ignore it. */ - int i; - - for (i = 0; i < lh->standard_opcode_lengths[op_code]; i++) - { - (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - } - } - } - } - - if (!end_sequence) - dwarf2_debug_line_missing_end_sequence_complaint (); - - /* We got a DW_LNE_end_sequence (or we ran off the end of the buffer, - in which case we still finish recording the last line). */ - state_machine.record_line (true); - } -} - -/* Decode the Line Number Program (LNP) for the given line_header - structure and CU. The actual information extracted and the type - of structures created from the LNP depends on the value of PST. - - FND holds the CU file name and directory, if known. - It is used for relative paths in the line table. - - NOTE: It is important that psymtabs have the same file name (via - strcmp) as the corresponding symtab. Since the directory is not - used in the name of the symtab we don't use it in the name of the - psymtabs we create. E.g. expand_line_sal requires this when - finding psymtabs to expand. A good testcase for this is - mb-inline.exp. - - LOWPC is the lowest address in CU (or 0 if not known). - - Boolean DECODE_MAPPING specifies we need to fully decode .debug_line - for its PC<->lines mapping information. Otherwise only the filename - table is read in. */ - -static void -dwarf_decode_lines (struct line_header *lh, struct dwarf2_cu *cu, - unrelocated_addr lowpc, int decode_mapping) -{ - if (decode_mapping) - dwarf_decode_lines_1 (lh, cu, lowpc); - - /* Make sure a symtab is created for every file, even files - which contain only variables (i.e. no code with associated - line numbers). */ - buildsym_compunit *builder = cu->get_builder (); - struct compunit_symtab *cust = builder->get_compunit_symtab (); - - for (auto &fe : lh->file_names ()) - { - dwarf2_start_subfile (cu, fe, *lh); - subfile *sf = builder->get_current_subfile (); - - if (sf->symtab == nullptr) - sf->symtab = allocate_symtab (cust, sf->name.c_str (), - sf->name_for_id.c_str ()); - - fe.symtab = sf->symtab; - } -} - -/* Start a subfile for DWARF. FILENAME is the name of the file and - DIRNAME the name of the source directory which contains FILENAME - or NULL if not known. - This routine tries to keep line numbers from identical absolute and - relative file names in a common subfile. - - Using the `list' example from the GDB testsuite, which resides in - /srcdir and compiling it with Irix6.2 cc in /compdir using a filename - of /srcdir/list0.c yields the following debugging information for list0.c: - - DW_AT_name: /srcdir/list0.c - DW_AT_comp_dir: /compdir - files.files[0].name: list0.h - files.files[0].dir: /srcdir - files.files[1].name: list0.c - files.files[1].dir: /srcdir - - The line number information for list0.c has to end up in a single - subfile, so that `break /srcdir/list0.c:1' works as expected. - start_subfile will ensure that this happens provided that we pass the - concatenation of files.files[1].dir and files.files[1].name as the - subfile's name. */ - -static void dwarf2_start_subfile (dwarf2_cu *cu, const file_entry &fe, const line_header &lh) { @@ -16659,7 +15934,7 @@ var_decode_location (struct attribute *attr, struct symbol *sym, variable has been optimized away. */ if (attr->form_is_block () && attr->as_block ()->size == 0) { - sym->set_aclass_index (LOC_OPTIMIZED_OUT); + sym->set_loc_class_index (LOC_OPTIMIZED_OUT); return; } @@ -16689,7 +15964,7 @@ var_decode_location (struct attribute *attr, struct symbol *sym, else tem = read_addr_index_from_leb128 (cu, block->data + 1, &dummy); sym->set_value_address ((CORE_ADDR) tem); - sym->set_aclass_index (LOC_STATIC); + sym->set_loc_class_index (LOC_STATIC); fixup_symbol_section (sym, objfile); sym->set_value_address (sym->value_address () @@ -16726,20 +16001,20 @@ add_ada_export_symbol (struct symbol *orig, const char *new_name, = new (&cu->per_objfile->objfile->objfile_obstack) symbol (*orig); copy->set_linkage_name (new_name); SYMBOL_LOCATION_BATON (copy) = (void *) orig_name; - copy->set_aclass_index (copy->aclass () == LOC_BLOCK + copy->set_loc_class_index (copy->loc_class () == LOC_BLOCK ? ada_block_index : ada_imported_index); add_symbol_to_list (copy, list_to_add); } -/* A helper function that decides if a given symbol is an Ada Pragma - Import or Pragma Export. */ +/* See read.h. */ -static bool +bool is_ada_import_or_export (dwarf2_cu *cu, const char *name, const char *linkagename) { return (cu->lang () == language_ada + && name != nullptr && linkagename != nullptr && !streq (name, linkagename) /* The following exclusions are necessary because symbols @@ -16826,7 +16101,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, /* Default assumptions. Use the passed type or decode it from the die. */ sym->set_domain (UNDEF_DOMAIN); - sym->set_aclass_index (LOC_OPTIMIZED_OUT); + sym->set_loc_class_index (LOC_OPTIMIZED_OUT); if (type != NULL) sym->set_type (type); else @@ -16876,10 +16151,10 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, CORE_ADDR addr = per_objfile->relocate (attr->as_address ()); sym->set_section_index (SECT_OFF_TEXT (objfile)); sym->set_value_address (addr); - sym->set_aclass_index (LOC_LABEL); + sym->set_loc_class_index (LOC_LABEL); } else - sym->set_aclass_index (LOC_OPTIMIZED_OUT); + sym->set_loc_class_index (LOC_OPTIMIZED_OUT); sym->set_type (builtin_type (objfile)->builtin_core_addr); sym->set_domain (LABEL_DOMAIN); list_to_add = cu->list_in_scope; @@ -16888,7 +16163,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by finish_block. */ sym->set_domain (FUNCTION_DOMAIN); - sym->set_aclass_index (LOC_BLOCK); + sym->set_loc_class_index (LOC_BLOCK); /* DW_TAG_entry_point provides an additional entry_point to an existing sub_program. Therefore, we inherit the "external" attribute from the sub_program to which the entry_point @@ -16903,7 +16178,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by finish_block. */ sym->set_domain (FUNCTION_DOMAIN); - sym->set_aclass_index (LOC_BLOCK); + sym->set_loc_class_index (LOC_BLOCK); attr2 = dwarf2_attr (die, DW_AT_external, cu); if ((attr2 != nullptr && attr2->as_boolean ()) || cu->lang () == language_ada @@ -16932,7 +16207,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, /* For Import, create a symbol using the source name, and have it refer to the linkage name. */ SYMBOL_LOCATION_BATON (sym) = (void *) linkagename; - sym->set_aclass_index (ada_block_index); + sym->set_loc_class_index (ada_block_index); } else { @@ -16948,7 +16223,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by finish_block. */ sym->set_domain (FUNCTION_DOMAIN); - sym->set_aclass_index (LOC_BLOCK); + sym->set_loc_class_index (LOC_BLOCK); sym->set_is_inlined (1); list_to_add = cu->list_in_scope; break; @@ -17000,7 +16275,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, && die->parent->tag == DW_TAG_common_block) attr2 = NULL; - if (sym->aclass () == LOC_STATIC + if (sym->loc_class () == LOC_STATIC && sym->value_address () == 0 && !per_objfile->per_bfd->has_section_at_zero) { @@ -17011,7 +16286,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, } else if (attr2 != nullptr && attr2->as_boolean ()) { - if (sym->aclass () == LOC_STATIC + if (sym->loc_class () == LOC_STATIC && (objfile->flags & OBJF_MAINLINE) == 0 && per_objfile->per_bfd->can_copy) { @@ -17080,7 +16355,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, ? cu->get_builder ()->get_global_symbols () : cu->list_in_scope); SYMBOL_LOCATION_BATON (sym) = (void *) linkagename; - sym->set_aclass_index (ada_imported_index); + sym->set_loc_class_index (ada_imported_index); } else if (attr2 != nullptr && attr2->as_boolean () && dwarf2_attr (die, DW_AT_type, cu) != NULL) @@ -17093,12 +16368,12 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, ? cu->get_builder ()->get_global_symbols () : cu->list_in_scope); - sym->set_aclass_index (LOC_UNRESOLVED); + sym->set_loc_class_index (LOC_UNRESOLVED); } else if (!die_is_declaration (die, cu)) { /* Use the default LOC_OPTIMIZED_OUT class. */ - gdb_assert (sym->aclass () == LOC_OPTIMIZED_OUT); + gdb_assert (sym->loc_class () == LOC_OPTIMIZED_OUT); if (!suppress_add) list_to_add = cu->list_in_scope; } @@ -17154,13 +16429,13 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, there's a special hack for C++ in the matching code, so we don't need to enter a separate typedef for the tag. */ - sym->set_aclass_index (LOC_TYPEDEF); + sym->set_loc_class_index (LOC_TYPEDEF); sym->set_domain (STRUCT_DOMAIN); } else { /* Other languages don't have a tag namespace. */ - sym->set_aclass_index (LOC_TYPEDEF); + sym->set_loc_class_index (LOC_TYPEDEF); sym->set_domain (TYPE_DOMAIN); } @@ -17205,7 +16480,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, case DW_TAG_base_type: case DW_TAG_subrange_type: case DW_TAG_generic_subrange: - sym->set_aclass_index (LOC_TYPEDEF); + sym->set_loc_class_index (LOC_TYPEDEF); sym->set_domain (TYPE_DOMAIN); list_to_add = cu->list_in_scope; break; @@ -17229,21 +16504,21 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu, case DW_TAG_imported_declaration: case DW_TAG_namespace: sym->set_domain (TYPE_DOMAIN); - sym->set_aclass_index (LOC_TYPEDEF); + sym->set_loc_class_index (LOC_TYPEDEF); list_to_add = cu->get_builder ()->get_global_symbols (); break; case DW_TAG_module: - sym->set_aclass_index (LOC_TYPEDEF); + sym->set_loc_class_index (LOC_TYPEDEF); sym->set_domain (MODULE_DOMAIN); list_to_add = cu->get_builder ()->get_global_symbols (); break; case DW_TAG_common_block: - sym->set_aclass_index (LOC_COMMON_BLOCK); + sym->set_loc_class_index (LOC_COMMON_BLOCK); sym->set_domain (COMMON_BLOCK_DOMAIN); list_to_add = cu->list_in_scope; break; case DW_TAG_namelist: - sym->set_aclass_index (LOC_STATIC); + sym->set_loc_class_index (LOC_STATIC); sym->set_domain (VAR_DOMAIN); list_to_add = cu->list_in_scope; break; @@ -17396,17 +16671,17 @@ dwarf2_const_value (const struct attribute *attr, struct symbol *sym, if (baton != NULL) { SYMBOL_LOCATION_BATON (sym) = baton; - sym->set_aclass_index (dwarf2_locexpr_index); + sym->set_loc_class_index (dwarf2_locexpr_index); } else if (bytes != NULL) { sym->set_value_bytes (bytes); - sym->set_aclass_index (LOC_CONST_BYTES); + sym->set_loc_class_index (LOC_CONST_BYTES); } else { sym->set_value_longest (value); - sym->set_aclass_index (LOC_CONST); + sym->set_loc_class_index (LOC_CONST); } } @@ -17773,9 +17048,11 @@ anonymous_struct_prefix (struct die_info *die, struct dwarf2_cu *cu) return NULL; attr = dw2_linkage_name_attr (die, cu); + if (attr == nullptr) + return nullptr; const char *attr_name = attr->as_string (); - if (attr == NULL || attr_name == NULL) - return NULL; + if (attr_name == nullptr) + return nullptr; /* dwarf2_name had to be already called. */ gdb_assert (attr->canonical_string_p ()); @@ -18977,7 +18254,7 @@ decode_locdesc (struct dwarf_block *blk, struct dwarf2_cu *cu, case DW_OP_deref: /* If we're not the last op, then we definitely can't encode - this using GDB's address_class enum. This is valid for partial + this using GDB's location_class enum. This is valid for partial global symbols, although the variable's address will be bogus in the psymtab. */ if (i < size) @@ -19219,7 +18496,7 @@ dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym, complaint (_("Location list used without " "specifying the CU base address.")); - sym->set_aclass_index ((is_block + sym->set_loc_class_index ((is_block ? dwarf2_loclist_block_index : dwarf2_loclist_index)); SYMBOL_LOCATION_BATON (sym) = baton; @@ -19252,7 +18529,7 @@ dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym, baton->size = 0; } - sym->set_aclass_index ((is_block + sym->set_loc_class_index ((is_block ? dwarf2_locexpr_block_index : dwarf2_locexpr_index)); SYMBOL_LOCATION_BATON (sym) = baton; diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index 4e3f8d7..2f9ad05 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -54,6 +54,7 @@ struct dwarf2_cu; struct dwarf2_debug_sections; struct dwarf2_per_bfd; struct dwarf2_per_cu; +struct file_entry; struct mapped_index; struct mapped_debug_names; struct signatured_type; @@ -127,7 +128,6 @@ struct dwarf2_per_cu lto_artificial (false), queued (false), m_header_read_in (false), - mark (false), files_read (false), scanned (false), section (section), @@ -195,10 +195,6 @@ public: it private at the moment. */ mutable packed<bool, 1> m_header_read_in; - /* A temporary mark bit used when iterating over all CUs in - expand_symtabs_matching. */ - packed<unsigned int, 1> mark; - /* True if we've tried to read the file table. There will be no point in trying to read it again next time. */ packed<bool, 1> files_read; @@ -673,6 +669,36 @@ public: std::string captured_debug_dir; }; +/* Scoped object to remove all units from PER_BFD and clear other associated + fields in case of failure. */ + +struct scoped_remove_all_units +{ + explicit scoped_remove_all_units (dwarf2_per_bfd &per_bfd) + : m_per_bfd (&per_bfd) + {} + + DISABLE_COPY_AND_ASSIGN (scoped_remove_all_units); + + ~scoped_remove_all_units () + { + if (m_per_bfd == nullptr) + return; + + m_per_bfd->all_units.clear (); + m_per_bfd->num_comp_units = 0; + m_per_bfd->num_type_units = 0; + } + + /* Disable this object. Call this to keep the units of M_PER_BFD on the + success path. */ + void disable () { m_per_bfd = nullptr; } + +private: + /* This is nullptr if the object is disabled. */ + dwarf2_per_bfd *m_per_bfd; +}; + /* An iterator for all_units that is based on index. This approach makes it possible to iterate over all_units safely, when some caller in the loop may add new units. */ @@ -1192,25 +1218,44 @@ struct dwarf2_base_index_functions : public quick_symbol_functions bool need_fullname) override; }; -/* If FILE_MATCHER is NULL or if PER_CU has - dwarf2_per_cu_quick_data::MARK set (see - dw_expand_symtabs_matching_file_matcher), expand the CU and call - EXPANSION_NOTIFY on it. */ +/* This is used to track whether a CU has already been visited during + symbol expansion. It is an auto-resizing bool vector. */ +class auto_bool_vector +{ +public: -extern bool dw2_expand_symtabs_matching_one - (dwarf2_per_cu *per_cu, - dwarf2_per_objfile *per_objfile, - expand_symtabs_file_matcher file_matcher, - expand_symtabs_expansion_listener expansion_notify, - expand_symtabs_lang_matcher lang_matcher); + auto_bool_vector () = default; + + /* Return true if element I is set. */ + bool is_set (size_t i) const + { + if (i < m_vec.size ()) + return m_vec[i]; + return false; + } + + /* Set a value in this vector, growing it automatically. */ + void set (size_t i, bool value) + { + if (m_vec.size () < i + 1) + m_vec.resize (i + 1); + m_vec[i] = value; + } + +private: + std::vector<bool> m_vec; +}; -/* If FILE_MATCHER is non-NULL, set all the - dwarf2_per_cu_quick_data::MARK of the current DWARF2_PER_OBJFILE - that match FILE_MATCHER. */ +/* If FILE_MATCHER is NULL and if CUS_TO_SKIP does not include the + CU's index, expand the CU and call LISTENER on it. */ -extern void dw_expand_symtabs_matching_file_matcher - (dwarf2_per_objfile *per_objfile, - expand_symtabs_file_matcher file_matcher); +extern bool dw2_search_one + (dwarf2_per_cu *per_cu, + dwarf2_per_objfile *per_objfile, + auto_bool_vector &cus_to_skip, + search_symtabs_file_matcher file_matcher, + search_symtabs_expansion_listener listener, + search_symtabs_lang_matcher lang_matcher); /* Return pointer to string at .debug_str offset STR_OFFSET. */ @@ -1321,4 +1366,40 @@ extern file_and_directory &find_file_and_directory (die_info *die, extern const dwarf2_section_info &get_section_for_ref (const attribute &attr, dwarf2_cu *cu); +/* A convenience function to find the proper .debug_line section for a CU. */ + +extern struct dwarf2_section_info *get_debug_line_section + (struct dwarf2_cu *cu); + +/* Start a subfile for DWARF. FILENAME is the name of the file and + DIRNAME the name of the source directory which contains FILENAME + or NULL if not known. + This routine tries to keep line numbers from identical absolute and + relative file names in a common subfile. + + Using the `list' example from the GDB testsuite, which resides in + /srcdir and compiling it with Irix6.2 cc in /compdir using a filename + of /srcdir/list0.c yields the following debugging information for list0.c: + + DW_AT_name: /srcdir/list0.c + DW_AT_comp_dir: /compdir + files.files[0].name: list0.h + files.files[0].dir: /srcdir + files.files[1].name: list0.c + files.files[1].dir: /srcdir + + The line number information for list0.c has to end up in a single + subfile, so that `break /srcdir/list0.c:1' works as expected. + start_subfile will ensure that this happens provided that we pass the + concatenation of files.files[1].dir and files.files[1].name as the + subfile's name. */ +extern void dwarf2_start_subfile (dwarf2_cu *cu, const file_entry &fe, + const line_header &lh); + +/* A helper function that decides if a given symbol is an Ada Pragma + Import or Pragma Export. */ + +extern bool is_ada_import_or_export (dwarf2_cu *cu, const char *name, + const char *linkagename); + #endif /* GDB_DWARF2_READ_H */ diff --git a/gdb/dwarf2/stringify.c b/gdb/dwarf2/stringify.c index c9625e8..bdb5125 100644 --- a/gdb/dwarf2/stringify.c +++ b/gdb/dwarf2/stringify.c @@ -25,6 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "dwarf2.h" +#include "dwarf2/read-gdb-index.h" #include "dwarf2/stringify.h" /* A convenience function that returns an "unknown" DWARF name, @@ -44,6 +45,11 @@ dwarf_unknown (const char *str, unsigned v) const char * dwarf_tag_name (unsigned tag) { + if (tag == DW_TAG_GDB_INDEX_OTHER) + return "DW_TAG_GDB_INDEX_OTHER"; + else if (tag == DW_TAG_GDB_INDEX_TYPE) + return "DW_TAG_GDB_INDEX_TYPE"; + const char *name = get_DW_TAG_name (tag); if (name == NULL) diff --git a/gdb/dwarf2/tag.h b/gdb/dwarf2/tag.h index ed730c0..9b5c775 100644 --- a/gdb/dwarf2/tag.h +++ b/gdb/dwarf2/tag.h @@ -22,6 +22,7 @@ #include "dwarf2.h" #include "symtab.h" +#include "read-gdb-index.h" /* Return true if TAG represents a type, false otherwise. */ @@ -102,6 +103,10 @@ tag_matches_domain (dwarf_tag tag, domain_search_flags search, language lang) } break; + case DW_TAG_imported_declaration: + /* DW_TAG_imported_declaration isn't necessarily a type, but the + scanner doesn't track the referent, and the full reader + also currently puts it in TYPE_DOMAIN. */ case DW_TAG_padding: case DW_TAG_array_type: case DW_TAG_pointer_type: @@ -140,6 +145,13 @@ tag_matches_domain (dwarf_tag tag, domain_search_flags search, language lang) else flags = SEARCH_MODULE_DOMAIN; break; + + case DW_TAG_GDB_INDEX_OTHER: + flags = SEARCH_MODULE_DOMAIN | SEARCH_TYPE_DOMAIN; + break; + case DW_TAG_GDB_INDEX_TYPE: + flags = SEARCH_STRUCT_DOMAIN | SEARCH_TYPE_DOMAIN; + break; } return (flags & search) != 0; |