/* Symbol table lookup for the GNU debugger, GDB.
- Copyright (C) 1986-2020 Free Software Foundation, Inc.
+ Copyright (C) 1986-2022 Free Software Foundation, Inc.
This file is part of GDB.
#include "symfile.h"
#include "objfiles.h"
#include "gdbcmd.h"
-#include "gdb_regex.h"
+#include "gdbsupport/gdb_regex.h"
#include "expression.h"
#include "language.h"
#include "demangle.h"
#include "addrmap.h"
#include "cli/cli-utils.h"
#include "cli/cli-style.h"
+#include "cli/cli-cmds.h"
#include "fnmatch.h"
#include "hashtab.h"
#include "typeprint.h"
-#include "gdb_obstack.h"
+#include "gdbsupport/gdb_obstack.h"
#include "block.h"
#include "dictionary.h"
/* See symtab.h. */
+call_site *
+compunit_symtab::find_call_site (CORE_ADDR pc) const
+{
+ if (m_call_site_htab == nullptr)
+ return nullptr;
+
+ CORE_ADDR delta
+ = this->objfile->section_offsets[COMPUNIT_BLOCK_LINE_SECTION (this)];
+ CORE_ADDR unrelocated_pc = pc - delta;
+
+ struct call_site call_site_local (unrelocated_pc, nullptr, nullptr);
+ void **slot
+ = htab_find_slot (m_call_site_htab, &call_site_local, NO_INSERT);
+ if (slot == nullptr)
+ return nullptr;
+
+ return (call_site *) *slot;
+}
+
+/* See symtab.h. */
+
+void
+compunit_symtab::set_call_site_htab (htab_t call_site_htab)
+{
+ gdb_assert (m_call_site_htab == nullptr);
+ m_call_site_htab = call_site_htab;
+}
+
+/* See symtab.h. */
+
struct symtab *
compunit_primary_filetab (const struct compunit_symtab *cust)
{
for (objfile *objfile : current_program_space->objfiles ())
{
- if (objfile->sf
- && objfile->sf->qf->map_symtabs_matching_filename (objfile,
- name,
- real_path.get (),
- callback))
+ if (objfile->map_symtabs_matching_filename (name, real_path.get (),
+ callback))
return;
}
}
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)? */
else if (physname[0] == 't' || physname[0] == 'Q')
{
/* The physname for template and qualified methods already includes
- the class name. */
+ the class name. */
xsnprintf (buf, sizeof (buf), "__%s%s", const_prefix, volatile_prefix);
newname = NULL;
len = 0;
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;
}
\f
|| language == language_objc
|| language == language_fortran)
{
- symbol_set_demangled_name (this, NULL, obstack);
+ set_demangled_name (NULL, obstack);
}
else if (language == language_ada)
{
/* See symtab.h */
-char *
+gdb::unique_xmalloc_ptr<char>
symbol_find_demangled_name (struct general_symbol_info *gsymbol,
const char *mangled)
{
- char *demangled = NULL;
+ gdb::unique_xmalloc_ptr<char> demangled;
int i;
if (gsymbol->language () == language_unknown)
{
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;
}
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->m_language = l;
return demangled;
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. */
+ we can save some space by not storing the demangled name. */
if (!copy_name)
m_name = linkage_name.data ();
else
m_name = obstack_strndup (&per_bfd->storage_obstack,
linkage_name.data (),
linkage_name.length ());
- symbol_set_demangled_name (this, NULL, &per_bfd->storage_obstack);
+ set_demangled_name (NULL, &per_bfd->storage_obstack);
return;
}
if (!hash.has_value ())
hash = hash_demangled_name_entry (&entry);
slot = ((struct demangled_name_entry **)
- htab_find_slot_with_hash (per_bfd->demangled_names_hash.get (),
+ 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
|| (language () == language_go && (*slot)->demangled == nullptr))
{
/* 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. */
+ 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)
{
linkage_name_copy = linkage_name;
if (demangled_name.get () == nullptr)
- demangled_name.reset
- (symbol_find_demangled_name (this, linkage_name_copy.data ()));
+ demangled_name
+ = 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
m_language = (*slot)->language;
m_name = (*slot)->mangled.data ();
- symbol_set_demangled_name (this, (*slot)->demangled.get (),
- &per_bfd->storage_obstack);
+ set_demangled_name ((*slot)->demangled.get (), &per_bfd->storage_obstack);
}
/* See symtab.h. */
case language_go:
case language_objc:
case language_fortran:
- if (symbol_get_demangled_name (this) != NULL)
- return symbol_get_demangled_name (this);
+ case language_rust:
+ if (language_specific.demangled_name != nullptr)
+ return language_specific.demangled_name;
break;
case language_ada:
return ada_decode_symbol (this);
case language_go:
case language_objc:
case language_fortran:
- dem_name = symbol_get_demangled_name (this);
+ case language_rust:
+ dem_name = language_specific.demangled_name;
break;
case language_ada:
dem_name = ada_decode_symbol (this);
/* See symtab.h. */
+struct obj_section *
+general_symbol_info::obj_section (const struct objfile *objfile) const
+{
+ if (section_index () >= 0)
+ return &objfile->sections[section_index ()];
+ return nullptr;
+}
+
+/* See symtab.h. */
+
bool
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);
+ = language_def (gsymbol->language ())->get_symbol_name_matcher (name);
return name_match (gsymbol->search_name (), name, NULL);
}
for (objfile *objfile : current_program_space->objfiles ())
{
- struct compunit_symtab *cust = NULL;
-
- if (objfile->sf)
- cust = objfile->sf->qf->find_pc_sect_compunit_symtab (objfile, msymbol,
- pc, section, 0);
+ struct compunit_symtab *cust
+ = objfile->find_pc_sect_compunit_symtab (msymbol, pc, section, 0);
if (cust)
return;
}
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);
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;
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);
}
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;
/* If the cache hasn't been created yet, avoid creating one. */
cache = symbol_cache_key.get (pspace);
if (cache == NULL)
- printf_filtered (" empty, no stats available\n");
+ printf_filtered (" empty, no stats available\n");
else
symbol_cache_stats (cache);
}
msym = lookup_minimal_symbol_by_pc_name (addr, ginfo->linkage_name (),
objfile);
if (msym)
- ginfo->section = MSYMBOL_SECTION (msym);
+ ginfo->set_section_index (msym->section_index ());
else
{
/* Static, function-local variables do appear in the linker
if (fallback == -1)
fallback = idx;
- if (obj_section_addr (s) - offset <= addr
- && addr < obj_section_endaddr (s) - offset)
+ if (s->addr () - offset <= addr && addr < s->endaddr () - offset)
{
- ginfo->section = idx;
+ ginfo->set_section_index (idx);
return;
}
}
section. If there is no allocated section, then it hardly
matters what we pick, so just pick zero. */
if (fallback == -1)
- ginfo->section = 0;
+ ginfo->set_section_index (0);
else
- ginfo->section = fallback;
+ ginfo->set_section_index (fallback);
}
}
if (objfile == NULL)
objfile = symbol_objfile (sym);
- if (SYMBOL_OBJ_SECTION (objfile, sym))
+ if (sym->obj_section (objfile) != nullptr)
return sym;
/* We should have an objfile by now. */
lookup, so we can always binary search. */
if (lang == language_cplus)
{
- char *demangled_name = gdb_demangle (name, DMGL_ANSI | DMGL_PARAMS);
+ gdb::unique_xmalloc_ptr<char> demangled_name
+ = gdb_demangle (name, DMGL_ANSI | DMGL_PARAMS);
if (demangled_name != NULL)
- return storage.set_malloc_ptr (demangled_name);
+ return storage.set_malloc_ptr (std::move (demangled_name));
/* 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<char> canon = cp_canonicalize_string (name);
+ if (canon != nullptr)
+ return storage.set_malloc_ptr (std::move (canon));
}
else if (lang == language_d)
{
- char *demangled_name = d_demangle (name, 0);
+ gdb::unique_xmalloc_ptr<char> demangled_name = d_demangle (name, 0);
if (demangled_name != NULL)
- return storage.set_malloc_ptr (demangled_name);
+ return storage.set_malloc_ptr (std::move (demangled_name));
}
else if (lang == language_go)
{
- char *demangled_name = go_demangle (name, 0);
+ gdb::unique_xmalloc_ptr<char> demangled_name
+ = language_def (language_go)->demangle_symbol (name, 0);
if (demangled_name != NULL)
- return storage.set_malloc_ptr (demangled_name);
+ return storage.set_malloc_ptr (std::move (demangled_name));
}
return name;
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.
lookup_language_this (const struct language_defn *lang,
const struct block *block)
{
- if (lang->la_name_of_this == NULL || block == NULL)
+ if (lang->name_of_this () == NULL || block == NULL)
return {};
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))",
- lang->la_name, host_address_to_string (block),
+ lang->name (), host_address_to_string (block),
objfile_debug_name (objfile));
}
{
struct symbol *sym;
- sym = block_lookup_symbol (block, lang->la_name_of_this,
+ sym = block_lookup_symbol (block, lang->name_of_this (),
symbol_name_match_type::SEARCH_NAME,
VAR_DOMAIN);
if (sym != NULL)
/* 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);
+ const char *t_field_name = type->field (i).name ();
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;
}
}
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",
/* 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->is_pointer_or_reference ())
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);
+ langdef->name_of_this ());
if (check_field (t, name, is_a_field_of_this))
{
/* Now do whatever is appropriate for LANGUAGE to look
up static and global variables. */
- result = langdef->la_lookup_symbol_nonlocal (langdef, name, block, domain);
+ result = langdef->lookup_symbol_nonlocal (name, block, domain);
if (result.symbol != NULL)
{
if (symbol_lookup_debug)
return (struct block_symbol) {sym, block};
if (language == language_cplus || language == language_fortran)
- {
- struct block_symbol blocksym
+ {
+ struct block_symbol blocksym
= cp_lookup_symbol_imports_or_template (scope, name, block,
domain);
- if (blocksym.symbol != NULL)
- return blocksym;
- }
+ if (blocksym.symbol != NULL)
+ return blocksym;
+ }
if (BLOCK_FUNCTION (block) != NULL && block_inlined_p (block))
break;
/* 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,
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)",
for (objfile *objfile : main_objfile->separate_debug_objfiles ())
{
struct block_symbol result
- = lookup_symbol_in_objfile (objfile, block_index, name, domain);
+ = lookup_symbol_in_objfile (objfile, block_index, name, domain);
if (result.symbol != nullptr)
return result;
name, domain_name (domain));
}
+ struct block_symbol other;
+ other.symbol = NULL;
for (compunit_symtab *cust : objfile->compunits ())
{
const struct blockvector *bv;
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)
const struct block *block;
struct block_symbol result;
- if (!objfile->sf)
- return {};
-
if (symbol_lookup_debug > 1)
{
fprintf_unfiltered (gdb_stdlog,
name, domain_name (domain));
}
- cust = objfile->sf->qf->lookup_symbol (objfile, block_index, name, domain);
+ cust = objfile->lookup_symbol (block_index, name, domain);
if (cust == NULL)
{
if (symbol_lookup_debug > 1)
return result;
}
-/* See symtab.h. */
+/* See language.h. */
struct block_symbol
-basic_lookup_symbol_nonlocal (const struct language_defn *langdef,
- const char *name,
- const struct block *block,
- const domain_enum domain)
+language_defn::lookup_symbol_nonlocal (const char *name,
+ const struct block *block,
+ const domain_enum domain) const
{
struct block_symbol result;
gdbarch = target_gdbarch ();
else
gdbarch = block_gdbarch (block);
- result.symbol = language_lookup_primitive_type_as_symbol (langdef,
+ result.symbol = language_lookup_primitive_type_as_symbol (this,
gdbarch, name);
result.block = NULL;
if (result.symbol != NULL)
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),"
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;
+ = objfile->lookup_global_symbol_language (name, domain, &symbol_found_p);
+ if (symbol_found_p)
+ return lang;
}
return language_unknown;
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;
}
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
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
const struct block *block;
struct symbol *sym;
- if (!objfile->sf)
- return NULL;
- cust = objfile->sf->qf->lookup_symbol (objfile, block_index, name,
- STRUCT_DOMAIN);
+ cust = objfile->lookup_symbol (block_index, name, STRUCT_DOMAIN);
if (cust == NULL)
return NULL;
find_pc_sect_compunit_symtab (CORE_ADDR pc, struct obj_section *section)
{
struct compunit_symtab *best_cust = NULL;
- CORE_ADDR distance = 0;
+ CORE_ADDR best_cust_range = 0;
struct bound_minimal_symbol msymbol;
/* If we know that this is not a text address, return failure. This is
{
for (compunit_symtab *cust : obj_file->compunits ())
{
- const struct block *b;
- const struct blockvector *bv;
+ const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (cust);
+ const struct block *global_block
+ = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ CORE_ADDR start = BLOCK_START (global_block);
+ CORE_ADDR end = BLOCK_END (global_block);
+ bool in_range_p = start <= pc && pc < end;
+ if (!in_range_p)
+ continue;
+
+ if (BLOCKVECTOR_MAP (bv))
+ {
+ if (addrmap_find (BLOCKVECTOR_MAP (bv), pc) == nullptr)
+ continue;
- bv = COMPUNIT_BLOCKVECTOR (cust);
- b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ return cust;
+ }
- if (BLOCK_START (b) <= pc
- && BLOCK_END (b) > pc
- && (distance == 0
- || BLOCK_END (b) - BLOCK_START (b) < distance))
+ CORE_ADDR range = end - start;
+ if (best_cust != nullptr
+ && range >= best_cust_range)
+ /* Cust doesn't have a smaller range than best_cust, skip it. */
+ continue;
+
+ /* For an objfile that has its functions reordered,
+ find_pc_psymtab will find the proper partial symbol table
+ and we simply return its corresponding symtab. */
+ /* In order to better support objfiles that contain both
+ stabs and coff debugging info, we continue on if a psymtab
+ can't be found. */
+ if ((obj_file->flags & OBJF_REORDERED) != 0)
{
- /* For an objfile that has its functions reordered,
- find_pc_psymtab will find the proper partial symbol table
- and we simply return its corresponding symtab. */
- /* In order to better support objfiles that contain both
- stabs and coff debugging info, we continue on if a psymtab
- can't be found. */
- if ((obj_file->flags & OBJF_REORDERED) && obj_file->sf)
- {
- struct compunit_symtab *result;
-
- result
- = obj_file->sf->qf->find_pc_sect_compunit_symtab (obj_file,
- msymbol,
- pc,
- section,
- 0);
- if (result != NULL)
- return result;
- }
- if (section != 0)
- {
- struct block_iterator iter;
- struct symbol *sym = NULL;
+ struct compunit_symtab *result;
+
+ result
+ = obj_file->find_pc_sect_compunit_symtab (msymbol,
+ pc,
+ section,
+ 0);
+ if (result != NULL)
+ return result;
+ }
+
+ if (section != 0)
+ {
+ struct symbol *sym = NULL;
+ struct block_iterator iter;
+ for (int b_index = GLOBAL_BLOCK;
+ b_index <= STATIC_BLOCK && sym == NULL;
+ ++b_index)
+ {
+ const struct block *b = BLOCKVECTOR_BLOCK (bv, b_index);
ALL_BLOCK_SYMBOLS (b, iter, sym)
{
fixup_symbol_section (sym, obj_file);
- if (matching_obj_sections (SYMBOL_OBJ_SECTION (obj_file,
- sym),
+ if (matching_obj_sections (sym->obj_section (obj_file),
section))
break;
}
- if (sym == NULL)
- continue; /* No symbol in this symtab matches
- section. */
}
- distance = BLOCK_END (b) - BLOCK_START (b);
- best_cust = cust;
+ if (sym == NULL)
+ continue; /* No symbol in this symtab matches
+ section. */
}
+
+ /* Cust is best found sofar, save it. */
+ best_cust = cust;
+ best_cust_range = range;
}
}
for (objfile *objf : current_program_space->objfiles ())
{
- struct compunit_symtab *result;
-
- if (!objf->sf)
- continue;
- result = objf->sf->qf->find_pc_sect_compunit_symtab (objf,
- msymbol,
- pc, section,
- 1);
+ struct compunit_symtab *result
+ = objf->find_pc_sect_compunit_symtab (msymbol, pc, section, 1);
if (result != NULL)
return result;
}
struct symbol *
find_symbol_at_address (CORE_ADDR address)
{
- for (objfile *objfile : current_program_space->objfiles ())
+ /* A helper function to search a given symtab for a symbol matching
+ ADDR. */
+ auto search_symtab = [] (compunit_symtab *symtab, CORE_ADDR addr) -> symbol *
{
- if (objfile->sf == NULL
- || objfile->sf->qf->find_compunit_symtab_by_address == NULL)
- continue;
+ const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (symtab);
- struct compunit_symtab *symtab
- = objfile->sf->qf->find_compunit_symtab_by_address (objfile, address);
- if (symtab != NULL)
+ for (int i = GLOBAL_BLOCK; i <= STATIC_BLOCK; ++i)
{
- const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (symtab);
+ const struct block *b = BLOCKVECTOR_BLOCK (bv, i);
+ struct block_iterator iter;
+ struct symbol *sym;
- for (int i = GLOBAL_BLOCK; i <= STATIC_BLOCK; ++i)
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
{
- const struct block *b = BLOCKVECTOR_BLOCK (bv, i);
- struct block_iterator iter;
- struct symbol *sym;
+ if (SYMBOL_CLASS (sym) == LOC_STATIC
+ && SYMBOL_VALUE_ADDRESS (sym) == addr)
+ return sym;
+ }
+ }
+ return nullptr;
+ };
- ALL_BLOCK_SYMBOLS (b, iter, sym)
- {
- if (SYMBOL_CLASS (sym) == LOC_STATIC
- && SYMBOL_VALUE_ADDRESS (sym) == address)
- return sym;
- }
+ for (objfile *objfile : current_program_space->objfiles ())
+ {
+ /* If this objfile was read with -readnow, then we need to
+ search the symtabs directly. */
+ if ((objfile->flags & OBJF_READNOW) != 0)
+ {
+ for (compunit_symtab *symtab : objfile->compunits ())
+ {
+ struct symbol *sym = search_symtab (symtab, address);
+ if (sym != nullptr)
+ return sym;
+ }
+ }
+ else
+ {
+ struct compunit_symtab *symtab
+ = objfile->find_compunit_symtab_by_address (address);
+ if (symtab != NULL)
+ {
+ struct symbol *sym = search_symtab (symtab, address);
+ if (sym != nullptr)
+ return sym;
}
}
}
fatally. */
if (BMSYMBOL_VALUE_ADDRESS (mfunsym) == pc)
internal_error (__FILE__, __LINE__,
- _("Infinite recursion detected in find_pc_sect_line;"
+ _("Infinite recursion detected in find_pc_sect_line;"
"please file a bug report"));
return find_pc_line (BMSYMBOL_VALUE_ADDRESS (mfunsym), 0);
item = l->item; /* Get first line info. */
/* Is this file's first line closer than the first lines of other files?
- If so, record this file, and its first line, as best alternate. */
+ If so, record this file, and its first line, as best alternate. */
if (item->pc > pc && (!alt || item->pc < alt->pc))
alt = item;
struct linetable_entry *last = item + len;
item = std::upper_bound (first, last, pc, pc_compare);
if (item != first)
- {
- /* Found a matching item. Skip backwards over any end of
- sequence markers. */
- for (prev = item - 1; prev->line == 0 && prev != first; prev--)
- /* Nothing. */;
- }
+ prev = item - 1; /* Found a matching item. */
/* 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
- (pc >= start of the last line), then prev == item. If pc < start of
- the first line, prev will not be set. */
+ item points at the next line. If we ran off the end of the linetable
+ (pc >= start of the last line), then prev == item. If pc < start of
+ the first line, prev will not be set. */
/* Is this file's best line closer than the best in the other files?
- If so, record this file, and its best line, as best so far. Don't
- save prev if it represents the end of a function (i.e. line number
- 0) instead of a real line. */
+ If so, record this file, and its best line, as best so far. Don't
+ save prev if it represents the end of a function (i.e. line number
+ 0) instead of a real line. */
if (prev && prev->line && (!best || prev->pc > best->pc))
{
struct obj_section *section;
section = find_pc_overlay (pc);
- if (pc_in_unmapped_range (pc, section))
- pc = overlay_mapped_address (pc, section);
- return find_pc_sect_line (pc, section, notcurrent);
+ if (!pc_in_unmapped_range (pc, section))
+ return find_pc_sect_line (pc, section, notcurrent);
+
+ /* If the original PC was an unmapped address then we translate this to a
+ mapped address in order to lookup the sal. However, as the user
+ passed us an unmapped address it makes more sense to return a result
+ that has the pc and end fields translated to unmapped addresses. */
+ pc = overlay_mapped_address (pc, section);
+ symtab_and_line sal = find_pc_sect_line (pc, section, notcurrent);
+ sal.pc = overlay_unmapped_address (sal.pc, section);
+ sal.end = overlay_unmapped_address (sal.end, section);
+ return sal;
}
/* See symtab.h. */
if (best_index < 0 || !exact)
{
/* Didn't find an exact match. So we better keep looking for
- another symtab with the same name. In the case of xcoff,
- multiple csects for one source file (produced by IBM's FORTRAN
- compiler) produce multiple symtabs (this is unavoidable
- assuming csects can be at arbitrary places in memory and that
- the GLOBAL_BLOCK of a symtab has a begin and end address). */
+ another symtab with the same name. In the case of xcoff,
+ multiple csects for one source file (produced by IBM's FORTRAN
+ compiler) produce multiple symtabs (this is unavoidable
+ assuming csects can be at arbitrary places in memory and that
+ the GLOBAL_BLOCK of a symtab has a begin and end address). */
/* BEST is the smallest linenumber > LINE so far seen,
- or 0 if none has been seen so far.
- BEST_INDEX and BEST_LINETABLE identify the item for it. */
+ or 0 if none has been seen so far.
+ BEST_INDEX and BEST_LINETABLE identify the item for it. */
int best;
if (best_index >= 0)
best = 0;
for (objfile *objfile : current_program_space->objfiles ())
- {
- if (objfile->sf)
- objfile->sf->qf->expand_symtabs_with_fullname
- (objfile, symtab_to_fullname (sym_tab));
- }
+ objfile->expand_symtabs_with_fullname (symtab_to_fullname (sym_tab));
for (objfile *objfile : current_program_space->objfiles ())
{
&& (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))
fixup_symbol_section (sym, NULL);
symtab_and_line sal
= find_function_start_sal_1 (BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym)),
- SYMBOL_OBJ_SECTION (symbol_objfile (sym), sym),
+ sym->obj_section (symbol_objfile (sym)),
funfirstline);
sal.symbol = sym;
return sal;
objfile = symbol_objfile (sym);
pc = BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym));
- section = SYMBOL_OBJ_SECTION (objfile, sym);
+ section = sym->obj_section (objfile);
name = sym->linkage_name ();
}
else
{
struct bound_minimal_symbol msymbol
- = lookup_minimal_symbol_by_pc_section (sal->pc, sal->section);
+ = lookup_minimal_symbol_by_pc_section (sal->pc, sal->section);
if (msymbol.minsym == NULL)
return;
objfile = msymbol.objfile;
pc = BMSYMBOL_VALUE_ADDRESS (msymbol);
- section = MSYMBOL_OBJ_SECTION (objfile, msymbol.minsym);
+ section = msymbol.minsym->obj_section (objfile);
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
/* Skip "first line" of function (which is actually its prologue). */
pc += gdbarch_deprecated_function_start_offset (gdbarch);
if (gdbarch_skip_entrypoint_p (gdbarch))
- pc = gdbarch_skip_entrypoint (gdbarch, pc);
+ pc = gdbarch_skip_entrypoint (gdbarch, pc);
if (skip)
pc = gdbarch_skip_prologue_noexcept (gdbarch, pc);
}
\f
-/* What part to match in a file name. */
+/* See class declaration. */
-struct filename_partial_match_opts
+info_sources_filter::info_sources_filter (match_on match_type,
+ const char *regexp)
+ : m_match_type (match_type),
+ m_regexp (regexp)
{
- /* Only match the directory name part. */
- bool dirname = false;
+ /* Setup the compiled regular expression M_C_REGEXP based on M_REGEXP. */
+ if (m_regexp != nullptr && *m_regexp != '\0')
+ {
+ gdb_assert (m_regexp != nullptr);
- /* Only match the basename part. */
- bool basename = false;
-};
+ int cflags = REG_NOSUB;
+#ifdef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
+ cflags |= REG_ICASE;
+#endif
+ m_c_regexp.emplace (m_regexp, cflags, _("Invalid regexp"));
+ }
+}
+
+/* See class declaration. */
+
+bool
+info_sources_filter::matches (const char *fullname) const
+{
+ /* Does it match regexp? */
+ if (m_c_regexp.has_value ())
+ {
+ const char *to_match;
+ std::string dirname;
+
+ switch (m_match_type)
+ {
+ case match_on::DIRNAME:
+ dirname = ldirname (fullname);
+ to_match = dirname.c_str ();
+ break;
+ case match_on::BASENAME:
+ to_match = lbasename (fullname);
+ break;
+ case match_on::FULLNAME:
+ to_match = fullname;
+ break;
+ default:
+ gdb_assert_not_reached ("bad m_match_type");
+ }
+
+ if (m_c_regexp->exec (to_match, 0, NULL, 0) != 0)
+ return false;
+ }
-/* Data structure to maintain printing state for output_source_filename. */
+ return true;
+}
+
+/* Data structure to maintain the state used for printing the results of
+ the 'info sources' command. */
struct output_source_filename_data
{
- /* Output only filenames matching REGEXP. */
- std::string regexp;
- gdb::optional<compiled_regex> c_regexp;
- /* Possibly only match a part of the filename. */
- filename_partial_match_opts partial_match;
+ /* Create an object for displaying the results of the 'info sources'
+ command to UIOUT. FILTER must remain valid and unchanged for the
+ lifetime of this object as this object retains a reference to FILTER. */
+ output_source_filename_data (struct ui_out *uiout,
+ const info_sources_filter &filter)
+ : m_filter (filter),
+ m_uiout (uiout)
+ { /* Nothing. */ }
+ DISABLE_COPY_AND_ASSIGN (output_source_filename_data);
- /* Cache of what we've seen so far. */
- struct filename_seen_cache *filename_seen_cache;
+ /* Reset enough state of this object so we can match against a new set of
+ files. The existing regular expression is retained though. */
+ void reset_output ()
+ {
+ m_first = true;
+ m_filename_seen_cache.clear ();
+ }
+
+ /* Worker for sources_info, outputs the file name formatted for either
+ cli or mi (based on the current_uiout). In cli mode displays
+ FULLNAME with a comma separating this name from any previously
+ printed name (line breaks are added at the comma). In MI mode
+ outputs a tuple containing DISP_NAME (the files display name),
+ FULLNAME, and EXPANDED_P (true when this file is from a fully
+ expanded symtab, otherwise false). */
+ void output (const char *disp_name, const char *fullname, bool expanded_p);
+
+ /* An overload suitable for use as a callback to
+ quick_symbol_functions::map_symbol_filenames. */
+ void operator() (const char *filename, const char *fullname)
+ {
+ /* The false here indicates that this file is from an unexpanded
+ symtab. */
+ output (filename, fullname, false);
+ }
+
+ /* Return true if at least one filename has been printed (after a call to
+ output) since either this object was created, or the last call to
+ reset_output. */
+ bool printed_filename_p () const
+ {
+ return !m_first;
+ }
+
+private:
/* Flag of whether we're printing the first one. */
- int first;
+ bool m_first = true;
+
+ /* Cache of what we've seen so far. */
+ filename_seen_cache m_filename_seen_cache;
+
+ /* How source filename should be filtered. */
+ const info_sources_filter &m_filter;
+
+ /* The object to which output is sent. */
+ struct ui_out *m_uiout;
};
-/* Slave routine for sources_info. Force line breaks at ,'s.
- NAME is the name to print.
- DATA contains the state for printing and watching for duplicates. */
+/* See comment in class declaration above. */
-static void
-output_source_filename (const char *name,
- struct output_source_filename_data *data)
+void
+output_source_filename_data::output (const char *disp_name,
+ const char *fullname,
+ bool expanded_p)
{
/* Since a single source file can result in several partial symbol
tables, we need to avoid printing it more than once. Note: if
situation. I'm not sure whether this can also happen for
symtabs; it doesn't hurt to check. */
- /* Was NAME already seen? */
- if (data->filename_seen_cache->seen (name))
- {
- /* Yes; don't print it again. */
- return;
- }
-
- /* Does it match data->regexp? */
- if (data->c_regexp.has_value ())
- {
- const char *to_match;
- std::string dirname;
+ /* Was NAME already seen? If so, then don't print it again. */
+ if (m_filename_seen_cache.seen (fullname))
+ return;
- if (data->partial_match.dirname)
- {
- dirname = ldirname (name);
- to_match = dirname.c_str ();
- }
- else if (data->partial_match.basename)
- to_match = lbasename (name);
- else
- to_match = name;
+ /* If the filter rejects this file then don't print it. */
+ if (!m_filter.matches (fullname))
+ return;
- if (data->c_regexp->exec (to_match, 0, NULL, 0) != 0)
- return;
- }
+ ui_out_emit_tuple ui_emitter (m_uiout, nullptr);
/* Print it and reset *FIRST. */
- if (! data->first)
- printf_filtered (", ");
- data->first = 0;
+ if (!m_first)
+ m_uiout->text (", ");
+ m_first = false;
wrap_here ("");
- fputs_styled (name, file_name_style.style (), gdb_stdout);
+ if (m_uiout->is_mi_like_p ())
+ {
+ m_uiout->field_string ("file", disp_name, file_name_style.style ());
+ if (fullname != nullptr)
+ m_uiout->field_string ("fullname", fullname,
+ file_name_style.style ());
+ m_uiout->field_string ("debug-fully-read",
+ (expanded_p ? "true" : "false"));
+ }
+ else
+ {
+ if (fullname == nullptr)
+ fullname = disp_name;
+ m_uiout->field_string ("fullname", fullname,
+ file_name_style.style ());
+ }
}
-/* A callback for map_partial_symbol_filenames. */
+/* For the 'info sources' command, what part of the file names should we be
+ matching the user supplied regular expression against? */
-static void
-output_partial_symbol_filename (const char *filename, const char *fullname,
- void *data)
+struct filename_partial_match_opts
{
- output_source_filename (fullname ? fullname : filename,
- (struct output_source_filename_data *) data);
-}
+ /* Only match the directory name part. */
+ bool dirname = false;
+
+ /* Only match the basename part. */
+ bool basename = false;
+};
using isrc_flag_option_def
= gdb::option::flag_option_def<filename_partial_match_opts>;
return {{info_sources_option_defs}, isrc_opts};
}
-/* Prints the header message for the source files that will be printed
- with the matching info present in DATA. SYMBOL_MSG is a message
- that tells what will or has been done with the symbols of the
- matching source files. */
-
-static void
-print_info_sources_header (const char *symbol_msg,
- const struct output_source_filename_data *data)
-{
- puts_filtered (symbol_msg);
- if (!data->regexp.empty ())
- {
- if (data->partial_match.dirname)
- printf_filtered (_("(dirname matching regular expression \"%s\")"),
- data->regexp.c_str ());
- else if (data->partial_match.basename)
- printf_filtered (_("(basename matching regular expression \"%s\")"),
- data->regexp.c_str ());
- else
- printf_filtered (_("(filename matching regular expression \"%s\")"),
- data->regexp.c_str ());
- }
- puts_filtered ("\n");
-}
-
/* Completer for "info sources". */
static void
return;
}
-static void
-info_sources_command (const char *args, int from_tty)
-{
- struct output_source_filename_data data;
-
- if (!have_full_symbols () && !have_partial_symbols ())
- {
- error (_("No symbol table is loaded. Use the \"file\" command."));
- }
-
- filename_seen_cache filenames_seen;
-
- auto group = make_info_sources_options_def_group (&data.partial_match);
-
- gdb::option::process_options
- (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, group);
-
- if (args != NULL && *args != '\000')
- data.regexp = args;
-
- data.filename_seen_cache = &filenames_seen;
- data.first = 1;
+/* See symtab.h. */
- if (data.partial_match.dirname && data.partial_match.basename)
- error (_("You cannot give both -basename and -dirname to 'info sources'."));
- if ((data.partial_match.dirname || data.partial_match.basename)
- && data.regexp.empty ())
- error (_("Missing REGEXP for 'info sources'."));
+void
+info_sources_worker (struct ui_out *uiout,
+ bool group_by_objfile,
+ const info_sources_filter &filter)
+{
+ output_source_filename_data data (uiout, filter);
- if (data.regexp.empty ())
- data.c_regexp.reset ();
- else
- {
- int cflags = REG_NOSUB;
-#ifdef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
- cflags |= REG_ICASE;
-#endif
- data.c_regexp.emplace (data.regexp.c_str (), cflags,
- _("Invalid regexp"));
- }
+ ui_out_emit_list results_emitter (uiout, "files");
+ gdb::optional<ui_out_emit_tuple> output_tuple;
+ gdb::optional<ui_out_emit_list> sources_list;
- print_info_sources_header
- (_("Source files for which symbols have been read in:\n"), &data);
+ gdb_assert (group_by_objfile || uiout->is_mi_like_p ());
for (objfile *objfile : current_program_space->objfiles ())
{
+ if (group_by_objfile)
+ {
+ output_tuple.emplace (uiout, nullptr);
+ uiout->field_string ("filename", objfile_name (objfile));
+ uiout->text (":\n");
+ bool debug_fully_readin = !objfile->has_unexpanded_symtabs ();
+ if (uiout->is_mi_like_p ())
+ {
+ const char *debug_info_state;
+ if (objfile_has_symbols (objfile))
+ {
+ if (debug_fully_readin)
+ debug_info_state = "fully-read";
+ else
+ debug_info_state = "partially-read";
+ }
+ else
+ debug_info_state = "none";
+ current_uiout->field_string ("debug-info", debug_info_state);
+ }
+ else
+ {
+ if (!debug_fully_readin)
+ uiout->text ("(Full debug information has not yet been read "
+ "for this file.)\n");
+ if (!objfile_has_symbols (objfile))
+ uiout->text ("(Objfile has no debug information.)\n");
+ uiout->text ("\n");
+ }
+ sources_list.emplace (uiout, "sources");
+ }
+
for (compunit_symtab *cu : objfile->compunits ())
{
for (symtab *s : compunit_filetabs (cu))
{
+ const char *file = symtab_to_filename_for_display (s);
const char *fullname = symtab_to_fullname (s);
-
- output_source_filename (fullname, &data);
+ data.output (file, fullname, true);
}
}
+
+ if (group_by_objfile)
+ {
+ objfile->map_symbol_filenames (data, true /* need_fullname */);
+ if (data.printed_filename_p ())
+ uiout->text ("\n\n");
+ data.reset_output ();
+ sources_list.reset ();
+ output_tuple.reset ();
+ }
+ }
+
+ if (!group_by_objfile)
+ {
+ data.reset_output ();
+ map_symbol_filenames (data, true /*need_fullname*/);
}
- printf_filtered ("\n\n");
+}
+
+/* Implement the 'info sources' command. */
+
+static void
+info_sources_command (const char *args, int from_tty)
+{
+ if (!have_full_symbols () && !have_partial_symbols ())
+ error (_("No symbol table is loaded. Use the \"file\" command."));
+
+ filename_partial_match_opts match_opts;
+ auto group = make_info_sources_options_def_group (&match_opts);
+ gdb::option::process_options
+ (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, group);
+
+ if (match_opts.dirname && match_opts.basename)
+ error (_("You cannot give both -basename and -dirname to 'info sources'."));
+
+ const char *regex = nullptr;
+ if (args != NULL && *args != '\000')
+ regex = args;
+
+ if ((match_opts.dirname || match_opts.basename) && regex == nullptr)
+ error (_("Missing REGEXP for 'info sources'."));
- print_info_sources_header
- (_("Source files for which symbols will be read in on demand:\n"), &data);
+ info_sources_filter::match_on match_type;
+ if (match_opts.dirname)
+ match_type = info_sources_filter::match_on::DIRNAME;
+ else if (match_opts.basename)
+ match_type = info_sources_filter::match_on::BASENAME;
+ else
+ match_type = info_sources_filter::match_on::FULLNAME;
- filenames_seen.clear ();
- data.first = 1;
- map_symbol_filenames (output_partial_symbol_filename, &data,
- 1 /*need_fullname*/);
- printf_filtered ("\n");
+ info_sources_filter filter (match_type, regex);
+ info_sources_worker (current_uiout, true, filter);
}
/* Compare FILE against all the entries of FILENAMES. If BASENAMES is
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);
+ auto do_file_match = [&] (const char *filename, bool basenames)
+ {
+ return file_matches (filename, filenames, basenames);
+ };
+ gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher = nullptr;
+ if (!filenames.empty ())
+ file_matcher = do_file_match;
+
+ objfile->expand_symtabs_matching
+ (file_matcher,
+ &lookup_name_info::match_any (),
+ [&] (const char *symname)
+ {
+ return (!preg.has_value ()
+ || preg->exec (symname, 0, NULL, 0) == 0);
+ },
+ NULL,
+ SEARCH_GLOBAL_BLOCK | SEARCH_STATIC_BLOCK,
+ UNDEF_DOMAIN,
+ 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
members. We only want to skip enums
here. */
&& !(SYMBOL_CLASS (sym) == LOC_CONST
- && (TYPE_CODE (SYMBOL_TYPE (sym))
+ && (SYMBOL_TYPE (sym)->code ()
== TYPE_CODE_ENUM))
&& (!treg.has_value ()
|| treg_matches_sym_type_name (*treg, sym)))
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 <TYPENAME> or <OPERATOR>. */
+ This is just a courtesy to make the matching less sensitive
+ to how many spaces the user leaves between 'operator'
+ and <TYPENAME> or <OPERATOR>. */
const char *opend;
const char *opname = operator_chars (symbol_name_regexp, &opend);
if (*opname)
{
int fix = -1; /* -1 means ok; otherwise number of
- spaces needed. */
+ spaces needed. */
if (isalpha (*opname) || *opname == '_' || *opname == '$')
{
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)
+ if (SYMBOL_TYPE (sym)->code () == TYPE_CODE_TYPEDEF)
typedef_print (SYMBOL_TYPE (sym), sym, &tmp_stream);
else
type_print (SYMBOL_TYPE (sym), "", &tmp_stream, -1);
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)
{
bool quiet = false;
bool exclude_minsyms = false;
- char *type_regexp = nullptr;
-
- ~info_vars_funcs_options ()
- {
- xfree (type_regexp);
- }
+ std::string type_regexp;
};
/* The options used by the 'info variables' and 'info functions'
gdb::option::string_option_def<info_vars_funcs_options> {
"t",
- [] (info_vars_funcs_options *opt) { return &opt->type_regexp;
- },
+ [] (info_vars_funcs_options *opt) { return &opt->type_regexp; },
nullptr, /* show_cmd_cb */
nullptr /* set_doc */
}
if (args != nullptr && *args == '\0')
args = nullptr;
- symtab_symbol_info (opts.quiet, opts.exclude_minsyms, args, VARIABLES_DOMAIN,
- opts.type_regexp, from_tty);
+ symtab_symbol_info
+ (opts.quiet, opts.exclude_minsyms, args, VARIABLES_DOMAIN,
+ opts.type_regexp.empty () ? nullptr : opts.type_regexp.c_str (),
+ from_tty);
}
/* Implement the 'info functions' command. */
if (args != nullptr && *args == '\0')
args = nullptr;
- symtab_symbol_info (opts.quiet, opts.exclude_minsyms, args,
- FUNCTIONS_DOMAIN, opts.type_regexp, from_tty);
+ symtab_symbol_info
+ (opts.quiet, opts.exclude_minsyms, args, FUNCTIONS_DOMAIN,
+ opts.type_regexp.empty () ? nullptr : opts.type_regexp.c_str (),
+ from_tty);
}
/* Holds the -q option for the 'info types' command. */
{
const char *colon = strchr (regexp, ':');
+ /* Ignore the colon if it is part of a Windows drive. */
+ if (HAS_DRIVE_SPEC (regexp)
+ && (regexp[2] == '/' || regexp[2] == '\\'))
+ colon = strchr (STRIP_DRIVE_SPEC (regexp), ':');
+
if (colon && *(colon + 1) != ':')
{
int colon_index;
const language_defn *lang = language_def (symbol_language);
symbol_name_matcher_ftype *name_match
- = get_symbol_name_matcher (lang, lookup_name);
+ = lang->get_symbol_name_matcher (lookup_name);
return name_match (symbol_name, lookup_name, &match_res);
}
/* See symtab.h. */
-void
+bool
completion_list_add_name (completion_tracker &tracker,
language symbol_language,
const char *symname,
/* 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
tracker.add_completion (std::move (completion),
&match_res.match_for_lcd, text, word);
}
+
+ return true;
}
/* completion_list_add_name wrapper for struct symbol. */
const lookup_name_info &lookup_name,
const char *text, const char *word)
{
- completion_list_add_name (tracker, sym->language (),
- sym->natural_name (),
- 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
/* 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. */
- std::string str
+ gdb::unique_xmalloc_ptr<char> str
= cp_canonicalize_string_no_typedefs (sym->natural_name ());
- if (!str.empty ())
- tracker.remove_completion (str.c_str ());
+ if (str != nullptr)
+ tracker.remove_completion (str.get ());
}
}
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++)
- if (TYPE_FIELD_NAME (t, j))
+ for (j = TYPE_N_BASECLASSES (t); j < t->num_fields (); j++)
+ if (t->field (j).name ())
completion_list_add_name (tracker, sym->language (),
- TYPE_FIELD_NAME (t, j),
+ t->field (j).name (),
lookup_name, text, word);
}
}
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:
CORE_ADDR msym_addr = MSYMBOL_VALUE_ADDRESS (objfile, minsym);
if (MSYMBOL_TYPE (minsym) == mst_data_gnu_ifunc)
{
- struct gdbarch *gdbarch = get_objfile_arch (objfile);
- msym_addr
- = gdbarch_convert_from_func_ptr_addr (gdbarch,
- msym_addr,
- current_top_target ());
+ struct gdbarch *gdbarch = objfile->arch ();
+ msym_addr = gdbarch_convert_from_func_ptr_addr
+ (gdbarch, msym_addr, current_inferior ()->top_target ());
}
if (msym_addr == address)
{
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);
if (mode == complete_symbol_mode::LINESPEC)
sym_text = text;
else
- {
- const char *p;
- char quote_found;
- const char *quote_pos = NULL;
+ {
+ const char *p;
+ char quote_found;
+ const char *quote_pos = NULL;
- /* First see if this is a quoted string. */
- quote_found = '\0';
- for (p = text; *p != '\0'; ++p)
- {
- if (quote_found != '\0')
- {
- if (*p == quote_found)
- /* Found close quote. */
- quote_found = '\0';
- else if (*p == '\\' && p[1] == quote_found)
- /* A backslash followed by the quote character
- doesn't end the string. */
- ++p;
- }
- else if (*p == '\'' || *p == '"')
- {
- quote_found = *p;
- quote_pos = p;
- }
- }
- if (quote_found == '\'')
- /* A string within single quotes can be a symbol, so complete on it. */
- sym_text = quote_pos + 1;
- else if (quote_found == '"')
- /* A double-quoted string is never a symbol, nor does it make sense
- to complete it any other way. */
- {
- return;
- }
- else
- {
- /* It is not a quoted string. Break it based on the characters
- which are in symbols. */
- while (p > text)
- {
- if (isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0'
- || p[-1] == ':' || strchr (break_on, p[-1]) != NULL)
- --p;
- else
- break;
- }
- sym_text = p;
- }
- }
+ /* First see if this is a quoted string. */
+ quote_found = '\0';
+ for (p = text; *p != '\0'; ++p)
+ {
+ if (quote_found != '\0')
+ {
+ if (*p == quote_found)
+ /* Found close quote. */
+ quote_found = '\0';
+ else if (*p == '\\' && p[1] == quote_found)
+ /* A backslash followed by the quote character
+ doesn't end the string. */
+ ++p;
+ }
+ else if (*p == '\'' || *p == '"')
+ {
+ quote_found = *p;
+ quote_pos = p;
+ }
+ }
+ if (quote_found == '\'')
+ /* A string within single quotes can be a symbol, so complete on it. */
+ sym_text = quote_pos + 1;
+ else if (quote_found == '"')
+ /* A double-quoted string is never a symbol, nor does it make sense
+ to complete it any other way. */
+ {
+ return;
+ }
+ else
+ {
+ /* It is not a quoted string. Break it based on the characters
+ which are in symbols. */
+ while (p > text)
+ {
+ if (isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0'
+ || p[-1] == ':' || strchr (break_on, p[-1]) != NULL)
+ --p;
+ else
+ break;
+ }
+ sym_text = p;
+ }
+ }
lookup_name_info lookup_name (sym_text, name_match_type, true);
add_symtab_completions (symtab,
tracker, mode, lookup_name,
sym_text, word, code);
+ return true;
},
+ SEARCH_GLOBAL_BLOCK | SEARCH_STATIC_BLOCK,
ALL_DOMAIN);
/* Search upwards from currently selected frame (so that we can
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);
}
/* Skip macros if we are completing a struct tag -- arguable but
usually what is expected. */
- if (current_language->la_macro_expansion == macro_expansion_c
+ if (current_language->macro_expansion () == macro_expansion_c
&& code == TYPE_CODE_UNDEF)
{
gdb::unique_xmalloc_ptr<struct macro_scope> scope;
}
}
-void
-default_collect_symbol_completion_matches (completion_tracker &tracker,
- complete_symbol_mode mode,
- symbol_name_match_type name_match_type,
- const char *text, const char *word,
- enum type_code code)
-{
- return default_collect_symbol_completion_matches_break_on (tracker, mode,
- name_match_type,
- text, word, "",
- code);
-}
-
/* Collect all symbols (regardless of class) which begin by matching
TEXT. */
symbol_name_match_type name_match_type,
const char *text, const char *word)
{
- current_language->la_collect_symbol_completion_matches (tracker, mode,
- name_match_type,
- text, word,
- TYPE_CODE_UNDEF);
+ current_language->collect_symbol_completion_matches (tracker, mode,
+ name_match_type,
+ text, word,
+ TYPE_CODE_UNDEF);
}
/* Like collect_symbol_completion_matches, but only collect
gdb_assert (code == TYPE_CODE_UNION
|| code == TYPE_CODE_STRUCT
|| code == TYPE_CODE_ENUM);
- current_language->la_collect_symbol_completion_matches (tracker, mode,
- name_match_type,
- text, word, code);
+ current_language->collect_symbol_completion_matches (tracker, mode,
+ name_match_type,
+ text, word, code);
}
/* Like collect_symbol_completion_matches, but collects a list of
if (mode == complete_symbol_mode::LINESPEC)
sym_text = text;
else
- {
- const char *p;
- char quote_found;
- const char *quote_pos = NULL;
+ {
+ const char *p;
+ char quote_found;
+ const char *quote_pos = NULL;
- /* First see if this is a quoted string. */
- quote_found = '\0';
- for (p = text; *p != '\0'; ++p)
- {
- if (quote_found != '\0')
- {
- if (*p == quote_found)
- /* Found close quote. */
- quote_found = '\0';
- else if (*p == '\\' && p[1] == quote_found)
- /* A backslash followed by the quote character
- doesn't end the string. */
- ++p;
- }
- else if (*p == '\'' || *p == '"')
- {
- quote_found = *p;
- quote_pos = p;
- }
- }
- if (quote_found == '\'')
- /* A string within single quotes can be a symbol, so complete on it. */
- sym_text = quote_pos + 1;
- else if (quote_found == '"')
- /* A double-quoted string is never a symbol, nor does it make sense
- to complete it any other way. */
- {
- return;
- }
- else
- {
- /* Not a quoted string. */
- sym_text = language_search_unquoted_string (text, p);
- }
- }
+ /* First see if this is a quoted string. */
+ quote_found = '\0';
+ for (p = text; *p != '\0'; ++p)
+ {
+ if (quote_found != '\0')
+ {
+ if (*p == quote_found)
+ /* Found close quote. */
+ quote_found = '\0';
+ else if (*p == '\\' && p[1] == quote_found)
+ /* A backslash followed by the quote character
+ doesn't end the string. */
+ ++p;
+ }
+ else if (*p == '\'' || *p == '"')
+ {
+ quote_found = *p;
+ quote_pos = p;
+ }
+ }
+ if (quote_found == '\'')
+ /* A string within single quotes can be a symbol, so complete on it. */
+ sym_text = quote_pos + 1;
+ else if (quote_found == '"')
+ /* A double-quoted string is never a symbol, nor does it make sense
+ to complete it any other way. */
+ {
+ return;
+ }
+ else
+ {
+ /* Not a quoted string. */
+ sym_text = language_search_unquoted_string (text, p);
+ }
+ }
lookup_name_info lookup_name (sym_text, name_match_type, true);
return 0;
}
-/* An object of this type is passed as the user_data argument to
+/* An object of this type is passed as the callback argument to
map_partial_symbol_filenames. */
struct add_partial_filename_data
{
const char *word;
int text_len;
completion_list *list;
+
+ void operator() (const char *filename, const char *fullname);
};
/* A callback for map_partial_symbol_filenames. */
-static void
-maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
- void *user_data)
+void
+add_partial_filename_data::operator() (const char *filename,
+ const char *fullname)
{
- struct add_partial_filename_data *data
- = (struct add_partial_filename_data *) user_data;
-
if (not_interesting_fname (filename))
return;
- if (!data->filename_seen_cache->seen (filename)
- && filename_ncmp (filename, data->text, data->text_len) == 0)
+ if (!filename_seen_cache->seen (filename)
+ && filename_ncmp (filename, text, text_len) == 0)
{
/* This file matches for a completion; add it to the
current list of matches. */
- add_filename_to_list (filename, data->text, data->word, data->list);
+ add_filename_to_list (filename, text, word, list);
}
else
{
const char *base_name = lbasename (filename);
if (base_name != filename
- && !data->filename_seen_cache->seen (base_name)
- && filename_ncmp (base_name, data->text, data->text_len) == 0)
- add_filename_to_list (base_name, data->text, data->word, data->list);
+ && !filename_seen_cache->seen (base_name)
+ && filename_ncmp (base_name, text, text_len) == 0)
+ add_filename_to_list (base_name, text, word, list);
}
}
datum.word = word;
datum.text_len = text_len;
datum.list = &list;
- map_symbol_filenames (maybe_add_partial_symtab_filename, &datum,
- 0 /*need_fullname*/);
+ map_symbol_filenames (datum, false /*need_fullname*/);
return list;
}
"ARM/Thumb C/C++ Compiler, RVCT",
"ARM C/C++ Compiler, RVCT"
};
- int i;
if (producer == NULL)
return false;
- for (i = 0; i < ARRAY_SIZE (arm_idents); i++)
- if (startswith (producer, arm_idents[i]))
+ for (const char *ident : arm_idents)
+ if (startswith (producer, ident))
return true;
return false;
\f
-/* Initialize the symbol SYM, and mark it as being owned by an objfile. */
-
-void
-initialize_objfile_symbol (struct symbol *sym)
-{
- SYMBOL_OBJFILE_OWNED (sym) = 1;
- SYMBOL_SECTION (sym) = -1;
-}
-
-/* Allocate and initialize a new 'struct symbol' on OBJFILE's
- obstack. */
-
-struct symbol *
-allocate_symbol (struct objfile *objfile)
-{
- struct symbol *result = new (&objfile->objfile_obstack) symbol ();
-
- initialize_objfile_symbol (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 = new (&objfile->objfile_obstack) template_symbol ();
- initialize_objfile_symbol (result);
-
- return result;
-}
-
/* See symtab.h. */
struct objfile *
{
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. */
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)
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);
return BMSYMBOL_VALUE_ADDRESS (found);
}
}
- return minsym->value.address + objf->section_offsets[minsym->section];
+ return (minsym->value.address
+ + objf->section_offsets[minsym->section_index ()]);
}
\f
static struct cmd_list_element *info_module_cmdlist = NULL;
-/* Implement the 'info module' command, just displays some help text for
- the available sub-commands. */
-
-static void
-info_module_command (const char *args, int from_tty)
-{
- help_list (info_module_cmdlist, "info module ", class_info, gdb_stdout);
-}
-
/* See symtab.h. */
std::vector<module_symbol_search>
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);
- }
+ std::string type_regexp;
+ std::string module_regexp;
};
/* The options used by 'info module variables' and 'info module functions'
if (args != nullptr && *args == '\0')
args = nullptr;
- info_module_subcommand (opts.quiet, opts.module_regexp, args,
- opts.type_regexp, FUNCTIONS_DOMAIN);
+ info_module_subcommand
+ (opts.quiet,
+ opts.module_regexp.empty () ? nullptr : opts.module_regexp.c_str (), args,
+ opts.type_regexp.empty () ? nullptr : opts.type_regexp.c_str (),
+ FUNCTIONS_DOMAIN);
}
/* Implements the 'info module variables' command. */
if (args != nullptr && *args == '\0')
args = nullptr;
- info_module_subcommand (opts.quiet, opts.module_regexp, args,
- opts.type_regexp, VARIABLES_DOMAIN);
+ info_module_subcommand
+ (opts.quiet,
+ opts.module_regexp.empty () ? nullptr : opts.module_regexp.c_str (), args,
+ opts.type_regexp.empty () ? nullptr : opts.type_regexp.c_str (),
+ VARIABLES_DOMAIN);
}
/* Command completer for 'info module ...' sub-commands. */
REGEXP is given. The optional flag -q disables printing of headers."));
set_cmd_completer_handle_brkchars (c, info_types_command_completer);
- const auto info_sources_opts = make_info_sources_options_def_group (nullptr);
+ const auto info_sources_opts
+ = make_info_sources_options_def_group (nullptr);
static std::string info_sources_help
= gdb::option::build_help (_("\
_("All module names, or those matching REGEXP."));
set_cmd_completer_handle_brkchars (c, info_types_command_completer);
- add_prefix_cmd ("module", class_info, info_module_command, _("\
+ add_basic_prefix_cmd ("module", class_info, _("\
Print information about modules."),
- &info_module_cmdlist, "info module ",
- 0, &infolist);
+ &info_module_cmdlist, 0, &infolist);
c = add_cmd ("functions", class_info, info_module_functions_command, _("\
Display functions arranged by modules.\n\
_("Set a breakpoint for all functions matching REGEXP."));
add_setshow_enum_cmd ("multiple-symbols", no_class,
- multiple_symbols_modes, &multiple_symbols_mode,
- _("\
+ multiple_symbols_modes, &multiple_symbols_mode,
+ _("\
Set how the debugger handles ambiguities in expressions."), _("\
Show how the debugger handles ambiguities in expressions."), _("\
Valid values are \"ask\", \"all\", \"cancel\", and the default is \"all\"."),
- NULL, NULL, &setlist, &showlist);
+ NULL, NULL, &setlist, &showlist);
add_setshow_boolean_cmd ("basenames-may-differ", class_obscure,
&basenames_may_differ, _("\
_("Print symbol cache statistics for each program space."),
&maintenanceprintlist);
- add_cmd ("flush-symbol-cache", class_maintenance,
- maintenance_flush_symbol_cache,
- _("Flush the symbol cache for each program space."),
- &maintenancelist);
-
- gdb::observers::executable_changed.attach (symtab_observer_executable_changed);
- gdb::observers::new_objfile.attach (symtab_new_objfile_observer);
- gdb::observers::free_objfile.attach (symtab_free_objfile_observer);
+ cmd_list_element *maintenance_flush_symbol_cache_cmd
+ = add_cmd ("symbol-cache", class_maintenance,
+ maintenance_flush_symbol_cache,
+ _("Flush the symbol cache for each program space."),
+ &maintenanceflushlist);
+ c = add_alias_cmd ("flush-symbol-cache", maintenance_flush_symbol_cache_cmd,
+ class_maintenance, 0, &maintenancelist);
+ deprecate_cmd (c, "maintenancelist flush symbol-cache");
+
+ gdb::observers::executable_changed.attach (symtab_observer_executable_changed,
+ "symtab");
+ gdb::observers::new_objfile.attach (symtab_new_objfile_observer, "symtab");
+ gdb::observers::free_objfile.attach (symtab_free_objfile_observer, "symtab");
}