Add symbol lookup cache.

gdb/ChangeLog:

	Add symbol lookup cache.
	* NEWS: Document new options and commands.
	* symtab.c (symbol_cache_key): New static global.
	(DEFAULT_SYMBOL_CACHE_SIZE, MAX_SYMBOL_CACHE_SIZE): New macros.
	(SYMBOL_LOOKUP_FAILED): New macro.
	(symbol_cache_slot_state): New enum.
	(block_symbol_cache): New struct.
	(symbol_cache): New struct.
	(new_symbol_cache_size, symbol_cache_size): New static globals.
	(hash_symbol_entry, eq_symbol_entry): New functions.
	(symbol_cache_byte_size, resize_symbol_cache): New functions.
	(make_symbol_cache, free_symbol_cache): New functions.
	(get_symbol_cache, symbol_cache_cleanup): New function.
	(set_symbol_cache_size, set_symbol_cache_size_handler): New functions.
	(symbol_cache_lookup, symbol_cache_clear_slot): New function.
	(symbol_cache_mark_found, symbol_cache_mark_not_found): New functions.
	(symbol_cache_flush, symbol_cache_dump): New functions.
	(maintenance_print_symbol_cache): New function.
	(maintenance_flush_symbol_cache): New function.
	(symbol_cache_stats): New function.
	(maintenance_print_symbol_cache_statistics): New function.
	(symtab_new_objfile_observer): New function.
	(symtab_free_objfile_observer): New function.
	(lookup_static_symbol, lookup_global_symbol): Use symbol cache.
	(_initialize_symtab): Init symbol_cache_key.  New parameter
	maint symbol-cache-size.  New maint commands print symbol-cache,
	print symbol-cache-statistics, flush-symbol-cache.
	Install new_objfile, free_objfile observers.

gdb/doc/ChangeLog:

	* gdb.texinfo (Symbols): Document new commands
	"maint print symbol-cache", "maint print symbol-cache-statistics",
	"maint flush-symbol-cache".  Document new option
	"maint set symbol-cache-size".
This commit is contained in:
Doug Evans 2015-01-31 13:29:33 -08:00
parent e700d1b279
commit f57d2163da
5 changed files with 819 additions and 14 deletions

View File

@ -1,3 +1,34 @@
2015-01-31 Doug Evans <xdje42@gmail.com>
Add symbol lookup cache.
* NEWS: Document new options and commands.
* symtab.c (symbol_cache_key): New static global.
(DEFAULT_SYMBOL_CACHE_SIZE, MAX_SYMBOL_CACHE_SIZE): New macros.
(SYMBOL_LOOKUP_FAILED): New macro.
(symbol_cache_slot_state): New enum.
(block_symbol_cache): New struct.
(symbol_cache): New struct.
(new_symbol_cache_size, symbol_cache_size): New static globals.
(hash_symbol_entry, eq_symbol_entry): New functions.
(symbol_cache_byte_size, resize_symbol_cache): New functions.
(make_symbol_cache, free_symbol_cache): New functions.
(get_symbol_cache, symbol_cache_cleanup): New function.
(set_symbol_cache_size, set_symbol_cache_size_handler): New functions.
(symbol_cache_lookup, symbol_cache_clear_slot): New function.
(symbol_cache_mark_found, symbol_cache_mark_not_found): New functions.
(symbol_cache_flush, symbol_cache_dump): New functions.
(maintenance_print_symbol_cache): New function.
(maintenance_flush_symbol_cache): New function.
(symbol_cache_stats): New function.
(maintenance_print_symbol_cache_statistics): New function.
(symtab_new_objfile_observer): New function.
(symtab_free_objfile_observer): New function.
(lookup_static_symbol, lookup_global_symbol): Use symbol cache.
(_initialize_symtab): Init symbol_cache_key. New parameter
maint symbol-cache-size. New maint commands print symbol-cache,
print symbol-cache-statistics, flush-symbol-cache.
Install new_objfile, free_objfile observers.
2015-01-31 Joel Brobecker <brobecker@adacore.com> 2015-01-31 Joel Brobecker <brobecker@adacore.com>
PR symtab/17855 PR symtab/17855

View File

@ -13,8 +13,23 @@
which is the name of the objfile as specified by the user, which is the name of the objfile as specified by the user,
without, for example, resolving symlinks. without, for example, resolving symlinks.
* New commands
maint print symbol-cache
Print the contents of the symbol cache.
maint print symbol-cache-statistics
Print statistics of symbol cache usage.
maint flush-symbol-cache
Flush the contents of the symbol cache.
* New options * New options
maint set symbol-cache-size
maint show symbol-cache-size
Control the size of the symbol cache.
* The command 'thread apply all' can now support new option '-ascending' * The command 'thread apply all' can now support new option '-ascending'
to call its specified command for all threads in ascending order. to call its specified command for all threads in ascending order.

View File

@ -1,3 +1,10 @@
2015-01-31 Doug Evans <xdje42@gmail.com>
* gdb.texinfo (Symbols): Document new commands
"maint print symbol-cache", "maint print symbol-cache-statistics",
"maint flush-symbol-cache". Document new option
"maint set symbol-cache-size".
2015-01-31 Doug Evans <xdje42@gmail.com> 2015-01-31 Doug Evans <xdje42@gmail.com>
* gdb.texinfo (dotdebug_gdb_scripts section): Update docs to * gdb.texinfo (dotdebug_gdb_scripts section): Update docs to

View File

@ -16495,8 +16495,39 @@ line 1574.
@} @}
(@value{GDBP}) (@value{GDBP})
@end smallexample @end smallexample
@end table
@kindex maint set symbol-cache-size
@cindex symbol cache size
@item maint set symbol-cache-size @var{size}
Set the size of the symbol cache to @var{size}.
The default size is intended to be good enough for debugging
most applications. This option exists to allow for experimenting
with different sizes.
@kindex maint show symbol-cache-size
@item maint show symbol-cache-size
Show the size of the symbol cache.
@kindex maint print symbol-cache
@cindex symbol cache, printing its contents
@item maint print symbol-cache
Print the contents of the symbol cache.
This is useful when debugging symbol cache issues.
@kindex maint print symbol-cache-statistics
@cindex symbol cache, printing usage statistics
@item maint print symbol-cache-statistics
Print symbol cache usage statistics.
This helps determine how well the cache is being utilized.
@kindex maint flush-symbol-cache
@cindex symbol cache, flushing
@item maint flush-symbol-cache
Flush the contents of the symbol cache, all entries are removed.
This command is useful when debugging the symbol cache.
It is also useful when collecting performance data.
@end table
@node Altering @node Altering
@chapter Altering Execution @chapter Altering Execution

View File

@ -102,12 +102,115 @@ struct main_info
enum language language_of_main; enum language language_of_main;
}; };
/* Program space key for finding its symbol cache. */
static const struct program_space_data *symbol_cache_key;
/* The default symbol cache size.
There is no extra cpu cost for large N (except when flushing the cache,
which is rare). The value here is just a first attempt. A better default
value may be higher or lower. A prime number can make up for a bad hash
computation, so that's why the number is what it is. */
#define DEFAULT_SYMBOL_CACHE_SIZE 1021
/* The maximum symbol cache size.
There's no method to the decision of what value to use here, other than
there's no point in allowing a user typo to make gdb consume all memory. */
#define MAX_SYMBOL_CACHE_SIZE (1024*1024)
/* symbol_cache_lookup returns this if a previous lookup failed to find the
symbol in any objfile. */
#define SYMBOL_LOOKUP_FAILED ((struct symbol *) 1)
/* Recording lookups that don't find the symbol is just as important, if not
more so, than recording found symbols. */
enum symbol_cache_slot_state
{
SYMBOL_SLOT_UNUSED,
SYMBOL_SLOT_NOT_FOUND,
SYMBOL_SLOT_FOUND
};
/* Symbols don't specify global vs static block.
So keep them in separate caches. */
struct block_symbol_cache
{
unsigned int hits;
unsigned int misses;
unsigned int collisions;
/* SYMBOLS is a variable length array of this size.
One can imagine that in general one cache (global/static) should be a
fraction of the size of the other, but there's no data at the moment
on which to decide. */
unsigned int size;
struct symbol_cache_slot
{
enum symbol_cache_slot_state state;
/* The objfile that was current when the symbol was looked up.
This is only needed for global blocks, but for simplicity's sake
we allocate the space for both. If data shows the extra space used
for static blocks is a problem, we can split things up then.
Global blocks need cache lookup to include the objfile context because
we need to account for gdbarch_iterate_over_objfiles_in_search_order
which can traverse objfiles in, effectively, any order, depending on
the current objfile, thus affecting which symbol is found. Normally,
only the current objfile is searched first, and then the rest are
searched in recorded order; but putting cache lookup inside
gdbarch_iterate_over_objfiles_in_search_order would be awkward.
Instead we just make the current objfile part of the context of
cache lookup. This means we can record the same symbol multiple times,
each with a different "current objfile" that was in effect when the
lookup was saved in the cache, but cache space is pretty cheap. */
const struct objfile *objfile_context;
union
{
struct symbol *found;
struct
{
char *name;
domain_enum domain;
} not_found;
} value;
} symbols[1];
};
/* The symbol cache.
Searching for symbols in the static and global blocks over multiple objfiles
again and again can be slow, as can searching very big objfiles. This is a
simple cache to improve symbol lookup performance, which is critical to
overall gdb performance.
Symbols are hashed on the name, its domain, and block.
They are also hashed on their objfile for objfile-specific lookups. */
struct symbol_cache
{
struct block_symbol_cache *global_symbols;
struct block_symbol_cache *static_symbols;
};
/* When non-zero, print debugging messages related to symtab creation. */ /* When non-zero, print debugging messages related to symtab creation. */
unsigned int symtab_create_debug = 0; unsigned int symtab_create_debug = 0;
/* When non-zero, print debugging messages related to symbol lookup. */ /* When non-zero, print debugging messages related to symbol lookup. */
unsigned int symbol_lookup_debug = 0; unsigned int symbol_lookup_debug = 0;
/* The size of the cache is staged here. */
static unsigned int new_symbol_cache_size = DEFAULT_SYMBOL_CACHE_SIZE;
/* The current value of the symbol cache size.
This is saved so that if the user enters a value too big we can restore
the original value from here. */
static unsigned int symbol_cache_size = DEFAULT_SYMBOL_CACHE_SIZE;
/* Non-zero if a file may be known by two different basenames. /* Non-zero if a file may be known by two different basenames.
This is the uncommon case, and significantly slows down gdb. This is the uncommon case, and significantly slows down gdb.
Default set to "off" to not slow down the common case. */ Default set to "off" to not slow down the common case. */
@ -1058,6 +1161,552 @@ expand_symtab_containing_pc (CORE_ADDR pc, struct obj_section *section)
} }
} }
/* Hash function for the symbol cache. */
static unsigned int
hash_symbol_entry (const struct objfile *objfile_context,
const char *name, domain_enum domain)
{
unsigned int hash = (uintptr_t) objfile_context;
if (name != NULL)
hash += htab_hash_string (name);
hash += domain;
return hash;
}
/* Equality function for the symbol cache. */
static int
eq_symbol_entry (const struct symbol_cache_slot *slot,
const struct objfile *objfile_context,
const char *name, domain_enum domain)
{
const char *slot_name;
domain_enum slot_domain;
if (slot->state == SYMBOL_SLOT_UNUSED)
return 0;
if (slot->objfile_context != objfile_context)
return 0;
if (slot->state == SYMBOL_SLOT_NOT_FOUND)
{
slot_name = slot->value.not_found.name;
slot_domain = slot->value.not_found.domain;
}
else
{
slot_name = SYMBOL_SEARCH_NAME (slot->value.found);
slot_domain = SYMBOL_DOMAIN (slot->value.found);
}
/* NULL names match. */
if (slot_name == NULL && name == NULL)
{
/* But there's no point in calling symbol_matches_domain in the
SYMBOL_SLOT_FOUND case. */
if (slot_domain != domain)
return 0;
}
else if (slot_name != NULL && name != NULL)
{
/* 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 strcmp_iw on SYMBOL_SEARCH_NAME. See dictionary.c.
It also means using symbol_matches_domain for found symbols.
See block.c.
If the slot records a not-found symbol, then require a precise match.
We could still be lax with whitespace like strcmp_iw though. */
if (slot->state == SYMBOL_SLOT_NOT_FOUND)
{
if (strcmp (slot_name, name) != 0)
return 0;
if (slot_domain != domain)
return 0;
}
else
{
struct symbol *sym = slot->value.found;
if (strcmp_iw (slot_name, name) != 0)
return 0;
if (!symbol_matches_domain (SYMBOL_LANGUAGE (sym),
slot_domain, domain))
return 0;
}
}
else
{
/* Only one name is NULL. */
return 0;
}
return 1;
}
/* Given a cache of size SIZE, return the size of the struct (with variable
length array) in bytes. */
static size_t
symbol_cache_byte_size (unsigned int size)
{
return (sizeof (struct block_symbol_cache)
+ ((size - 1) * sizeof (struct symbol_cache_slot)));
}
/* Resize CACHE. */
static void
resize_symbol_cache (struct symbol_cache *cache, unsigned int new_size)
{
/* If there's no change in size, don't do anything.
All caches have the same size, so we can just compare with the size
of the global symbols cache. */
if ((cache->global_symbols != NULL
&& cache->global_symbols->size == new_size)
|| (cache->global_symbols == NULL
&& new_size == 0))
return;
xfree (cache->global_symbols);
xfree (cache->static_symbols);
if (new_size == 0)
{
cache->global_symbols = NULL;
cache->static_symbols = NULL;
}
else
{
size_t total_size = symbol_cache_byte_size (new_size);
cache->global_symbols = xcalloc (1, total_size);
cache->static_symbols = xcalloc (1, total_size);
cache->global_symbols->size = new_size;
cache->static_symbols->size = new_size;
}
}
/* Make a symbol cache of size SIZE. */
static struct symbol_cache *
make_symbol_cache (unsigned int size)
{
struct symbol_cache *cache;
cache = XCNEW (struct symbol_cache);
resize_symbol_cache (cache, symbol_cache_size);
return cache;
}
/* Free the space used by CACHE. */
static void
free_symbol_cache (struct symbol_cache *cache)
{
xfree (cache->global_symbols);
xfree (cache->static_symbols);
xfree (cache);
}
/* Return the symbol cache of PSPACE.
Create one if it doesn't exist yet. */
static struct symbol_cache *
get_symbol_cache (struct program_space *pspace)
{
struct symbol_cache *cache = program_space_data (pspace, symbol_cache_key);
if (cache == NULL)
{
cache = make_symbol_cache (symbol_cache_size);
set_program_space_data (pspace, symbol_cache_key, cache);
}
return cache;
}
/* Delete the symbol cache of PSPACE.
Called when PSPACE is destroyed. */
static void
symbol_cache_cleanup (struct program_space *pspace, void *data)
{
struct symbol_cache *cache = data;
free_symbol_cache (cache);
}
/* Set the size of the symbol cache in all program spaces. */
static void
set_symbol_cache_size (unsigned int new_size)
{
struct program_space *pspace;
ALL_PSPACES (pspace)
{
struct symbol_cache *cache
= program_space_data (pspace, symbol_cache_key);
/* The pspace could have been created but not have a cache yet. */
if (cache != NULL)
resize_symbol_cache (cache, new_size);
}
}
/* Called when symbol-cache-size is set. */
static void
set_symbol_cache_size_handler (char *args, int from_tty,
struct cmd_list_element *c)
{
if (new_symbol_cache_size > MAX_SYMBOL_CACHE_SIZE)
{
/* Restore the previous value.
This is the value the "show" command prints. */
new_symbol_cache_size = symbol_cache_size;
error (_("Symbol cache size is too large, max is %u."),
MAX_SYMBOL_CACHE_SIZE);
}
symbol_cache_size = new_symbol_cache_size;
set_symbol_cache_size (symbol_cache_size);
}
/* Lookup symbol NAME,DOMAIN in BLOCK in the symbol cache of PSPACE.
OBJFILE_CONTEXT is the current objfile, which may be NULL.
The result is the symbol if found, SYMBOL_LOOKUP_FAILED if a previous lookup
failed (and thus this one will too), or NULL if the symbol is not present
in the cache.
*BSC_PTR, *SLOT_PTR are set to the cache and slot of the symbol, whether
found or not found. */
static struct symbol *
symbol_cache_lookup (struct symbol_cache *cache,
struct objfile *objfile_context, int block,
const char *name, domain_enum domain,
struct block_symbol_cache **bsc_ptr,
struct symbol_cache_slot **slot_ptr)
{
struct block_symbol_cache *bsc;
unsigned int hash;
struct symbol_cache_slot *slot;
if (block == GLOBAL_BLOCK)
bsc = cache->global_symbols;
else
bsc = cache->static_symbols;
if (bsc == NULL)
{
*bsc_ptr = NULL;
*slot_ptr = NULL;
return NULL;
}
hash = hash_symbol_entry (objfile_context, name, domain);
slot = bsc->symbols + hash % bsc->size;
*bsc_ptr = bsc;
*slot_ptr = slot;
if (eq_symbol_entry (slot, objfile_context, name, domain))
{
if (symbol_lookup_debug)
fprintf_unfiltered (gdb_stdlog,
"%s block symbol cache hit%s for %s, %s\n",
block == GLOBAL_BLOCK ? "Global" : "Static",
slot->state == SYMBOL_SLOT_NOT_FOUND
? " (not found)" : "",
name, domain_name (domain));
++bsc->hits;
if (slot->state == SYMBOL_SLOT_NOT_FOUND)
return SYMBOL_LOOKUP_FAILED;
return slot->value.found;
}
if (symbol_lookup_debug)
{
fprintf_unfiltered (gdb_stdlog,
"%s block symbol cache miss for %s, %s\n",
block == GLOBAL_BLOCK ? "Global" : "Static",
name, domain_name (domain));
}
++bsc->misses;
return NULL;
}
/* 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*
necessarily the objfile the symbol was found in. */
static void
symbol_cache_mark_found (struct block_symbol_cache *bsc,
struct symbol_cache_slot *slot,
struct objfile *objfile_context,
struct symbol *symbol)
{
if (bsc == NULL)
return;
if (slot->state != SYMBOL_SLOT_UNUSED)
{
++bsc->collisions;
symbol_cache_clear_slot (slot);
}
slot->state = SYMBOL_SLOT_FOUND;
slot->objfile_context = objfile_context;
slot->value.found = symbol;
}
/* Mark symbol NAME, DOMAIN as not 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). */
static void
symbol_cache_mark_not_found (struct block_symbol_cache *bsc,
struct symbol_cache_slot *slot,
struct objfile *objfile_context,
const char *name, domain_enum domain)
{
if (bsc == NULL)
return;
if (slot->state != SYMBOL_SLOT_UNUSED)
{
++bsc->collisions;
symbol_cache_clear_slot (slot);
}
slot->state = SYMBOL_SLOT_NOT_FOUND;
slot->objfile_context = objfile_context;
slot->value.not_found.name = xstrdup (name);
slot->value.not_found.domain = domain;
}
/* Flush the symbol cache of PSPACE. */
static void
symbol_cache_flush (struct program_space *pspace)
{
struct symbol_cache *cache = program_space_data (pspace, symbol_cache_key);
int pass;
size_t total_size;
if (cache == NULL)
return;
if (cache->global_symbols == NULL)
{
gdb_assert (symbol_cache_size == 0);
gdb_assert (cache->static_symbols == NULL);
return;
}
/* If the cache is untouched since the last flush, early exit.
This is important for performance during the startup of a program linked
with 100s (or 1000s) of shared libraries. */
if (cache->global_symbols->misses == 0
&& cache->static_symbols->misses == 0)
return;
gdb_assert (cache->global_symbols->size == symbol_cache_size);
gdb_assert (cache->static_symbols->size == symbol_cache_size);
for (pass = 0; pass < 2; ++pass)
{
struct block_symbol_cache *bsc
= pass == 0 ? cache->global_symbols : cache->static_symbols;
unsigned int i;
for (i = 0; i < bsc->size; ++i)
symbol_cache_clear_slot (&bsc->symbols[i]);
}
cache->global_symbols->hits = 0;
cache->global_symbols->misses = 0;
cache->global_symbols->collisions = 0;
cache->static_symbols->hits = 0;
cache->static_symbols->misses = 0;
cache->static_symbols->collisions = 0;
}
/* Dump CACHE. */
static void
symbol_cache_dump (const struct symbol_cache *cache)
{
int pass;
if (cache->global_symbols == NULL)
{
printf_filtered (" <disabled>\n");
return;
}
for (pass = 0; pass < 2; ++pass)
{
const struct block_symbol_cache *bsc
= pass == 0 ? cache->global_symbols : cache->static_symbols;
unsigned int i;
if (pass == 0)
printf_filtered ("Global symbols:\n");
else
printf_filtered ("Static symbols:\n");
for (i = 0; i < bsc->size; ++i)
{
const struct symbol_cache_slot *slot = &bsc->symbols[i];
QUIT;
switch (slot->state)
{
case SYMBOL_SLOT_UNUSED:
break;
case SYMBOL_SLOT_NOT_FOUND:
printf_filtered (" [%-4u] = %s, %s (not found)\n", i,
host_address_to_string (slot->objfile_context),
slot->value.not_found.name);
break;
case SYMBOL_SLOT_FOUND:
printf_filtered (" [%-4u] = %s, %s\n", i,
host_address_to_string (slot->objfile_context),
SYMBOL_PRINT_NAME (slot->value.found));
break;
}
}
}
}
/* The "mt print symbol-cache" command. */
static void
maintenance_print_symbol_cache (char *args, int from_tty)
{
struct program_space *pspace;
ALL_PSPACES (pspace)
{
struct symbol_cache *cache;
printf_filtered (_("Symbol cache for pspace %d\n%s:\n"),
pspace->num,
pspace->symfile_object_file != NULL
? objfile_name (pspace->symfile_object_file)
: "(no object file)");
/* If the cache hasn't been created yet, avoid creating one. */
cache = program_space_data (pspace, symbol_cache_key);
if (cache == NULL)
printf_filtered (" <empty>\n");
else
symbol_cache_dump (cache);
}
}
/* The "mt flush-symbol-cache" command. */
static void
maintenance_flush_symbol_cache (char *args, int from_tty)
{
struct program_space *pspace;
ALL_PSPACES (pspace)
{
symbol_cache_flush (pspace);
}
}
/* Print usage statistics of CACHE. */
static void
symbol_cache_stats (struct symbol_cache *cache)
{
int pass;
if (cache->global_symbols == NULL)
{
printf_filtered (" <disabled>\n");
return;
}
for (pass = 0; pass < 2; ++pass)
{
const struct block_symbol_cache *bsc
= pass == 0 ? cache->global_symbols : cache->static_symbols;
QUIT;
if (pass == 0)
printf_filtered ("Global block cache stats:\n");
else
printf_filtered ("Static block cache stats:\n");
printf_filtered (" size: %u\n", bsc->size);
printf_filtered (" hits: %u\n", bsc->hits);
printf_filtered (" misses: %u\n", bsc->misses);
printf_filtered (" collisions: %u\n", bsc->collisions);
}
}
/* The "mt print symbol-cache-statistics" command. */
static void
maintenance_print_symbol_cache_statistics (char *args, int from_tty)
{
struct program_space *pspace;
ALL_PSPACES (pspace)
{
struct symbol_cache *cache;
printf_filtered (_("Symbol cache statistics for pspace %d\n%s:\n"),
pspace->num,
pspace->symfile_object_file != NULL
? objfile_name (pspace->symfile_object_file)
: "(no object file)");
/* If the cache hasn't been created yet, avoid creating one. */
cache = program_space_data (pspace, symbol_cache_key);
if (cache == NULL)
printf_filtered (" empty, no stats available\n");
else
symbol_cache_stats (cache);
}
}
/* This module's 'new_objfile' observer. */
static void
symtab_new_objfile_observer (struct objfile *objfile)
{
/* Ideally we'd use OBJFILE->pspace, but OBJFILE may be NULL. */
symbol_cache_flush (current_program_space);
}
/* This module's 'free_objfile' observer. */
static void
symtab_free_objfile_observer (struct objfile *objfile)
{
symbol_cache_flush (objfile->pspace);
}
/* Debug symbols usually don't have section information. We need to dig that /* Debug symbols usually don't have section information. We need to dig that
out of the minimal symbols and stash that in the debug symbol. */ out of the minimal symbols and stash that in the debug symbol. */
@ -1970,16 +2619,36 @@ lookup_symbol_in_objfile (struct objfile *objfile, int block_index,
struct symbol * struct symbol *
lookup_static_symbol (const char *name, const domain_enum domain) lookup_static_symbol (const char *name, const domain_enum domain)
{ {
struct symbol_cache *cache = get_symbol_cache (current_program_space);
struct objfile *objfile; struct objfile *objfile;
struct symbol *result; struct symbol *result;
struct block_symbol_cache *bsc;
struct symbol_cache_slot *slot;
/* Lookup in STATIC_BLOCK is not current-objfile-dependent, so just pass
NULL for OBJFILE_CONTEXT. */
result = symbol_cache_lookup (cache, NULL, STATIC_BLOCK, name, domain,
&bsc, &slot);
if (result != NULL)
{
if (result == SYMBOL_LOOKUP_FAILED)
return NULL;
return result;
}
ALL_OBJFILES (objfile) ALL_OBJFILES (objfile)
{ {
result = lookup_symbol_in_objfile (objfile, STATIC_BLOCK, name, domain); result = lookup_symbol_in_objfile (objfile, STATIC_BLOCK, name, domain);
if (result != NULL) if (result != NULL)
return result; {
/* Still pass NULL for OBJFILE_CONTEXT here. */
symbol_cache_mark_found (bsc, slot, NULL, result);
return result;
}
} }
/* Still pass NULL for OBJFILE_CONTEXT here. */
symbol_cache_mark_not_found (bsc, slot, NULL, name, domain);
return NULL; return NULL;
} }
@ -2027,25 +2696,48 @@ lookup_global_symbol (const char *name,
const struct block *block, const struct block *block,
const domain_enum domain) const domain_enum domain)
{ {
struct symbol *sym = NULL; struct symbol_cache *cache = get_symbol_cache (current_program_space);
struct objfile *objfile = NULL; struct symbol *sym;
struct objfile *objfile;
struct global_sym_lookup_data lookup_data; struct global_sym_lookup_data lookup_data;
struct block_symbol_cache *bsc;
struct symbol_cache_slot *slot;
objfile = lookup_objfile_from_block (block);
/* First see if we can find the symbol in the cache.
This works because we use the current objfile to qualify the lookup. */
sym = symbol_cache_lookup (cache, objfile, GLOBAL_BLOCK, name, domain,
&bsc, &slot);
if (sym != NULL)
{
if (sym == SYMBOL_LOOKUP_FAILED)
return NULL;
return sym;
}
/* Call library-specific lookup procedure. */ /* Call library-specific lookup procedure. */
objfile = lookup_objfile_from_block (block);
if (objfile != NULL) if (objfile != NULL)
sym = solib_global_lookup (objfile, name, domain); sym = solib_global_lookup (objfile, name, domain);
/* If that didn't work go a global search (of global blocks, heh). */
if (sym == NULL)
{
memset (&lookup_data, 0, sizeof (lookup_data));
lookup_data.name = name;
lookup_data.domain = domain;
gdbarch_iterate_over_objfiles_in_search_order
(objfile != NULL ? get_objfile_arch (objfile) : target_gdbarch (),
lookup_symbol_global_iterator_cb, &lookup_data, objfile);
sym = lookup_data.result;
}
if (sym != NULL) if (sym != NULL)
return sym; symbol_cache_mark_found (bsc, slot, objfile, sym);
else
symbol_cache_mark_not_found (bsc, slot, objfile, name, domain);
memset (&lookup_data, 0, sizeof (lookup_data)); return sym;
lookup_data.name = name;
lookup_data.domain = domain;
gdbarch_iterate_over_objfiles_in_search_order
(objfile != NULL ? get_objfile_arch (objfile) : target_gdbarch (),
lookup_symbol_global_iterator_cb, &lookup_data, objfile);
return lookup_data.result;
} }
int int
@ -5436,6 +6128,9 @@ _initialize_symtab (void)
main_progspace_key main_progspace_key
= register_program_space_data_with_cleanup (NULL, main_info_cleanup); = register_program_space_data_with_cleanup (NULL, main_info_cleanup);
symbol_cache_key
= register_program_space_data_with_cleanup (NULL, symbol_cache_cleanup);
add_info ("variables", variables_info, _("\ add_info ("variables", variables_info, _("\
All global and static variable names, or those matching REGEXP.")); All global and static variable names, or those matching REGEXP."));
if (dbx_commands) if (dbx_commands)
@ -5511,5 +6206,31 @@ When enabled (non-zero), symbol lookups are logged."),
NULL, NULL, NULL, NULL,
&setdebuglist, &showdebuglist); &setdebuglist, &showdebuglist);
add_setshow_zuinteger_cmd ("symbol-cache-size", no_class,
&new_symbol_cache_size,
_("Set the size of the symbol cache."),
_("Show the size of the symbol cache."), _("\
The size of the symbol cache.\n\
If zero then the symbol cache is disabled."),
set_symbol_cache_size_handler, NULL,
&maintenance_set_cmdlist,
&maintenance_show_cmdlist);
add_cmd ("symbol-cache", class_maintenance, maintenance_print_symbol_cache,
_("Dump the symbol cache for each program space."),
&maintenanceprintlist);
add_cmd ("symbol-cache-statistics", class_maintenance,
maintenance_print_symbol_cache_statistics,
_("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);
observer_attach_executable_changed (symtab_observer_executable_changed); observer_attach_executable_changed (symtab_observer_executable_changed);
observer_attach_new_objfile (symtab_new_objfile_observer);
observer_attach_free_objfile (symtab_free_objfile_observer);
} }