X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fsymtab.c;h=791ce11a7372c11583eec384b5d44bf13d4366ea;hb=82836c928ffc6aaa9e594ba69af5f446bdc95bf4;hp=dff92ca203c06f21c7e7d720d0dc212c01865218;hpb=1a6ff1a96b302283d517b3cdeae7310adecbe859;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/symtab.c b/gdb/symtab.c index dff92ca203..791ce11a73 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -1,6 +1,6 @@ /* Symbol table lookup for the GNU debugger, GDB. - Copyright (C) 1986-2019 Free Software Foundation, Inc. + Copyright (C) 1986-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -183,6 +183,16 @@ struct symbol_cache_slot } value; }; +/* Clear out SLOT. */ + +static void +symbol_cache_clear_slot (struct symbol_cache_slot *slot) +{ + if (slot->state == SYMBOL_SLOT_NOT_FOUND) + xfree (slot->value.not_found.name); + slot->state = SYMBOL_SLOT_UNUSED; +} + /* Symbols don't specify global vs static block. So keep them in separate caches. */ @@ -201,6 +211,19 @@ struct block_symbol_cache struct symbol_cache_slot symbols[1]; }; +/* Clear all slots of BSC and free BSC. */ + +static void +destroy_block_symbol_cache (struct block_symbol_cache *bsc) +{ + if (bsc != nullptr) + { + for (unsigned int i = 0; i < bsc->size; i++) + symbol_cache_clear_slot (&bsc->symbols[i]); + xfree (bsc); + } +} + /* The symbol cache. Searching for symbols in the static and global blocks over multiple objfiles @@ -217,8 +240,8 @@ struct symbol_cache ~symbol_cache () { - xfree (global_symbols); - xfree (static_symbols); + destroy_block_symbol_cache (global_symbols); + destroy_block_symbol_cache (static_symbols); } struct block_symbol_cache *global_symbols = nullptr; @@ -299,6 +322,7 @@ search_domain_name (enum search_domain e) case VARIABLES_DOMAIN: return "VARIABLES_DOMAIN"; case FUNCTIONS_DOMAIN: return "FUNCTIONS_DOMAIN"; case TYPES_DOMAIN: return "TYPES_DOMAIN"; + case MODULES_DOMAIN: return "MODULES_DOMAIN"; case ALL_DOMAIN: return "ALL_DOMAIN"; default: gdb_assert_not_reached ("bad search_domain"); } @@ -480,6 +504,9 @@ iterate_over_some_symtabs (const char *name, gdb_assert (IS_ABSOLUTE_PATH (real_path)); gdb_assert (IS_ABSOLUTE_PATH (name)); + gdb::unique_xmalloc_ptr fullname_real_path + = gdb_realpath (fullname); + fullname = fullname_real_path.get (); if (FILENAME_CMP (real_path, fullname) == 0) { if (callback (s)) @@ -568,7 +595,7 @@ gdb_mangle_name (struct type *type, int method_id, int signature_id) struct fn_field *method = &f[signature_id]; const char *field_name = TYPE_FN_FIELDLIST_NAME (type, method_id); const char *physname = TYPE_FN_FIELD_PHYSNAME (f, signature_id); - const char *newname = TYPE_NAME (type); + const char *newname = type->name (); /* Does the form of physname indicate that it is the full mangled name of a constructor (not just the args)? */ @@ -640,44 +667,27 @@ gdb_mangle_name (struct type *type, int method_id, int signature_id) return (mangled_name); } -/* Set the demangled name of GSYMBOL to NAME. NAME must be already - correctly allocated. */ +/* See symtab.h. */ void -symbol_set_demangled_name (struct general_symbol_info *gsymbol, - const char *name, - struct obstack *obstack) +general_symbol_info::set_demangled_name (const char *name, + struct obstack *obstack) { - if (gsymbol->language == language_ada) + if (language () == language_ada) { if (name == NULL) { - gsymbol->ada_mangled = 0; - gsymbol->language_specific.obstack = obstack; + ada_mangled = 0; + language_specific.obstack = obstack; } else { - gsymbol->ada_mangled = 1; - gsymbol->language_specific.demangled_name = name; + ada_mangled = 1; + language_specific.demangled_name = name; } } else - gsymbol->language_specific.demangled_name = name; -} - -/* Return the demangled name of GSYMBOL. */ - -const char * -symbol_get_demangled_name (const struct general_symbol_info *gsymbol) -{ - if (gsymbol->language == language_ada) - { - if (!gsymbol->ada_mangled) - return NULL; - /* Fall through. */ - } - - return gsymbol->language_specific.demangled_name; + language_specific.demangled_name = name; } @@ -685,28 +695,26 @@ symbol_get_demangled_name (const struct general_symbol_info *gsymbol) depending upon the language for the symbol. */ void -symbol_set_language (struct general_symbol_info *gsymbol, - enum language language, - struct obstack *obstack) +general_symbol_info::set_language (enum language language, + struct obstack *obstack) { - gsymbol->language = language; - if (gsymbol->language == language_cplus - || gsymbol->language == language_d - || gsymbol->language == language_go - || gsymbol->language == language_objc - || gsymbol->language == language_fortran) + m_language = language; + if (language == language_cplus + || language == language_d + || language == language_go + || language == language_objc + || language == language_fortran) { - symbol_set_demangled_name (gsymbol, NULL, obstack); + set_demangled_name (NULL, obstack); } - else if (gsymbol->language == language_ada) + else if (language == language_ada) { - gdb_assert (gsymbol->ada_mangled == 0); - gsymbol->language_specific.obstack = obstack; + gdb_assert (ada_mangled == 0); + language_specific.obstack = obstack; } else { - memset (&gsymbol->language_specific, 0, - sizeof (gsymbol->language_specific)); + memset (&language_specific, 0, sizeof (language_specific)); } } @@ -715,9 +723,12 @@ symbol_set_language (struct general_symbol_info *gsymbol, /* Objects of this type are stored in the demangled name hash table. */ struct demangled_name_entry { + demangled_name_entry (gdb::string_view mangled_name) + : mangled (mangled_name) {} + gdb::string_view mangled; - ENUM_BITFIELD(language) language : LANGUAGE_BITS; - char demangled[1]; + enum language language; + gdb::unique_xmalloc_ptr demangled; }; /* Hash function for the demangled name hash. */ @@ -744,6 +755,15 @@ eq_demangled_name_entry (const void *a, const void *b) return da->mangled == db->mangled; } +static void +free_demangled_name_entry (void *data) +{ + struct demangled_name_entry *e + = (struct demangled_name_entry *) data; + + e->~demangled_name_entry(); +} + /* Create the hash table used for demangled names. Each hash entry is a pair of strings; one for the mangled name and one for the demangled name. The entry is hashed via just the mangled name. */ @@ -754,34 +774,40 @@ create_demangled_names_hash (struct objfile_per_bfd_storage *per_bfd) /* Choose 256 as the starting size of the hash table, somewhat arbitrarily. The hash table code will round this up to the next prime number. Choosing a much larger table size wastes memory, and saves only about - 1% in symbol reading. */ + 1% in symbol reading. However, if the minsym count is already + initialized (e.g. because symbol name setting was deferred to + a background thread) we can initialize the hashtable with a count + based on that, because we will almost certainly have at least that + many entries. If we have a nonzero number but less than 256, + we still stay with 256 to have some space for psymbols, etc. */ + + /* htab will expand the table when it is 3/4th full, so we account for that + here. +2 to round up. */ + int minsym_based_count = (per_bfd->minimal_symbol_count + 2) / 3 * 4; + int count = std::max (per_bfd->minimal_symbol_count, minsym_based_count); per_bfd->demangled_names_hash.reset (htab_create_alloc - (256, hash_demangled_name_entry, eq_demangled_name_entry, - NULL, xcalloc, xfree)); + (count, hash_demangled_name_entry, eq_demangled_name_entry, + free_demangled_name_entry, xcalloc, xfree)); } -/* Try to determine the demangled name for a symbol, based on the - language of that symbol. If the language is set to language_auto, - it will attempt to find any demangling algorithm that works and - then set the language appropriately. The returned name is allocated - by the demangler and should be xfree'd. */ +/* See symtab.h */ -static char * +char * symbol_find_demangled_name (struct general_symbol_info *gsymbol, const char *mangled) { char *demangled = NULL; int i; - if (gsymbol->language == language_unknown) - gsymbol->language = language_auto; + if (gsymbol->language () == language_unknown) + gsymbol->m_language = language_auto; - if (gsymbol->language != language_auto) + if (gsymbol->language () != language_auto) { - const struct language_defn *lang = language_def (gsymbol->language); + const struct language_defn *lang = language_def (gsymbol->language ()); - language_sniff_from_mangled_name (lang, mangled, &demangled); + lang->sniff_from_mangled_name (mangled, &demangled); return demangled; } @@ -790,9 +816,9 @@ symbol_find_demangled_name (struct general_symbol_info *gsymbol, enum language l = (enum language) i; const struct language_defn *lang = language_def (l); - if (language_sniff_from_mangled_name (lang, mangled, &demangled)) + if (lang->sniff_from_mangled_name (mangled, &demangled)) { - gsymbol->language = l; + gsymbol->m_language = l; return demangled; } } @@ -812,31 +838,24 @@ symbol_find_demangled_name (struct general_symbol_info *gsymbol, so the pointer can be discarded after calling this function. */ void -symbol_set_names (struct general_symbol_info *gsymbol, - const char *linkage_name, int len, bool copy_name, - struct objfile_per_bfd_storage *per_bfd) +general_symbol_info::compute_and_set_names (gdb::string_view linkage_name, + bool copy_name, + objfile_per_bfd_storage *per_bfd, + gdb::optional hash) { struct demangled_name_entry **slot; - /* A 0-terminated copy of the linkage name. */ - const char *linkage_name_copy; - struct demangled_name_entry entry; - if (gsymbol->language == language_ada) + if (language () == language_ada) { /* In Ada, we do the symbol lookups using the mangled name, so we can save some space by not storing the demangled name. */ if (!copy_name) - gsymbol->name = linkage_name; + m_name = linkage_name.data (); else - { - char *name = (char *) obstack_alloc (&per_bfd->storage_obstack, - len + 1); - - memcpy (name, linkage_name, len); - name[len] = '\0'; - gsymbol->name = name; - } - symbol_set_demangled_name (gsymbol, NULL, &per_bfd->storage_obstack); + m_name = obstack_strndup (&per_bfd->storage_obstack, + linkage_name.data (), + linkage_name.length ()); + set_demangled_name (NULL, &per_bfd->storage_obstack); return; } @@ -844,132 +863,134 @@ symbol_set_names (struct general_symbol_info *gsymbol, if (per_bfd->demangled_names_hash == NULL) create_demangled_names_hash (per_bfd); - if (linkage_name[len] != '\0') - { - char *alloc_name; - - alloc_name = (char *) alloca (len + 1); - memcpy (alloc_name, linkage_name, len); - alloc_name[len] = '\0'; - - linkage_name_copy = alloc_name; - } - else - linkage_name_copy = linkage_name; - - entry.mangled = gdb::string_view (linkage_name_copy, len); + struct demangled_name_entry entry (linkage_name); + if (!hash.has_value ()) + hash = hash_demangled_name_entry (&entry); slot = ((struct demangled_name_entry **) - htab_find_slot (per_bfd->demangled_names_hash.get (), - &entry, INSERT)); + htab_find_slot_with_hash (per_bfd->demangled_names_hash.get (), + &entry, *hash, INSERT)); + + /* The const_cast is safe because the only reason it is already + initialized is if we purposefully set it from a background + thread to avoid doing the work here. However, it is still + allocated from the heap and needs to be freed by us, just + like if we called symbol_find_demangled_name here. If this is + nullptr, we call symbol_find_demangled_name below, but we put + this smart pointer here to be sure that we don't leak this name. */ + gdb::unique_xmalloc_ptr demangled_name + (const_cast (language_specific.demangled_name)); /* If this name is not in the hash table, add it. */ if (*slot == NULL /* A C version of the symbol may have already snuck into the table. This happens to, e.g., main.init (__go_init_main). Cope. */ - || (gsymbol->language == language_go - && (*slot)->demangled[0] == '\0')) + || (language () == language_go && (*slot)->demangled == nullptr)) { - char *demangled_name_ptr - = symbol_find_demangled_name (gsymbol, linkage_name_copy); - gdb::unique_xmalloc_ptr demangled_name (demangled_name_ptr); - int demangled_len = demangled_name ? strlen (demangled_name.get ()) : 0; + /* A 0-terminated copy of the linkage name. Callers must set COPY_NAME + to true if the string might not be nullterminated. We have to make + this copy because demangling needs a nullterminated string. */ + gdb::string_view linkage_name_copy; + if (copy_name) + { + char *alloc_name = (char *) alloca (linkage_name.length () + 1); + memcpy (alloc_name, linkage_name.data (), linkage_name.length ()); + alloc_name[linkage_name.length ()] = '\0'; + + linkage_name_copy = gdb::string_view (alloc_name, + linkage_name.length ()); + } + else + linkage_name_copy = linkage_name; + + if (demangled_name.get () == nullptr) + demangled_name.reset + (symbol_find_demangled_name (this, linkage_name_copy.data ())); /* Suppose we have demangled_name==NULL, copy_name==0, and linkage_name_copy==linkage_name. In this case, we already have the mangled name saved, and we don't have a demangled name. So, you might think we could save a little space by not recording this in the hash table at all. - + It turns out that it is actually important to still save such an entry in the hash table, because storing this name gives us better bcache hit rates for partial symbols. */ - if (!copy_name && linkage_name_copy == linkage_name) + if (!copy_name) { *slot = ((struct demangled_name_entry *) obstack_alloc (&per_bfd->storage_obstack, - offsetof (struct demangled_name_entry, demangled) - + demangled_len + 1)); - (*slot)->mangled = gdb::string_view (linkage_name, len); + sizeof (demangled_name_entry))); + new (*slot) demangled_name_entry (linkage_name); } else { - char *mangled_ptr; - /* If we must copy the mangled name, put it directly after - the demangled name so we can have a single - allocation. */ + the struct so we can have a single allocation. */ *slot = ((struct demangled_name_entry *) obstack_alloc (&per_bfd->storage_obstack, - offsetof (struct demangled_name_entry, demangled) - + len + demangled_len + 2)); - mangled_ptr = &((*slot)->demangled[demangled_len + 1]); - strcpy (mangled_ptr, linkage_name_copy); - (*slot)->mangled = gdb::string_view (mangled_ptr, len); + sizeof (demangled_name_entry) + + linkage_name.length () + 1)); + char *mangled_ptr = reinterpret_cast (*slot + 1); + memcpy (mangled_ptr, linkage_name.data (), linkage_name.length ()); + mangled_ptr [linkage_name.length ()] = '\0'; + new (*slot) demangled_name_entry + (gdb::string_view (mangled_ptr, linkage_name.length ())); } - (*slot)->language = gsymbol->language; - - if (demangled_name != NULL) - strcpy ((*slot)->demangled, demangled_name.get ()); - else - (*slot)->demangled[0] = '\0'; + (*slot)->demangled = std::move (demangled_name); + (*slot)->language = language (); } - else if (gsymbol->language == language_unknown - || gsymbol->language == language_auto) - gsymbol->language = (*slot)->language; + else if (language () == language_unknown || language () == language_auto) + m_language = (*slot)->language; - gsymbol->name = (*slot)->mangled.data (); - if ((*slot)->demangled[0] != '\0') - symbol_set_demangled_name (gsymbol, (*slot)->demangled, - &per_bfd->storage_obstack); - else - symbol_set_demangled_name (gsymbol, NULL, &per_bfd->storage_obstack); + m_name = (*slot)->mangled.data (); + set_demangled_name ((*slot)->demangled.get (), &per_bfd->storage_obstack); } -/* Return the source code name of a symbol. In languages where - demangling is necessary, this is the demangled name. */ +/* See symtab.h. */ const char * -symbol_natural_name (const struct general_symbol_info *gsymbol) +general_symbol_info::natural_name () const { - switch (gsymbol->language) + switch (language ()) { case language_cplus: case language_d: case language_go: case language_objc: case language_fortran: - if (symbol_get_demangled_name (gsymbol) != NULL) - return symbol_get_demangled_name (gsymbol); + case language_rust: + if (language_specific.demangled_name != nullptr) + return language_specific.demangled_name; break; case language_ada: - return ada_decode_symbol (gsymbol); + return ada_decode_symbol (this); default: break; } - return gsymbol->name; + return linkage_name (); } -/* Return the demangled name for a symbol based on the language for - that symbol. If no demangled name exists, return NULL. */ +/* See symtab.h. */ const char * -symbol_demangled_name (const struct general_symbol_info *gsymbol) +general_symbol_info::demangled_name () const { const char *dem_name = NULL; - switch (gsymbol->language) + switch (language ()) { case language_cplus: case language_d: case language_go: case language_objc: case language_fortran: - dem_name = symbol_get_demangled_name (gsymbol); + case language_rust: + dem_name = language_specific.demangled_name; break; case language_ada: - dem_name = ada_decode_symbol (gsymbol); + dem_name = ada_decode_symbol (this); break; default: break; @@ -977,18 +998,15 @@ symbol_demangled_name (const struct general_symbol_info *gsymbol) return dem_name; } -/* Return the search name of a symbol---generally the demangled or - linkage name of the symbol, depending on how it will be searched for. - If there is no distinct demangled name, then returns the same value - (same pointer) as SYMBOL_LINKAGE_NAME. */ +/* See symtab.h. */ const char * -symbol_search_name (const struct general_symbol_info *gsymbol) +general_symbol_info::search_name () const { - if (gsymbol->language == language_ada) - return gsymbol->name; + if (language () == language_ada) + return linkage_name (); else - return symbol_natural_name (gsymbol); + return natural_name (); } /* See symtab.h. */ @@ -998,8 +1016,8 @@ symbol_matches_search_name (const struct general_symbol_info *gsymbol, const lookup_name_info &name) { symbol_name_matcher_ftype *name_match - = get_symbol_name_matcher (language_def (gsymbol->language), name); - return name_match (symbol_search_name (gsymbol), name, NULL); + = get_symbol_name_matcher (language_def (gsymbol->language ()), name); + return name_match (gsymbol->search_name (), name, NULL); } @@ -1139,7 +1157,7 @@ eq_symbol_entry (const struct symbol_cache_slot *slot, } else { - slot_name = SYMBOL_SEARCH_NAME (slot->value.found.symbol); + slot_name = slot->value.found.symbol->search_name (); slot_domain = SYMBOL_DOMAIN (slot->value.found.symbol); } @@ -1156,7 +1174,7 @@ eq_symbol_entry (const struct symbol_cache_slot *slot, /* It's important that we use the same comparison that was done the first time through. If the slot records a found symbol, then this means using the symbol name comparison function of - the symbol's language with SYMBOL_SEARCH_NAME. See + the symbol's language with symbol->search_name (). See dictionary.c. It also means using symbol_matches_domain for found symbols. See block.c. @@ -1178,8 +1196,7 @@ eq_symbol_entry (const struct symbol_cache_slot *slot, if (!SYMBOL_MATCHES_SEARCH_NAME (sym, lookup_name)) return 0; - if (!symbol_matches_domain (SYMBOL_LANGUAGE (sym), - slot_domain, domain)) + if (!symbol_matches_domain (sym->language (), slot_domain, domain)) return 0; } } @@ -1216,8 +1233,8 @@ resize_symbol_cache (struct symbol_cache *cache, unsigned int new_size) && new_size == 0)) return; - xfree (cache->global_symbols); - xfree (cache->static_symbols); + destroy_block_symbol_cache (cache->global_symbols); + destroy_block_symbol_cache (cache->static_symbols); if (new_size == 0) { @@ -1259,9 +1276,7 @@ get_symbol_cache (struct program_space *pspace) static void set_symbol_cache_size (unsigned int new_size) { - struct program_space *pspace; - - ALL_PSPACES (pspace) + for (struct program_space *pspace : program_spaces) { struct symbol_cache *cache = symbol_cache_key.get (pspace); @@ -1355,16 +1370,6 @@ symbol_cache_lookup (struct symbol_cache *cache, return {}; } -/* Clear out SLOT. */ - -static void -symbol_cache_clear_slot (struct symbol_cache_slot *slot) -{ - if (slot->state == SYMBOL_SLOT_NOT_FOUND) - xfree (slot->value.not_found.name); - slot->state = SYMBOL_SLOT_UNUSED; -} - /* Mark SYMBOL as found in SLOT. OBJFILE_CONTEXT is the current objfile when the lookup was done, or NULL if it's not needed to distinguish lookups (STATIC_BLOCK). It is *not* @@ -1505,7 +1510,7 @@ symbol_cache_dump (const struct symbol_cache *cache) printf_filtered (" [%4u] = %s, %s %s\n", i, host_address_to_string (context), - SYMBOL_PRINT_NAME (found), + found->print_name (), domain_name (SYMBOL_DOMAIN (found))); break; } @@ -1519,9 +1524,7 @@ symbol_cache_dump (const struct symbol_cache *cache) static void maintenance_print_symbol_cache (const char *args, int from_tty) { - struct program_space *pspace; - - ALL_PSPACES (pspace) + for (struct program_space *pspace : program_spaces) { struct symbol_cache *cache; @@ -1545,9 +1548,7 @@ maintenance_print_symbol_cache (const char *args, int from_tty) static void maintenance_flush_symbol_cache (const char *args, int from_tty) { - struct program_space *pspace; - - ALL_PSPACES (pspace) + for (struct program_space *pspace : program_spaces) { symbol_cache_flush (pspace); } @@ -1590,9 +1591,7 @@ symbol_cache_stats (struct symbol_cache *cache) static void maintenance_print_symbol_cache_statistics (const char *args, int from_tty) { - struct program_space *pspace; - - ALL_PSPACES (pspace) + for (struct program_space *pspace : program_spaces) { struct symbol_cache *cache; @@ -1642,7 +1641,8 @@ fixup_section (struct general_symbol_info *ginfo, e.g. on PowerPC64, where the minimal symbol for a function will point to the function descriptor, while the debug symbol will point to the actual function code. */ - msym = lookup_minimal_symbol_by_pc_name (addr, ginfo->name, objfile); + msym = lookup_minimal_symbol_by_pc_name (addr, ginfo->linkage_name (), + objfile); if (msym) ginfo->section = MSYMBOL_SECTION (msym); else @@ -1659,11 +1659,10 @@ fixup_section (struct general_symbol_info *ginfo, So, instead, search the section table when lookup by name has failed. The ``addr'' and ``endaddr'' fields may have already - been relocated. If so, the relocation offset (i.e. the - ANOFFSET value) needs to be subtracted from these values when - performing the comparison. We unconditionally subtract it, - because, when no relocation has been performed, the ANOFFSET - value will simply be zero. + been relocated. If so, the relocation offset needs to be + subtracted from these values when performing the comparison. + We unconditionally subtract it, because, when no relocation + has been performed, the value will simply be zero. The address of the symbol whose section we're fixing up HAS NOT BEEN adjusted (relocated) yet. It can't have been since @@ -1689,7 +1688,7 @@ fixup_section (struct general_symbol_info *ginfo, ALL_OBJFILE_OSECTIONS (objfile, s) { int idx = s - objfile->sections; - CORE_ADDR offset = ANOFFSET (objfile->section_offsets, idx); + CORE_ADDR offset = objfile->section_offsets[idx]; if (fallback == -1) fallback = idx; @@ -1752,7 +1751,7 @@ fixup_symbol_section (struct symbol *sym, struct objfile *objfile) return sym; } - fixup_section (&sym->ginfo, addr, objfile); + fixup_section (sym, addr, objfile); return sym; } @@ -1767,7 +1766,7 @@ demangle_for_lookup_info::demangle_for_lookup_info if (lookup_name.ignore_parameters () && lang == language_cplus) { gdb::unique_xmalloc_ptr without_params - = cp_remove_params_if_any (lookup_name.name ().c_str (), + = cp_remove_params_if_any (lookup_name.c_str (), lookup_name.completion_mode ()); if (without_params != NULL) @@ -1780,9 +1779,9 @@ demangle_for_lookup_info::demangle_for_lookup_info } if (lookup_name.match_type () == symbol_name_match_type::SEARCH_NAME) - m_demangled_name = lookup_name.name (); + m_demangled_name = lookup_name.c_str (); else - m_demangled_name = demangle_for_lookup (lookup_name.name ().c_str (), + m_demangled_name = demangle_for_lookup (lookup_name.c_str (), lang, storage); } @@ -1793,7 +1792,7 @@ lookup_name_info::match_any () { /* Lookup any symbol that "" would complete. I.e., this matches all symbol names. */ - static const lookup_name_info lookup_name ({}, symbol_name_match_type::FULL, + static const lookup_name_info lookup_name ("", symbol_name_match_type::FULL, true); return lookup_name; @@ -1831,9 +1830,9 @@ demangle_for_lookup (const char *name, enum language lang, /* If we were given a non-mangled name, canonicalize it according to the language (so far only for C++). */ - std::string canon = cp_canonicalize_string (name); - if (!canon.empty ()) - return storage.swap_string (canon); + gdb::unique_xmalloc_ptr canon = cp_canonicalize_string (name); + if (canon != nullptr) + return storage.set_malloc_ptr (std::move (canon)); } else if (lang == language_d) { @@ -1856,7 +1855,7 @@ demangle_for_lookup (const char *name, enum language lang, unsigned int search_name_hash (enum language language, const char *search_name) { - return language_def (language)->la_search_name_hash (search_name); + return language_def (language)->search_name_hash (search_name); } /* See symtab.h. @@ -1918,7 +1917,7 @@ lookup_language_this (const struct language_defn *lang, if (symbol_lookup_debug > 1) { - struct objfile *objfile = lookup_objfile_from_block (block); + struct objfile *objfile = block_objfile (block); fprintf_unfiltered (gdb_stdlog, "lookup_language_this (%s, %s (objfile %s))", @@ -1938,7 +1937,7 @@ lookup_language_this (const struct language_defn *lang, if (symbol_lookup_debug > 1) { fprintf_unfiltered (gdb_stdlog, " = %s (%s, block %s)\n", - SYMBOL_PRINT_NAME (sym), + sym->print_name (), host_address_to_string (sym), host_address_to_string (block)); } @@ -1967,14 +1966,14 @@ check_field (struct type *type, const char *name, /* The type may be a stub. */ type = check_typedef (type); - for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--) + for (i = type->num_fields () - 1; i >= TYPE_N_BASECLASSES (type); i--) { const char *t_field_name = TYPE_FIELD_NAME (type, i); if (t_field_name && (strcmp_iw (t_field_name, name) == 0)) { is_a_field_of_this->type = type; - is_a_field_of_this->field = &TYPE_FIELD (type, i); + is_a_field_of_this->field = &type->field (i); return 1; } } @@ -2013,7 +2012,8 @@ lookup_symbol_aux (const char *name, symbol_name_match_type match_type, if (symbol_lookup_debug) { - struct objfile *objfile = lookup_objfile_from_block (block); + struct objfile *objfile = (block == nullptr + ? nullptr : block_objfile (block)); fprintf_unfiltered (gdb_stdlog, "lookup_symbol_aux (%s, %s (objfile %s), %s, %s)\n", @@ -2063,11 +2063,11 @@ lookup_symbol_aux (const char *name, symbol_name_match_type match_type, /* I'm not really sure that type of this can ever be typedefed; just be safe. */ t = check_typedef (t); - if (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_IS_REFERENCE (t)) + if (t->code () == TYPE_CODE_PTR || TYPE_IS_REFERENCE (t)) t = TYPE_TARGET_TYPE (t); - if (TYPE_CODE (t) != TYPE_CODE_STRUCT - && TYPE_CODE (t) != TYPE_CODE_UNION) + if (t->code () != TYPE_CODE_STRUCT + && t->code () != TYPE_CODE_UNION) error (_("Internal error: `%s' is not an aggregate"), langdef->la_name_of_this); @@ -2158,32 +2158,6 @@ lookup_local_symbol (const char *name, /* See symtab.h. */ -struct objfile * -lookup_objfile_from_block (const struct block *block) -{ - if (block == NULL) - return NULL; - - block = block_global_block (block); - /* Look through all blockvectors. */ - for (objfile *obj : current_program_space->objfiles ()) - { - for (compunit_symtab *cust : obj->compunits ()) - if (block == BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), - GLOBAL_BLOCK)) - { - if (obj->separate_debug_objfile_backlink) - obj = obj->separate_debug_objfile_backlink; - - return obj; - } - } - - return NULL; -} - -/* See symtab.h. */ - struct symbol * lookup_symbol_in_block (const char *name, symbol_name_match_type match_type, const struct block *block, @@ -2193,7 +2167,8 @@ lookup_symbol_in_block (const char *name, symbol_name_match_type match_type, if (symbol_lookup_debug > 1) { - struct objfile *objfile = lookup_objfile_from_block (block); + struct objfile *objfile = (block == nullptr + ? nullptr : block_objfile (block)); fprintf_unfiltered (gdb_stdlog, "lookup_symbol_in_block (%s, %s (objfile %s), %s)", @@ -2262,6 +2237,8 @@ lookup_symbol_in_objfile_symtabs (struct objfile *objfile, name, domain_name (domain)); } + struct block_symbol other; + other.symbol = NULL; for (compunit_symtab *cust : objfile->compunits ()) { const struct blockvector *bv; @@ -2272,18 +2249,36 @@ lookup_symbol_in_objfile_symtabs (struct objfile *objfile, block = BLOCKVECTOR_BLOCK (bv, block_index); result.symbol = block_lookup_symbol_primary (block, name, domain); result.block = block; - if (result.symbol != NULL) + if (result.symbol == NULL) + continue; + if (best_symbol (result.symbol, domain)) { - if (symbol_lookup_debug > 1) + other = result; + break; + } + if (symbol_matches_domain (result.symbol->language (), + SYMBOL_DOMAIN (result.symbol), domain)) + { + struct symbol *better + = better_symbol (other.symbol, result.symbol, domain); + if (better != other.symbol) { - fprintf_unfiltered (gdb_stdlog, " = %s (block %s)\n", - host_address_to_string (result.symbol), - host_address_to_string (block)); + other.symbol = better; + other.block = block; } - result.symbol = fixup_symbol_section (result.symbol, objfile); - return result; + } + } + if (other.symbol != NULL) + { + if (symbol_lookup_debug > 1) + { + fprintf_unfiltered (gdb_stdlog, " = %s (block %s)\n", + host_address_to_string (other.symbol), + host_address_to_string (other.block)); } + other.symbol = fixup_symbol_section (other.symbol, objfile); + return other; } if (symbol_lookup_debug > 1) @@ -2463,7 +2458,8 @@ lookup_symbol_in_static_block (const char *name, if (symbol_lookup_debug) { - struct objfile *objfile = lookup_objfile_from_block (static_block); + struct objfile *objfile = (block == nullptr + ? nullptr : block_objfile (block)); fprintf_unfiltered (gdb_stdlog, "lookup_symbol_in_static_block (%s, %s (objfile %s)," @@ -2537,6 +2533,33 @@ lookup_symbol_in_objfile (struct objfile *objfile, enum block_enum block_index, return result; } +/* Find the language for partial symbol with NAME. */ + +static enum language +find_quick_global_symbol_language (const char *name, const domain_enum domain) +{ + for (objfile *objfile : current_program_space->objfiles ()) + { + if (objfile->sf && objfile->sf->qf + && objfile->sf->qf->lookup_global_symbol_language) + continue; + return language_unknown; + } + + for (objfile *objfile : current_program_space->objfiles ()) + { + bool symbol_found_p; + enum language lang + = objfile->sf->qf->lookup_global_symbol_language (objfile, name, domain, + &symbol_found_p); + if (!symbol_found_p) + continue; + return lang; + } + + return language_unknown; +} + /* Private data to be used with lookup_symbol_global_iterator_cb. */ struct global_or_static_sym_lookup_data @@ -2616,7 +2639,7 @@ lookup_global_or_static_symbol (const char *name, lookup_data.block_index = block_index; lookup_data.domain = domain; gdbarch_iterate_over_objfiles_in_search_order - (objfile != NULL ? get_objfile_arch (objfile) : target_gdbarch (), + (objfile != NULL ? objfile->arch () : target_gdbarch (), lookup_symbol_global_or_static_iterator_cb, &lookup_data, objfile); result = lookup_data.result; } @@ -2648,17 +2671,30 @@ lookup_global_symbol (const char *name, global block first. This yields "more expected" behavior, and is needed to support 'FILENAME'::VARIABLE lookups. */ const struct block *global_block = block_global_block (block); + symbol *sym = NULL; if (global_block != nullptr) { - symbol *sym = lookup_symbol_in_block (name, - symbol_name_match_type::FULL, - global_block, domain); - if (sym != nullptr) + sym = lookup_symbol_in_block (name, + symbol_name_match_type::FULL, + global_block, domain); + if (sym != NULL && best_symbol (sym, domain)) return { sym, global_block }; } - struct objfile *objfile = lookup_objfile_from_block (block); - return lookup_global_or_static_symbol (name, GLOBAL_BLOCK, objfile, domain); + struct objfile *objfile = nullptr; + if (block != nullptr) + { + objfile = block_objfile (block); + if (objfile->separate_debug_objfile_backlink != nullptr) + objfile = objfile->separate_debug_objfile_backlink; + } + + block_symbol bs + = lookup_global_or_static_symbol (name, GLOBAL_BLOCK, objfile, domain); + if (better_symbol (sym, bs.symbol, domain) == sym) + return { sym, global_block }; + else + return bs; } bool @@ -2686,7 +2722,7 @@ symbol_matches_domain (enum language symbol_language, struct type * lookup_transparent_type (const char *name) { - return current_language->la_lookup_transparent_type (name); + return current_language->lookup_transparent_type (name); } /* A helper for basic_lookup_transparent_type that interfaces with the @@ -2815,8 +2851,7 @@ iterate_over_symbols (const struct block *block, ALL_BLOCK_SYMBOLS_WITH_NAME (block, name, iter, sym) { - if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), - SYMBOL_DOMAIN (sym), domain)) + if (symbol_matches_domain (sym->language (), SYMBOL_DOMAIN (sym), domain)) { struct block_symbol block_sym = {sym, block}; @@ -3110,7 +3145,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent) if (MSYMBOL_TYPE (msymbol.minsym) == mst_solib_trampoline) { struct bound_minimal_symbol mfunsym - = lookup_minimal_symbol_text (MSYMBOL_LINKAGE_NAME (msymbol.minsym), + = lookup_minimal_symbol_text (msymbol.minsym->linkage_name (), NULL); if (mfunsym.minsym == NULL) @@ -3124,7 +3159,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent) * but the "break" still works, and the warning is annoying. * So I commented out the warning. RT */ /* warning ("In stub for %s; unable to find real function/line info", - SYMBOL_LINKAGE_NAME (msymbol)); */ + msymbol->linkage_name ()); */ ; /* fall through */ else if (BMSYMBOL_VALUE_ADDRESS (mfunsym) @@ -3132,11 +3167,21 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent) /* Avoid infinite recursion */ /* See above comment about why warning is commented out. */ /* warning ("In stub for %s; unable to find real function/line info", - SYMBOL_LINKAGE_NAME (msymbol)); */ + msymbol->linkage_name ()); */ ; /* fall through */ else - return find_pc_line (BMSYMBOL_VALUE_ADDRESS (mfunsym), 0); + { + /* Detect an obvious case of infinite recursion. If this + should occur, we'd like to know about it, so error out, + fatally. */ + if (BMSYMBOL_VALUE_ADDRESS (mfunsym) == pc) + internal_error (__FILE__, __LINE__, + _("Infinite recursion detected in find_pc_sect_line;" + "please file a bug report")); + + return find_pc_line (BMSYMBOL_VALUE_ADDRESS (mfunsym), 0); + } } symtab_and_line val; @@ -3192,7 +3237,12 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent) struct linetable_entry *last = item + len; item = std::upper_bound (first, last, pc, pc_compare); if (item != first) - prev = item - 1; /* Found a matching item. */ + { + /* Found a matching item. Skip backwards over any end of + sequence markers. */ + for (prev = item - 1; prev->line == 0 && prev != first; prev--) + /* Nothing. */; + } /* At this point, prev points at the line whose start addr is <= pc, and item points at the next line. If we ran off the end of the linetable @@ -3209,6 +3259,23 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent) best = prev; best_symtab = iter_s; + /* If during the binary search we land on a non-statement entry, + scan backward through entries at the same address to see if + there is an entry marked as is-statement. In theory this + duplication should have been removed from the line table + during construction, this is just a double check. If the line + table has had the duplication removed then this should be + pretty cheap. */ + if (!best->is_stmt) + { + struct linetable_entry *tmp = best; + while (tmp > first && (tmp - 1)->pc == tmp->pc + && (tmp - 1)->line != 0 && !tmp->is_stmt) + --tmp; + if (tmp->is_stmt) + best = tmp; + } + /* Discard BEST_END if it's before the PC of the current BEST. */ if (best_end <= best->pc) best_end = 0; @@ -3239,6 +3306,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent) } else { + val.is_stmt = best->is_stmt; val.symtab = best_symtab; val.line = best->line; val.pc = best->pc; @@ -3407,7 +3475,8 @@ find_pcs_for_symtab_line (struct symtab *symtab, int line, { struct linetable_entry *item = &SYMTAB_LINETABLE (symtab)->item[idx]; - if (*best_item == NULL || item->line < (*best_item)->line) + if (*best_item == NULL + || (item->line < (*best_item)->line && item->is_stmt)) *best_item = item; break; @@ -3518,6 +3587,10 @@ find_line_common (struct linetable *l, int lineno, { struct linetable_entry *item = &(l->item[i]); + /* Ignore non-statements. */ + if (!item->is_stmt) + continue; + if (item->line == lineno) { /* Return the first (lowest address) entry which matches. */ @@ -3560,7 +3633,7 @@ find_function_start_sal_1 (CORE_ADDR func_addr, obj_section *section, && (COMPUNIT_LOCATIONS_VALID (SYMTAB_COMPUNIT (sal.symtab)) || SYMTAB_LANGUAGE (sal.symtab) == language_asm)) { - struct gdbarch *gdbarch = get_objfile_arch (SYMTAB_OBJFILE (sal.symtab)); + struct gdbarch *gdbarch = SYMTAB_OBJFILE (sal.symtab)->arch (); sal.pc = func_addr; if (gdbarch_skip_entrypoint_p (gdbarch)) @@ -3703,7 +3776,7 @@ skip_prologue_sal (struct symtab_and_line *sal) objfile = symbol_objfile (sym); pc = BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym)); section = SYMBOL_OBJ_SECTION (objfile, sym); - name = SYMBOL_LINKAGE_NAME (sym); + name = sym->linkage_name (); } else { @@ -3716,10 +3789,10 @@ skip_prologue_sal (struct symtab_and_line *sal) objfile = msymbol.objfile; pc = BMSYMBOL_VALUE_ADDRESS (msymbol); section = MSYMBOL_OBJ_SECTION (objfile, msymbol.minsym); - name = MSYMBOL_LINKAGE_NAME (msymbol.minsym); + name = msymbol.minsym->linkage_name (); } - gdbarch = get_objfile_arch (objfile); + gdbarch = objfile->arch (); /* Process the prologue in two passes. In the first pass try to skip the prologue (SKIP is true) and verify there is a real need for it (indicated @@ -4332,31 +4405,28 @@ info_sources_command (const char *args, int from_tty) printf_filtered ("\n"); } -/* Compare FILE against all the NFILES entries of FILES. If BASENAMES is - non-zero compare only lbasename of FILES. */ +/* Compare FILE against all the entries of FILENAMES. If BASENAMES is + true compare only lbasename of FILENAMES. */ -static int -file_matches (const char *file, const char *files[], int nfiles, int basenames) +static bool +file_matches (const char *file, const std::vector &filenames, + bool basenames) { - int i; + if (filenames.empty ()) + return true; - if (file != NULL && nfiles != 0) + for (const char *name : filenames) { - for (i = 0; i < nfiles; i++) - { - if (compare_filenames_for_search (file, (basenames - ? lbasename (files[i]) - : files[i]))) - return 1; - } + name = (basenames ? lbasename (name) : name); + if (compare_filenames_for_search (file, name)) + return true; } - else if (nfiles == 0) - return 1; - return 0; + + return false; } -/* Helper function for sort_search_symbols_remove_dups and qsort. Can only - sort symbols, not minimal symbols. */ +/* Helper function for std::sort on symbol_search objects. Can only sort + symbols, not minimal symbols. */ int symbol_search::compare_search_syms (const symbol_search &sym_a, @@ -4372,8 +4442,7 @@ symbol_search::compare_search_syms (const symbol_search &sym_a, if (sym_a.block != sym_b.block) return sym_a.block - sym_b.block; - return strcmp (SYMBOL_PRINT_NAME (sym_a.symbol), - SYMBOL_PRINT_NAME (sym_b.symbol)); + return strcmp (sym_a.symbol->print_name (), sym_b.symbol->print_name ()); } /* Returns true if the type_name of symbol_type of SYM matches TREG. @@ -4390,7 +4459,7 @@ treg_matches_sym_type_name (const compiled_regex &treg, { fprintf_unfiltered (gdb_stdlog, "treg_matches_sym_type_name\n sym %s\n", - SYMBOL_NATURAL_NAME (sym)); + sym->natural_name ()); } sym_type = SYMBOL_TYPE (sym); @@ -4418,79 +4487,255 @@ treg_matches_sym_type_name (const compiled_regex &treg, return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0; } +/* See symtab.h. */ + +bool +global_symbol_searcher::is_suitable_msymbol + (const enum search_domain kind, const minimal_symbol *msymbol) +{ + switch (MSYMBOL_TYPE (msymbol)) + { + case mst_data: + case mst_bss: + case mst_file_data: + case mst_file_bss: + return kind == VARIABLES_DOMAIN; + case mst_text: + case mst_file_text: + case mst_solib_trampoline: + case mst_text_gnu_ifunc: + return kind == FUNCTIONS_DOMAIN; + default: + return false; + } +} + +/* See symtab.h. */ -/* Sort the symbols in RESULT and remove duplicates. */ +bool +global_symbol_searcher::expand_symtabs + (objfile *objfile, const gdb::optional &preg) const +{ + enum search_domain kind = m_kind; + bool found_msymbol = false; + + if (objfile->sf) + objfile->sf->qf->expand_symtabs_matching + (objfile, + [&] (const char *filename, bool basenames) + { + return file_matches (filename, filenames, basenames); + }, + &lookup_name_info::match_any (), + [&] (const char *symname) + { + return (!preg.has_value () + || preg->exec (symname, 0, NULL, 0) == 0); + }, + NULL, + kind); + + /* Here, we search through the minimal symbol tables for functions and + variables that match, and force their symbols to be read. This is in + particular necessary for demangled variable names, which are no longer + put into the partial symbol tables. The symbol will then be found + during the scan of symtabs later. + + For functions, find_pc_symtab should succeed if we have debug info for + the function, for variables we have to call + lookup_symbol_in_objfile_from_linkage_name to determine if the + variable has debug info. If the lookup fails, set found_msymbol so + that we will rescan to print any matching symbols without debug info. + We only search the objfile the msymbol came from, we no longer search + all objfiles. In large programs (1000s of shared libs) searching all + objfiles is not worth the pain. */ + if (filenames.empty () + && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN)) + { + for (minimal_symbol *msymbol : objfile->msymbols ()) + { + QUIT; -static void -sort_search_symbols_remove_dups (std::vector *result) + if (msymbol->created_by_gdb) + continue; + + if (is_suitable_msymbol (kind, msymbol)) + { + if (!preg.has_value () + || preg->exec (msymbol->natural_name (), 0, + NULL, 0) == 0) + { + /* An important side-effect of these lookup functions is + to expand the symbol table if msymbol is found, later + in the process we will add matching symbols or + msymbols to the results list, and that requires that + the symbols tables are expanded. */ + if (kind == FUNCTIONS_DOMAIN + ? (find_pc_compunit_symtab + (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) + == NULL) + : (lookup_symbol_in_objfile_from_linkage_name + (objfile, msymbol->linkage_name (), + VAR_DOMAIN) + .symbol == NULL)) + found_msymbol = true; + } + } + } + } + + return found_msymbol; +} + +/* See symtab.h. */ + +bool +global_symbol_searcher::add_matching_symbols + (objfile *objfile, + const gdb::optional &preg, + const gdb::optional &treg, + std::set *result_set) const { - std::sort (result->begin (), result->end ()); - result->erase (std::unique (result->begin (), result->end ()), - result->end ()); + enum search_domain kind = m_kind; + + /* Add matching symbols (if not already present). */ + for (compunit_symtab *cust : objfile->compunits ()) + { + const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (cust); + + for (block_enum block : { GLOBAL_BLOCK, STATIC_BLOCK }) + { + struct block_iterator iter; + struct symbol *sym; + const struct block *b = BLOCKVECTOR_BLOCK (bv, block); + + ALL_BLOCK_SYMBOLS (b, iter, sym) + { + struct symtab *real_symtab = symbol_symtab (sym); + + QUIT; + + /* Check first sole REAL_SYMTAB->FILENAME. It does + not need to be a substring of symtab_to_fullname as + it may contain "./" etc. */ + if ((file_matches (real_symtab->filename, filenames, false) + || ((basenames_may_differ + || file_matches (lbasename (real_symtab->filename), + filenames, true)) + && file_matches (symtab_to_fullname (real_symtab), + filenames, false))) + && ((!preg.has_value () + || preg->exec (sym->natural_name (), 0, + NULL, 0) == 0) + && ((kind == VARIABLES_DOMAIN + && SYMBOL_CLASS (sym) != LOC_TYPEDEF + && SYMBOL_CLASS (sym) != LOC_UNRESOLVED + && SYMBOL_CLASS (sym) != LOC_BLOCK + /* LOC_CONST can be used for more than + just enums, e.g., c++ static const + members. We only want to skip enums + here. */ + && !(SYMBOL_CLASS (sym) == LOC_CONST + && (SYMBOL_TYPE (sym)->code () + == TYPE_CODE_ENUM)) + && (!treg.has_value () + || treg_matches_sym_type_name (*treg, sym))) + || (kind == FUNCTIONS_DOMAIN + && SYMBOL_CLASS (sym) == LOC_BLOCK + && (!treg.has_value () + || treg_matches_sym_type_name (*treg, + sym))) + || (kind == TYPES_DOMAIN + && SYMBOL_CLASS (sym) == LOC_TYPEDEF + && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN) + || (kind == MODULES_DOMAIN + && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN + && SYMBOL_LINE (sym) != 0)))) + { + if (result_set->size () < m_max_search_results) + { + /* Match, insert if not already in the results. */ + symbol_search ss (block, sym); + if (result_set->find (ss) == result_set->end ()) + result_set->insert (ss); + } + else + return false; + } + } + } + } + + return true; } -/* Search the symbol table for matches to the regular expression REGEXP, - returning the results. +/* See symtab.h. */ + +bool +global_symbol_searcher::add_matching_msymbols + (objfile *objfile, const gdb::optional &preg, + std::vector *results) const +{ + enum search_domain kind = m_kind; + + for (minimal_symbol *msymbol : objfile->msymbols ()) + { + QUIT; + + if (msymbol->created_by_gdb) + continue; - Only symbols of KIND are searched: - VARIABLES_DOMAIN - search all symbols, excluding functions, type names, - and constants (enums). - if T_REGEXP is not NULL, only returns var that have - a type matching regular expression T_REGEXP. - FUNCTIONS_DOMAIN - search all functions - TYPES_DOMAIN - search all type names - ALL_DOMAIN - an internal error for this function + if (is_suitable_msymbol (kind, msymbol)) + { + if (!preg.has_value () + || preg->exec (msymbol->natural_name (), 0, + NULL, 0) == 0) + { + /* For functions we can do a quick check of whether the + symbol might be found via find_pc_symtab. */ + if (kind != FUNCTIONS_DOMAIN + || (find_pc_compunit_symtab + (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) + == NULL)) + { + if (lookup_symbol_in_objfile_from_linkage_name + (objfile, msymbol->linkage_name (), + VAR_DOMAIN).symbol == NULL) + { + /* Matching msymbol, add it to the results list. */ + if (results->size () < m_max_search_results) + results->emplace_back (GLOBAL_BLOCK, msymbol, objfile); + else + return false; + } + } + } + } + } - Within each file the results are sorted locally; each symtab's global and - static blocks are separately alphabetized. - Duplicate entries are removed. + return true; +} - When EXCLUDE_MINSYMS is false then matching minsyms are also returned, - otherwise they are excluded. */ +/* See symtab.h. */ std::vector -search_symbols (const char *regexp, enum search_domain kind, - const char *t_regexp, - int nfiles, const char *files[], - bool exclude_minsyms) +global_symbol_searcher::search () const { - const struct blockvector *bv; - const struct block *b; - int i = 0; - struct block_iterator iter; - struct symbol *sym; - int found_misc = 0; - static const enum minimal_symbol_type types[] - = {mst_data, mst_text, mst_unknown}; - static const enum minimal_symbol_type types2[] - = {mst_bss, mst_file_text, mst_unknown}; - static const enum minimal_symbol_type types3[] - = {mst_file_data, mst_solib_trampoline, mst_unknown}; - static const enum minimal_symbol_type types4[] - = {mst_file_bss, mst_text_gnu_ifunc, mst_unknown}; - enum minimal_symbol_type ourtype; - enum minimal_symbol_type ourtype2; - enum minimal_symbol_type ourtype3; - enum minimal_symbol_type ourtype4; - std::vector result; gdb::optional preg; gdb::optional treg; - gdb_assert (kind <= TYPES_DOMAIN); + gdb_assert (m_kind != ALL_DOMAIN); - ourtype = types[kind]; - ourtype2 = types2[kind]; - ourtype3 = types3[kind]; - ourtype4 = types4[kind]; - - if (regexp != NULL) + if (m_symbol_name_regexp != NULL) { + const char *symbol_name_regexp = m_symbol_name_regexp; + /* Make sure spacing is right for C++ operators. This is just a courtesy to make the matching less sensitive to how many spaces the user leaves between 'operator' and or . */ const char *opend; - const char *opname = operator_chars (regexp, &opend); + const char *opname = operator_chars (symbol_name_regexp, &opend); if (*opname) { @@ -4515,244 +4760,80 @@ search_symbols (const char *regexp, enum search_domain kind, char *tmp = (char *) alloca (8 + fix + strlen (opname) + 1); sprintf (tmp, "operator%.*s%s", fix, " ", opname); - regexp = tmp; + symbol_name_regexp = tmp; } } int cflags = REG_NOSUB | (case_sensitivity == case_sensitive_off ? REG_ICASE : 0); - preg.emplace (regexp, cflags, _("Invalid regexp")); + preg.emplace (symbol_name_regexp, cflags, + _("Invalid regexp")); } - if (t_regexp != NULL) + if (m_symbol_type_regexp != NULL) { int cflags = REG_NOSUB | (case_sensitivity == case_sensitive_off ? REG_ICASE : 0); - treg.emplace (t_regexp, cflags, _("Invalid regexp")); - } - - /* Search through the partial symtabs *first* for all symbols - matching the regexp. That way we don't have to reproduce all of - the machinery below. */ - expand_symtabs_matching ([&] (const char *filename, bool basenames) - { - return file_matches (filename, files, nfiles, - basenames); - }, - lookup_name_info::match_any (), - [&] (const char *symname) - { - return (!preg.has_value () - || preg->exec (symname, - 0, NULL, 0) == 0); - }, - NULL, - kind); - - /* Here, we search through the minimal symbol tables for functions - and variables that match, and force their symbols to be read. - This is in particular necessary for demangled variable names, - which are no longer put into the partial symbol tables. - The symbol will then be found during the scan of symtabs below. - - For functions, find_pc_symtab should succeed if we have debug info - for the function, for variables we have to call - lookup_symbol_in_objfile_from_linkage_name to determine if the variable - has debug info. - If the lookup fails, set found_misc so that we will rescan to print - any matching symbols without debug info. - We only search the objfile the msymbol came from, we no longer search - all objfiles. In large programs (1000s of shared libs) searching all - objfiles is not worth the pain. */ - - if (nfiles == 0 && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN)) - { - for (objfile *objfile : current_program_space->objfiles ()) - { - for (minimal_symbol *msymbol : objfile->msymbols ()) - { - QUIT; - - if (msymbol->created_by_gdb) - continue; - - if (MSYMBOL_TYPE (msymbol) == ourtype - || MSYMBOL_TYPE (msymbol) == ourtype2 - || MSYMBOL_TYPE (msymbol) == ourtype3 - || MSYMBOL_TYPE (msymbol) == ourtype4) - { - if (!preg.has_value () - || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0, - NULL, 0) == 0) - { - /* Note: An important side-effect of these - lookup functions is to expand the symbol - table if msymbol is found, for the benefit of - the next loop on compunits. */ - if (kind == FUNCTIONS_DOMAIN - ? (find_pc_compunit_symtab - (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) - == NULL) - : (lookup_symbol_in_objfile_from_linkage_name - (objfile, MSYMBOL_LINKAGE_NAME (msymbol), - VAR_DOMAIN) - .symbol == NULL)) - found_misc = 1; - } - } - } - } + treg.emplace (m_symbol_type_regexp, cflags, + _("Invalid regexp")); } + bool found_msymbol = false; + std::set result_set; for (objfile *objfile : current_program_space->objfiles ()) { - for (compunit_symtab *cust : objfile->compunits ()) - { - bv = COMPUNIT_BLOCKVECTOR (cust); - for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++) - { - b = BLOCKVECTOR_BLOCK (bv, i); - ALL_BLOCK_SYMBOLS (b, iter, sym) - { - struct symtab *real_symtab = symbol_symtab (sym); - - QUIT; - - /* Check first sole REAL_SYMTAB->FILENAME. It does - not need to be a substring of symtab_to_fullname as - it may contain "./" etc. */ - if ((file_matches (real_symtab->filename, files, nfiles, 0) - || ((basenames_may_differ - || file_matches (lbasename (real_symtab->filename), - files, nfiles, 1)) - && file_matches (symtab_to_fullname (real_symtab), - files, nfiles, 0))) - && ((!preg.has_value () - || preg->exec (SYMBOL_NATURAL_NAME (sym), 0, - NULL, 0) == 0) - && ((kind == VARIABLES_DOMAIN - && SYMBOL_CLASS (sym) != LOC_TYPEDEF - && SYMBOL_CLASS (sym) != LOC_UNRESOLVED - && SYMBOL_CLASS (sym) != LOC_BLOCK - /* LOC_CONST can be used for more than - just enums, e.g., c++ static const - members. We only want to skip enums - here. */ - && !(SYMBOL_CLASS (sym) == LOC_CONST - && (TYPE_CODE (SYMBOL_TYPE (sym)) - == TYPE_CODE_ENUM)) - && (!treg.has_value () - || treg_matches_sym_type_name (*treg, sym))) - || (kind == FUNCTIONS_DOMAIN - && SYMBOL_CLASS (sym) == LOC_BLOCK - && (!treg.has_value () - || treg_matches_sym_type_name (*treg, - sym))) - || (kind == TYPES_DOMAIN - && SYMBOL_CLASS (sym) == LOC_TYPEDEF - && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)))) - { - /* match */ - result.emplace_back (i, sym); - } - } - } - } - } + /* Expand symtabs within objfile that possibly contain matching + symbols. */ + found_msymbol |= expand_symtabs (objfile, preg); - if (!result.empty ()) - sort_search_symbols_remove_dups (&result); + /* Find matching symbols within OBJFILE and add them in to the + RESULT_SET set. Use a set here so that we can easily detect + duplicates as we go, and can therefore track how many unique + matches we have found so far. */ + if (!add_matching_symbols (objfile, preg, treg, &result_set)) + break; + } - /* If there are no eyes, avoid all contact. I mean, if there are - no debug symbols, then add matching minsyms. But if the user wants - to see symbols matching a type regexp, then never give a minimal symbol, - as we assume that a minimal symbol does not have a type. */ + /* Convert the result set into a sorted result list, as std::set is + defined to be sorted then no explicit call to std::sort is needed. */ + std::vector result (result_set.begin (), result_set.end ()); - if ((found_misc || (nfiles == 0 && kind != FUNCTIONS_DOMAIN)) - && !exclude_minsyms + /* If there are no debug symbols, then add matching minsyms. But if the + user wants to see symbols matching a type regexp, then never give a + minimal symbol, as we assume that a minimal symbol does not have a + type. */ + if ((found_msymbol || (filenames.empty () && m_kind == VARIABLES_DOMAIN)) + && !m_exclude_minsyms && !treg.has_value ()) { + gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN); for (objfile *objfile : current_program_space->objfiles ()) - { - for (minimal_symbol *msymbol : objfile->msymbols ()) - { - QUIT; - - if (msymbol->created_by_gdb) - continue; - - if (MSYMBOL_TYPE (msymbol) == ourtype - || MSYMBOL_TYPE (msymbol) == ourtype2 - || MSYMBOL_TYPE (msymbol) == ourtype3 - || MSYMBOL_TYPE (msymbol) == ourtype4) - { - if (!preg.has_value () - || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0, - NULL, 0) == 0) - { - /* For functions we can do a quick check of whether the - symbol might be found via find_pc_symtab. */ - if (kind != FUNCTIONS_DOMAIN - || (find_pc_compunit_symtab - (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) - == NULL)) - { - if (lookup_symbol_in_objfile_from_linkage_name - (objfile, MSYMBOL_LINKAGE_NAME (msymbol), - VAR_DOMAIN) - .symbol == NULL) - { - /* match */ - result.emplace_back (i, msymbol, objfile); - } - } - } - } - } - } + if (!add_matching_msymbols (objfile, preg, &result)) + break; } return result; } -/* Helper function for symtab_symbol_info, this function uses - the data returned from search_symbols() to print information - regarding the match to gdb_stdout. If LAST is not NULL, - print file and line number information for the symbol as - well. Skip printing the filename if it matches LAST. */ +/* See symtab.h. */ -static void -print_symbol_info (enum search_domain kind, - struct symbol *sym, - int block, const char *last) +std::string +symbol_to_info_string (struct symbol *sym, int block, + enum search_domain kind) { - scoped_switch_to_sym_language_if_auto l (sym); - struct symtab *s = symbol_symtab (sym); - - if (last != NULL) - { - const char *s_filename = symtab_to_filename_for_display (s); + std::string str; - if (filename_cmp (last, s_filename) != 0) - { - printf_filtered (_("\nFile %ps:\n"), - styled_string (file_name_style.style (), - s_filename)); - } - - if (SYMBOL_LINE (sym) != 0) - printf_filtered ("%d:\t", SYMBOL_LINE (sym)); - else - puts_filtered ("\t"); - } + gdb_assert (block == GLOBAL_BLOCK || block == STATIC_BLOCK); if (kind != TYPES_DOMAIN && block == STATIC_BLOCK) - printf_filtered ("static "); + str += "static "; /* Typedef that is not a C++ class. */ if (kind == TYPES_DOMAIN && SYMBOL_DOMAIN (sym) != STRUCT_DOMAIN) { + string_file tmp_stream; + /* FIXME: For C (and C++) we end up with a difference in output here between how a typedef is printed, and non-typedefs are printed. The TYPEDEF_PRINT code places a ";" at the end in an attempt to @@ -4761,26 +4842,70 @@ print_symbol_info (enum search_domain kind, For the struct printing case below, things are worse, we force printing of the ";" in this function, which is going to be wrong for languages that don't require a ";" between statements. */ - if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_TYPEDEF) - typedef_print (SYMBOL_TYPE (sym), sym, gdb_stdout); + if (SYMBOL_TYPE (sym)->code () == TYPE_CODE_TYPEDEF) + typedef_print (SYMBOL_TYPE (sym), sym, &tmp_stream); else - { - type_print (SYMBOL_TYPE (sym), "", gdb_stdout, -1); - printf_filtered ("\n"); - } + type_print (SYMBOL_TYPE (sym), "", &tmp_stream, -1); + str += tmp_stream.string (); } /* variable, func, or typedef-that-is-c++-class. */ else if (kind < TYPES_DOMAIN || (kind == TYPES_DOMAIN && SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN)) { + string_file tmp_stream; + type_print (SYMBOL_TYPE (sym), (SYMBOL_CLASS (sym) == LOC_TYPEDEF - ? "" : SYMBOL_PRINT_NAME (sym)), - gdb_stdout, 0); + ? "" : sym->print_name ()), + &tmp_stream, 0); + + str += tmp_stream.string (); + str += ";"; + } + /* Printing of modules is currently done here, maybe at some future + point we might want a language specific method to print the module + symbol so that we can customise the output more. */ + else if (kind == MODULES_DOMAIN) + str += sym->print_name (); + + return str; +} + +/* Helper function for symbol info commands, for example 'info functions', + 'info variables', etc. KIND is the kind of symbol we searched for, and + BLOCK is the type of block the symbols was found in, either GLOBAL_BLOCK + or STATIC_BLOCK. SYM is the symbol we found. If LAST is not NULL, + print file and line number information for the symbol as well. Skip + printing the filename if it matches LAST. */ + +static void +print_symbol_info (enum search_domain kind, + struct symbol *sym, + int block, const char *last) +{ + scoped_switch_to_sym_language_if_auto l (sym); + struct symtab *s = symbol_symtab (sym); + + if (last != NULL) + { + const char *s_filename = symtab_to_filename_for_display (s); + + if (filename_cmp (last, s_filename) != 0) + { + printf_filtered (_("\nFile %ps:\n"), + styled_string (file_name_style.style (), + s_filename)); + } - printf_filtered (";\n"); + if (SYMBOL_LINE (sym) != 0) + printf_filtered ("%d:\t", SYMBOL_LINE (sym)); + else + puts_filtered ("\t"); } + + std::string str = symbol_to_info_string (sym, block, kind); + printf_filtered ("%s\n", str.c_str ()); } /* This help function for symtab_symbol_info() prints information @@ -4789,7 +4914,7 @@ print_symbol_info (enum search_domain kind, static void print_msymbol_info (struct bound_minimal_symbol msymbol) { - struct gdbarch *gdbarch = get_objfile_arch (msymbol.objfile); + struct gdbarch *gdbarch = msymbol.objfile->arch (); char *tmp; if (gdbarch_addr_bit (gdbarch) <= 32) @@ -4806,8 +4931,7 @@ print_msymbol_info (struct bound_minimal_symbol msymbol) printf_filtered (_("%ps %ps\n"), styled_string (address_style.style (), tmp), - styled_string (sym_style, - MSYMBOL_PRINT_NAME (msymbol.minsym))); + styled_string (sym_style, msymbol.minsym->print_name ())); } /* This is the guts of the commands "info functions", "info types", and @@ -4821,19 +4945,19 @@ symtab_symbol_info (bool quiet, bool exclude_minsyms, const char *t_regexp, int from_tty) { static const char * const classnames[] = - {"variable", "function", "type"}; + {"variable", "function", "type", "module"}; const char *last_filename = ""; int first = 1; - gdb_assert (kind <= TYPES_DOMAIN); + gdb_assert (kind != ALL_DOMAIN); if (regexp != nullptr && *regexp == '\0') regexp = nullptr; - /* Must make sure that if we're interrupted, symbols gets freed. */ - std::vector symbols = search_symbols (regexp, kind, - t_regexp, 0, NULL, - exclude_minsyms); + global_symbol_searcher spec (kind, regexp); + spec.set_symbol_type_regexp (t_regexp); + spec.set_exclude_minsyms (exclude_minsyms); + std::vector symbols = spec.search (); if (!quiet) { @@ -4890,13 +5014,13 @@ symtab_symbol_info (bool quiet, bool exclude_minsyms, and 'info functions' commands. These correspond to the -q, -t, and -n options. */ -struct info_print_options +struct info_vars_funcs_options { bool quiet = false; bool exclude_minsyms = false; char *type_regexp = nullptr; - ~info_print_options () + ~info_vars_funcs_options () { xfree (type_regexp); } @@ -4905,24 +5029,25 @@ struct info_print_options /* The options used by the 'info variables' and 'info functions' commands. */ -static const gdb::option::option_def info_print_options_defs[] = { - gdb::option::boolean_option_def { +static const gdb::option::option_def info_vars_funcs_options_defs[] = { + gdb::option::boolean_option_def { "q", - [] (info_print_options *opt) { return &opt->quiet; }, + [] (info_vars_funcs_options *opt) { return &opt->quiet; }, nullptr, /* show_cmd_cb */ nullptr /* set_doc */ }, - gdb::option::boolean_option_def { + gdb::option::boolean_option_def { "n", - [] (info_print_options *opt) { return &opt->exclude_minsyms; }, + [] (info_vars_funcs_options *opt) { return &opt->exclude_minsyms; }, nullptr, /* show_cmd_cb */ nullptr /* set_doc */ }, - gdb::option::string_option_def { + gdb::option::string_option_def { "t", - [] (info_print_options *opt) { return &opt->type_regexp; }, + [] (info_vars_funcs_options *opt) { return &opt->type_regexp; + }, nullptr, /* show_cmd_cb */ nullptr /* set_doc */ } @@ -4932,20 +5057,20 @@ static const gdb::option::option_def info_print_options_defs[] = { functions'. */ static gdb::option::option_def_group -make_info_print_options_def_group (info_print_options *opts) +make_info_vars_funcs_options_def_group (info_vars_funcs_options *opts) { - return {{info_print_options_defs}, opts}; + return {{info_vars_funcs_options_defs}, opts}; } /* Command completer for 'info variables' and 'info functions'. */ static void -info_print_command_completer (struct cmd_list_element *ignore, - completion_tracker &tracker, - const char *text, const char * /* word */) +info_vars_funcs_command_completer (struct cmd_list_element *ignore, + completion_tracker &tracker, + const char *text, const char * /* word */) { const auto group - = make_info_print_options_def_group (nullptr); + = make_info_vars_funcs_options_def_group (nullptr); if (gdb::option::complete_options (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group)) return; @@ -4959,8 +5084,8 @@ info_print_command_completer (struct cmd_list_element *ignore, static void info_variables_command (const char *args, int from_tty) { - info_print_options opts; - auto grp = make_info_print_options_def_group (&opts); + info_vars_funcs_options opts; + auto grp = make_info_vars_funcs_options_def_group (&opts); gdb::option::process_options (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp); if (args != nullptr && *args == '\0') @@ -4975,8 +5100,9 @@ info_variables_command (const char *args, int from_tty) static void info_functions_command (const char *args, int from_tty) { - info_print_options opts; - auto grp = make_info_print_options_def_group (&opts); + info_vars_funcs_options opts; + + auto grp = make_info_vars_funcs_options_def_group (&opts); gdb::option::process_options (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp); if (args != nullptr && *args == '\0') @@ -5044,23 +5170,29 @@ info_types_command_completer (struct cmd_list_element *ignore, symbol_completer (ignore, tracker, text, word); } -/* Breakpoint all functions matching regular expression. */ +/* Implement the 'info modules' command. */ -void -rbreak_command_wrapper (char *regexp, int from_tty) +static void +info_modules_command (const char *args, int from_tty) { - rbreak_command (regexp, from_tty); + info_types_options opts; + + auto grp = make_info_types_options_def_group (&opts); + gdb::option::process_options + (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp); + if (args != nullptr && *args == '\0') + args = nullptr; + symtab_symbol_info (opts.quiet, true, args, MODULES_DOMAIN, NULL, + from_tty); } static void rbreak_command (const char *regexp, int from_tty) { std::string string; - const char **files = NULL; - const char *file_name; - int nfiles = 0; + const char *file_name = nullptr; - if (regexp) + if (regexp != nullptr) { const char *colon = strchr (regexp, ':'); @@ -5076,17 +5208,14 @@ rbreak_command (const char *regexp, int from_tty) while (isspace (local_name[colon_index])) local_name[colon_index--] = 0; file_name = local_name; - files = &file_name; - nfiles = 1; regexp = skip_spaces (colon + 1); } } - std::vector symbols = search_symbols (regexp, - FUNCTIONS_DOMAIN, - NULL, - nfiles, files, - false); + global_symbol_searcher spec (FUNCTIONS_DOMAIN, regexp); + if (file_name != nullptr) + spec.filenames.push_back (file_name); + std::vector symbols = spec.search (); scoped_rbreak_breakpoints finalize; for (const symbol_search &p : symbols) @@ -5097,18 +5226,18 @@ rbreak_command (const char *regexp, int from_tty) const char *fullname = symtab_to_fullname (symtab); string = string_printf ("%s:'%s'", fullname, - SYMBOL_LINKAGE_NAME (p.symbol)); + p.symbol->linkage_name ()); break_command (&string[0], from_tty); print_symbol_info (FUNCTIONS_DOMAIN, p.symbol, p.block, NULL); } else { string = string_printf ("'%s'", - MSYMBOL_LINKAGE_NAME (p.msymbol.minsym)); + p.msymbol.minsym->linkage_name ()); break_command (&string[0], from_tty); printf_filtered (" %s;\n", - MSYMBOL_PRINT_NAME (p.msymbol.minsym)); + p.msymbol.minsym->print_name ()); } } } @@ -5131,7 +5260,7 @@ compare_symbol_name (const char *symbol_name, language symbol_language, /* See symtab.h. */ -void +bool completion_list_add_name (completion_tracker &tracker, language symbol_language, const char *symname, @@ -5143,7 +5272,7 @@ completion_list_add_name (completion_tracker &tracker, /* Clip symbols that cannot match. */ if (!compare_symbol_name (symname, symbol_language, lookup_name, match_res)) - return; + return false; /* Refresh SYMNAME from the match string. It's potentially different depending on language. (E.g., on Ada, the match may be @@ -5167,6 +5296,8 @@ completion_list_add_name (completion_tracker &tracker, tracker.add_completion (std::move (completion), &match_res.match_for_lcd, text, word); } + + return true; } /* completion_list_add_name wrapper for struct symbol. */ @@ -5177,9 +5308,31 @@ completion_list_add_symbol (completion_tracker &tracker, const lookup_name_info &lookup_name, const char *text, const char *word) { - completion_list_add_name (tracker, SYMBOL_LANGUAGE (sym), - SYMBOL_NATURAL_NAME (sym), - lookup_name, text, word); + if (!completion_list_add_name (tracker, sym->language (), + sym->natural_name (), + lookup_name, text, word)) + return; + + /* C++ function symbols include the parameters within both the msymbol + name and the symbol name. The problem is that the msymbol name will + describe the parameters in the most basic way, with typedefs stripped + out, while the symbol name will represent the types as they appear in + the program. This means we will see duplicate entries in the + completion tracker. The following converts the symbol name back to + the msymbol name and removes the msymbol name from the completion + tracker. */ + if (sym->language () == language_cplus + && SYMBOL_DOMAIN (sym) == VAR_DOMAIN + && SYMBOL_CLASS (sym) == LOC_BLOCK) + { + /* The call to canonicalize returns the empty string if the input + string is already in canonical form, thanks to this we don't + remove the symbol we just added above. */ + gdb::unique_xmalloc_ptr str + = cp_canonicalize_string_no_typedefs (sym->natural_name ()); + if (str != nullptr) + tracker.remove_completion (str.get ()); + } } /* completion_list_add_name wrapper for struct minimal_symbol. */ @@ -5190,8 +5343,8 @@ completion_list_add_msymbol (completion_tracker &tracker, const lookup_name_info &lookup_name, const char *text, const char *word) { - completion_list_add_name (tracker, MSYMBOL_LANGUAGE (sym), - MSYMBOL_NATURAL_NAME (sym), + completion_list_add_name (tracker, sym->language (), + sym->natural_name (), lookup_name, text, word); } @@ -5211,7 +5364,7 @@ completion_list_objc_symbol (completion_tracker &tracker, const char *method, *category, *selector; char *tmp2 = NULL; - method = MSYMBOL_NATURAL_NAME (msymbol); + method = msymbol->natural_name (); /* Is it a method? */ if ((method[0] != '-') && (method[0] != '+')) @@ -5318,13 +5471,13 @@ completion_list_add_fields (completion_tracker &tracker, if (SYMBOL_CLASS (sym) == LOC_TYPEDEF) { struct type *t = SYMBOL_TYPE (sym); - enum type_code c = TYPE_CODE (t); + enum type_code c = t->code (); int j; if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT) - for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++) + for (j = TYPE_N_BASECLASSES (t); j < t->num_fields (); j++) if (TYPE_FIELD_NAME (t, j)) - completion_list_add_name (tracker, SYMBOL_LANGUAGE (sym), + completion_list_add_name (tracker, sym->language (), TYPE_FIELD_NAME (t, j), lookup_name, text, word); } @@ -5335,7 +5488,7 @@ completion_list_add_fields (completion_tracker &tracker, bool symbol_is_function_or_method (symbol *sym) { - switch (TYPE_CODE (SYMBOL_TYPE (sym))) + switch (SYMBOL_TYPE (sym)->code ()) { case TYPE_CODE_FUNC: case TYPE_CODE_METHOD: @@ -5370,7 +5523,7 @@ find_gnu_ifunc (const symbol *sym) if (SYMBOL_CLASS (sym) != LOC_BLOCK) return {}; - lookup_name_info lookup_name (SYMBOL_SEARCH_NAME (sym), + lookup_name_info lookup_name (sym->search_name (), symbol_name_match_type::SEARCH_NAME); struct objfile *objfile = symbol_objfile (sym); @@ -5386,7 +5539,7 @@ find_gnu_ifunc (const symbol *sym) CORE_ADDR msym_addr = MSYMBOL_VALUE_ADDRESS (objfile, minsym); if (MSYMBOL_TYPE (minsym) == mst_data_gnu_ifunc) { - struct gdbarch *gdbarch = get_objfile_arch (objfile); + struct gdbarch *gdbarch = objfile->arch (); msym_addr = gdbarch_convert_from_func_ptr_addr (gdbarch, msym_addr, @@ -5435,7 +5588,7 @@ add_symtab_completions (struct compunit_symtab *cust, if (code == TYPE_CODE_UNDEF || (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN - && TYPE_CODE (SYMBOL_TYPE (sym)) == code)) + && SYMBOL_TYPE (sym)->code () == code)) completion_list_add_symbol (tracker, sym, lookup_name, text, word); @@ -5586,7 +5739,7 @@ default_collect_symbol_completion_matches_break_on sym_text, word); } else if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN - && TYPE_CODE (SYMBOL_TYPE (sym)) == code) + && SYMBOL_TYPE (sym)->code () == code) completion_list_add_symbol (tracker, sym, lookup_name, sym_text, word); } @@ -6007,6 +6160,16 @@ find_main_name (void) /* The languages above didn't identify the name of the main procedure. Fallback to "main". */ + + /* Try to find language for main in psymtabs. */ + enum language lang + = find_quick_global_symbol_language ("main", VAR_DOMAIN); + if (lang != language_unknown) + { + set_main_name ("main", lang); + return; + } + set_main_name ("main", language_unknown); } @@ -6179,53 +6342,6 @@ initialize_ordinary_address_classes (void) -/* Helper function to initialize the fields of an objfile-owned symbol. - It assumed that *SYM is already all zeroes. */ - -static void -initialize_objfile_symbol_1 (struct symbol *sym) -{ - SYMBOL_OBJFILE_OWNED (sym) = 1; - SYMBOL_SECTION (sym) = -1; -} - -/* Initialize the symbol SYM, and mark it as being owned by an objfile. */ - -void -initialize_objfile_symbol (struct symbol *sym) -{ - memset (sym, 0, sizeof (*sym)); - initialize_objfile_symbol_1 (sym); -} - -/* Allocate and initialize a new 'struct symbol' on OBJFILE's - obstack. */ - -struct symbol * -allocate_symbol (struct objfile *objfile) -{ - struct symbol *result; - - result = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct symbol); - initialize_objfile_symbol_1 (result); - - return result; -} - -/* Allocate and initialize a new 'struct template_symbol' on OBJFILE's - obstack. */ - -struct template_symbol * -allocate_template_symbol (struct objfile *objfile) -{ - struct template_symbol *result; - - result = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct template_symbol); - initialize_objfile_symbol_1 (result); - - return result; -} - /* See symtab.h. */ struct objfile * @@ -6242,7 +6358,7 @@ symbol_arch (const struct symbol *symbol) { if (!SYMBOL_OBJFILE_OWNED (symbol)) return symbol->owner.arch; - return get_objfile_arch (SYMTAB_OBJFILE (symbol->owner.symtab)); + return SYMTAB_OBJFILE (symbol->owner.symtab)->arch (); } /* See symtab.h. */ @@ -6271,16 +6387,19 @@ get_symbol_address (const struct symbol *sym) gdb_assert (sym->maybe_copied); gdb_assert (SYMBOL_CLASS (sym) == LOC_STATIC); - const char *linkage_name = SYMBOL_LINKAGE_NAME (sym); + const char *linkage_name = sym->linkage_name (); for (objfile *objfile : current_program_space->objfiles ()) { + if (objfile->separate_debug_objfile_backlink != nullptr) + continue; + bound_minimal_symbol minsym = lookup_minimal_symbol_linkage (linkage_name, objfile); if (minsym.minsym != nullptr) return BMSYMBOL_VALUE_ADDRESS (minsym); } - return sym->ginfo.value.address; + return sym->value.address; } /* See symtab.h. */ @@ -6291,11 +6410,12 @@ get_msymbol_address (struct objfile *objf, const struct minimal_symbol *minsym) gdb_assert (minsym->maybe_copied); gdb_assert ((objf->flags & OBJF_MAINLINE) == 0); - const char *linkage_name = MSYMBOL_LINKAGE_NAME (minsym); + const char *linkage_name = minsym->linkage_name (); for (objfile *objfile : current_program_space->objfiles ()) { - if ((objfile->flags & OBJF_MAINLINE) != 0) + if (objfile->separate_debug_objfile_backlink == nullptr + && (objfile->flags & OBJF_MAINLINE) != 0) { bound_minimal_symbol found = lookup_minimal_symbol_linkage (linkage_name, objfile); @@ -6303,14 +6423,313 @@ get_msymbol_address (struct objfile *objf, const struct minimal_symbol *minsym) return BMSYMBOL_VALUE_ADDRESS (found); } } - return (minsym->value.address - + ANOFFSET (objf->section_offsets, minsym->section)); + return minsym->value.address + objf->section_offsets[minsym->section]; } +/* Hold the sub-commands of 'info module'. */ + +static struct cmd_list_element *info_module_cmdlist = NULL; + +/* See symtab.h. */ + +std::vector +search_module_symbols (const char *module_regexp, const char *regexp, + const char *type_regexp, search_domain kind) +{ + std::vector results; + + /* Search for all modules matching MODULE_REGEXP. */ + global_symbol_searcher spec1 (MODULES_DOMAIN, module_regexp); + spec1.set_exclude_minsyms (true); + std::vector modules = spec1.search (); + + /* Now search for all symbols of the required KIND matching the required + regular expressions. We figure out which ones are in which modules + below. */ + global_symbol_searcher spec2 (kind, regexp); + spec2.set_symbol_type_regexp (type_regexp); + spec2.set_exclude_minsyms (true); + std::vector symbols = spec2.search (); + + /* Now iterate over all MODULES, checking to see which items from + SYMBOLS are in each module. */ + for (const symbol_search &p : modules) + { + QUIT; + + /* This is a module. */ + gdb_assert (p.symbol != nullptr); + + std::string prefix = p.symbol->print_name (); + prefix += "::"; + + for (const symbol_search &q : symbols) + { + if (q.symbol == nullptr) + continue; + + if (strncmp (q.symbol->print_name (), prefix.c_str (), + prefix.size ()) != 0) + continue; + + results.push_back ({p, q}); + } + } + + return results; +} + +/* Implement the core of both 'info module functions' and 'info module + variables'. */ + +static void +info_module_subcommand (bool quiet, const char *module_regexp, + const char *regexp, const char *type_regexp, + search_domain kind) +{ + /* Print a header line. Don't build the header line bit by bit as this + prevents internationalisation. */ + if (!quiet) + { + if (module_regexp == nullptr) + { + if (type_regexp == nullptr) + { + if (regexp == nullptr) + printf_filtered ((kind == VARIABLES_DOMAIN + ? _("All variables in all modules:") + : _("All functions in all modules:"))); + else + printf_filtered + ((kind == VARIABLES_DOMAIN + ? _("All variables matching regular expression" + " \"%s\" in all modules:") + : _("All functions matching regular expression" + " \"%s\" in all modules:")), + regexp); + } + else + { + if (regexp == nullptr) + printf_filtered + ((kind == VARIABLES_DOMAIN + ? _("All variables with type matching regular " + "expression \"%s\" in all modules:") + : _("All functions with type matching regular " + "expression \"%s\" in all modules:")), + type_regexp); + else + printf_filtered + ((kind == VARIABLES_DOMAIN + ? _("All variables matching regular expression " + "\"%s\",\n\twith type matching regular " + "expression \"%s\" in all modules:") + : _("All functions matching regular expression " + "\"%s\",\n\twith type matching regular " + "expression \"%s\" in all modules:")), + regexp, type_regexp); + } + } + else + { + if (type_regexp == nullptr) + { + if (regexp == nullptr) + printf_filtered + ((kind == VARIABLES_DOMAIN + ? _("All variables in all modules matching regular " + "expression \"%s\":") + : _("All functions in all modules matching regular " + "expression \"%s\":")), + module_regexp); + else + printf_filtered + ((kind == VARIABLES_DOMAIN + ? _("All variables matching regular expression " + "\"%s\",\n\tin all modules matching regular " + "expression \"%s\":") + : _("All functions matching regular expression " + "\"%s\",\n\tin all modules matching regular " + "expression \"%s\":")), + regexp, module_regexp); + } + else + { + if (regexp == nullptr) + printf_filtered + ((kind == VARIABLES_DOMAIN + ? _("All variables with type matching regular " + "expression \"%s\"\n\tin all modules matching " + "regular expression \"%s\":") + : _("All functions with type matching regular " + "expression \"%s\"\n\tin all modules matching " + "regular expression \"%s\":")), + type_regexp, module_regexp); + else + printf_filtered + ((kind == VARIABLES_DOMAIN + ? _("All variables matching regular expression " + "\"%s\",\n\twith type matching regular expression " + "\"%s\",\n\tin all modules matching regular " + "expression \"%s\":") + : _("All functions matching regular expression " + "\"%s\",\n\twith type matching regular expression " + "\"%s\",\n\tin all modules matching regular " + "expression \"%s\":")), + regexp, type_regexp, module_regexp); + } + } + printf_filtered ("\n"); + } + + /* Find all symbols of type KIND matching the given regular expressions + along with the symbols for the modules in which those symbols + reside. */ + std::vector module_symbols + = search_module_symbols (module_regexp, regexp, type_regexp, kind); + + std::sort (module_symbols.begin (), module_symbols.end (), + [] (const module_symbol_search &a, const module_symbol_search &b) + { + if (a.first < b.first) + return true; + else if (a.first == b.first) + return a.second < b.second; + else + return false; + }); + + const char *last_filename = ""; + const symbol *last_module_symbol = nullptr; + for (const module_symbol_search &ms : module_symbols) + { + const symbol_search &p = ms.first; + const symbol_search &q = ms.second; + + gdb_assert (q.symbol != nullptr); + + if (last_module_symbol != p.symbol) + { + printf_filtered ("\n"); + printf_filtered (_("Module \"%s\":\n"), p.symbol->print_name ()); + last_module_symbol = p.symbol; + last_filename = ""; + } + + print_symbol_info (FUNCTIONS_DOMAIN, q.symbol, q.block, + last_filename); + last_filename + = symtab_to_filename_for_display (symbol_symtab (q.symbol)); + } +} + +/* Hold the option values for the 'info module .....' sub-commands. */ + +struct info_modules_var_func_options +{ + bool quiet = false; + char *type_regexp = nullptr; + char *module_regexp = nullptr; + + ~info_modules_var_func_options () + { + xfree (type_regexp); + xfree (module_regexp); + } +}; + +/* The options used by 'info module variables' and 'info module functions' + commands. */ + +static const gdb::option::option_def info_modules_var_func_options_defs [] = { + gdb::option::boolean_option_def { + "q", + [] (info_modules_var_func_options *opt) { return &opt->quiet; }, + nullptr, /* show_cmd_cb */ + nullptr /* set_doc */ + }, + + gdb::option::string_option_def { + "t", + [] (info_modules_var_func_options *opt) { return &opt->type_regexp; }, + nullptr, /* show_cmd_cb */ + nullptr /* set_doc */ + }, + + gdb::option::string_option_def { + "m", + [] (info_modules_var_func_options *opt) { return &opt->module_regexp; }, + nullptr, /* show_cmd_cb */ + nullptr /* set_doc */ + } +}; + +/* Return the option group used by the 'info module ...' sub-commands. */ + +static inline gdb::option::option_def_group +make_info_modules_var_func_options_def_group + (info_modules_var_func_options *opts) +{ + return {{info_modules_var_func_options_defs}, opts}; +} + +/* Implements the 'info module functions' command. */ + +static void +info_module_functions_command (const char *args, int from_tty) +{ + info_modules_var_func_options opts; + auto grp = make_info_modules_var_func_options_def_group (&opts); + gdb::option::process_options + (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp); + if (args != nullptr && *args == '\0') + args = nullptr; + + info_module_subcommand (opts.quiet, opts.module_regexp, args, + opts.type_regexp, FUNCTIONS_DOMAIN); +} + +/* Implements the 'info module variables' command. */ + +static void +info_module_variables_command (const char *args, int from_tty) +{ + info_modules_var_func_options opts; + auto grp = make_info_modules_var_func_options_def_group (&opts); + gdb::option::process_options + (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp); + if (args != nullptr && *args == '\0') + args = nullptr; + + info_module_subcommand (opts.quiet, opts.module_regexp, args, + opts.type_regexp, VARIABLES_DOMAIN); +} + +/* Command completer for 'info module ...' sub-commands. */ + +static void +info_module_var_func_command_completer (struct cmd_list_element *ignore, + completion_tracker &tracker, + const char *text, + const char * /* word */) +{ + + const auto group = make_info_modules_var_func_options_def_group (nullptr); + if (gdb::option::complete_options + (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group)) + return; + + const char *word = advance_to_expression_complete_word_point (tracker, text); + symbol_completer (ignore, tracker, text, word); +} + + + +void _initialize_symtab (); void -_initialize_symtab (void) +_initialize_symtab () { cmd_list_element *c; @@ -6323,7 +6742,7 @@ Usage: info variables [-q] [-n] [-t TYPEREGEXP] [NAMEREGEXP]\n\ Prints the global and static variables.\n"), _("global and static variables"), true)); - set_cmd_completer_handle_brkchars (c, info_print_command_completer); + set_cmd_completer_handle_brkchars (c, info_vars_funcs_command_completer); if (dbx_commands) { c = add_com ("whereis", class_info, info_variables_command, @@ -6333,7 +6752,7 @@ Usage: whereis [-q] [-n] [-t TYPEREGEXP] [NAMEREGEXP]\n\ Prints the global and static variables.\n"), _("global and static variables"), true)); - set_cmd_completer_handle_brkchars (c, info_print_command_completer); + set_cmd_completer_handle_brkchars (c, info_vars_funcs_command_completer); } c = add_info ("functions", info_functions_command, @@ -6343,7 +6762,7 @@ Usage: info functions [-q] [-n] [-t TYPEREGEXP] [NAMEREGEXP]\n\ Prints the functions.\n"), _("functions"), true)); - set_cmd_completer_handle_brkchars (c, info_print_command_completer); + set_cmd_completer_handle_brkchars (c, info_vars_funcs_command_completer); c = add_info ("types", info_types_command, _("\ All type names, or those matching REGEXP.\n\ @@ -6367,6 +6786,49 @@ Options:\n\ c = add_info ("sources", info_sources_command, info_sources_help.c_str ()); set_cmd_completer_handle_brkchars (c, info_sources_command_completer); + c = add_info ("modules", info_modules_command, + _("All module names, or those matching REGEXP.")); + set_cmd_completer_handle_brkchars (c, info_types_command_completer); + + add_basic_prefix_cmd ("module", class_info, _("\ +Print information about modules."), + &info_module_cmdlist, "info module ", + 0, &infolist); + + c = add_cmd ("functions", class_info, info_module_functions_command, _("\ +Display functions arranged by modules.\n\ +Usage: info module functions [-q] [-m MODREGEXP] [-t TYPEREGEXP] [REGEXP]\n\ +Print a summary of all functions within each Fortran module, grouped by\n\ +module and file. For each function the line on which the function is\n\ +defined is given along with the type signature and name of the function.\n\ +\n\ +If REGEXP is provided then only functions whose name matches REGEXP are\n\ +listed. If MODREGEXP is provided then only functions in modules matching\n\ +MODREGEXP are listed. If TYPEREGEXP is given then only functions whose\n\ +type signature matches TYPEREGEXP are listed.\n\ +\n\ +The -q flag suppresses printing some header information."), + &info_module_cmdlist); + set_cmd_completer_handle_brkchars + (c, info_module_var_func_command_completer); + + c = add_cmd ("variables", class_info, info_module_variables_command, _("\ +Display variables arranged by modules.\n\ +Usage: info module variables [-q] [-m MODREGEXP] [-t TYPEREGEXP] [REGEXP]\n\ +Print a summary of all variables within each Fortran module, grouped by\n\ +module and file. For each variable the line on which the variable is\n\ +defined is given along with the type and name of the variable.\n\ +\n\ +If REGEXP is provided then only variables whose name matches REGEXP are\n\ +listed. If MODREGEXP is provided then only variables in modules matching\n\ +MODREGEXP are listed. If TYPEREGEXP is given then only variables whose\n\ +type matches TYPEREGEXP are listed.\n\ +\n\ +The -q flag suppresses printing some header information."), + &info_module_cmdlist); + set_cmd_completer_handle_brkchars + (c, info_module_var_func_command_completer); + add_com ("rbreak", class_breakpoint, rbreak_command, _("Set a breakpoint for all functions matching REGEXP."));