/* Symbol table lookup for the GNU debugger, GDB.
Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software
- Foundation, Inc.
+ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ Free Software Foundation, Inc.
This file is part of GDB.
#include "source.h"
#include "filenames.h" /* for FILENAME_CMP */
+#include "hashtab.h"
+
#include "gdb_obstack.h"
#include <sys/types.h>
int *is_a_field_of_this,
struct symtab **symtab);
-static struct symbol *lookup_symbol_aux_local (const char *name,
- const char *mangled_name,
- const struct block *block,
- const namespace_enum namespace,
- struct symtab **symtab);
+static
+struct symbol *lookup_symbol_aux_local (const char *name,
+ const char *mangled_name,
+ const struct block *block,
+ const namespace_enum namespace,
+ struct symtab **symtab,
+ const struct block **static_block);
+
+static
+struct symbol *lookup_symbol_aux_block (const char *name,
+ const char *mangled_name,
+ const struct block *block,
+ const namespace_enum namespace,
+ struct symtab **symtab);
static
struct symbol *lookup_symbol_aux_symtabs (int block_index,
const char *mangled_name,
const namespace_enum namespace,
int *is_a_field_of_this,
- struct symtab **symtab,
- int *force_return);
+ struct symtab **symtab);
static struct symbol *find_active_alias (struct symbol *sym, CORE_ADDR addr);
{
gsymbol->language_specific.objc_specific.demangled_name = NULL;
}
- /* OBSOLETE else if (SYMBOL_LANGUAGE (symbol) == language_chill) */
- /* OBSOLETE { */
- /* OBSOLETE SYMBOL_CHILL_DEMANGLED_NAME (symbol) = NULL; */
- /* OBSOLETE } */
else
{
memset (&gsymbol->language_specific, 0,
}
}
-/* Initialize a symbol's mangled name. */
+/* Functions to initialize a symbol's mangled name. */
+
+/* Create the hash table used for demangled names. Each hash entry is
+ a pair of strings; one for the mangled name and one for the demangled
+ name. The entry is hashed via just the mangled name. */
+
+static void
+create_demangled_names_hash (struct objfile *objfile)
+{
+ /* Choose 256 as the starting size of the hash table, somewhat arbitrarily.
+ The hash table code will round this up to the next prime number.
+ Choosing a much larger table size wastes memory, and saves only about
+ 1% in symbol reading. */
+
+ objfile->demangled_names_hash = htab_create_alloc_ex
+ (256, htab_hash_string, (int (*) (const void *, const void *)) streq,
+ NULL, objfile->md, xmcalloc, xmfree);
+}
-/* Try to initialize the demangled name for a symbol, based on the
+/* Try to determine the demangled name for a symbol, based on the
language of that symbol. If the language is set to language_auto,
it will attempt to find any demangling algorithm that works and
- then set the language appropriately. If no demangling of any kind
- is found, the language is set back to language_unknown, so we can
- avoid doing this work again the next time we encounter the symbol.
- Any required space to store the name is obtained from the specified
- obstack. */
+ then set the language appropriately. The returned name is allocated
+ by the demangler and should be xfree'd. */
-void
-symbol_init_demangled_name (struct general_symbol_info *gsymbol,
- struct obstack *obstack)
+static char *
+symbol_find_demangled_name (struct general_symbol_info *gsymbol,
+ const char *mangled)
{
- char *mangled = gsymbol->name;
char *demangled = NULL;
if (gsymbol->language == language_unknown)
|| gsymbol->language == language_auto)
{
demangled =
- cplus_demangle (gsymbol->name, DMGL_PARAMS | DMGL_ANSI);
+ cplus_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
if (demangled != NULL)
- {
- gsymbol->language = language_cplus;
- gsymbol->language_specific.cplus_specific.demangled_name =
- obsavestring (demangled, strlen (demangled), obstack);
- xfree (demangled);
- }
- else
- {
- gsymbol->language_specific.cplus_specific.demangled_name = NULL;
- }
+ {
+ gsymbol->language = language_cplus;
+ return demangled;
+ }
}
if (gsymbol->language == language_java)
{
demangled =
- cplus_demangle (gsymbol->name,
+ cplus_demangle (mangled,
DMGL_PARAMS | DMGL_ANSI | DMGL_JAVA);
if (demangled != NULL)
- {
- gsymbol->language = language_java;
- gsymbol->language_specific.cplus_specific.demangled_name =
- obsavestring (demangled, strlen (demangled), obstack);
- xfree (demangled);
- }
+ {
+ gsymbol->language = language_java;
+ return demangled;
+ }
+ }
+ return NULL;
+}
+
+/* Set both the mangled and demangled (if any) names for GSYMBOL based on
+ NAME and LEN. The hash table corresponding to OBJFILE is used, and the
+ memory comes from that objfile's symbol_obstack. NAME is copied, so the
+ pointer can be discarded after calling this function. */
+
+void
+symbol_set_names (struct general_symbol_info *gsymbol,
+ const char *name, int len, struct objfile *objfile)
+{
+ char **slot;
+ const char *tmpname;
+
+ if (objfile->demangled_names_hash == NULL)
+ create_demangled_names_hash (objfile);
+
+ /* The stabs reader generally provides names that are not NULL-terminated;
+ most of the other readers don't do this, so we can just use the given
+ copy. */
+ if (name[len] != 0)
+ {
+ char *alloc_name = alloca (len + 1);
+ memcpy (alloc_name, name, len);
+ alloc_name[len] = 0;
+ tmpname = alloc_name;
+ }
+ else
+ tmpname = name;
+
+ slot = (char **) htab_find_slot (objfile->demangled_names_hash, tmpname, INSERT);
+
+ /* If this name is not in the hash table, add it. */
+ if (*slot == NULL)
+ {
+ char *demangled_name = symbol_find_demangled_name (gsymbol, tmpname);
+ int demangled_len = demangled_name ? strlen (demangled_name) : 0;
+
+ /* If there is a demangled name, place it right after the mangled name.
+ Otherwise, just place a second zero byte after the end of the mangled
+ name. */
+ *slot = obstack_alloc (&objfile->symbol_obstack,
+ len + demangled_len + 2);
+ memcpy (*slot, tmpname, len + 1);
+ if (demangled_name)
+ {
+ memcpy (*slot + len + 1, demangled_name, demangled_len + 1);
+ xfree (demangled_name);
+ }
else
- {
- gsymbol->language_specific.cplus_specific.demangled_name = NULL;
- }
+ (*slot)[len + 1] = 0;
+ }
+
+ gsymbol->name = *slot;
+ if ((*slot)[len + 1])
+ gsymbol->language_specific.cplus_specific.demangled_name
+ = &(*slot)[len + 1];
+ else
+ gsymbol->language_specific.cplus_specific.demangled_name = NULL;
+}
+
+/* Initialize the demangled name of GSYMBOL if possible. Any required space
+ to store the name is obtained from the specified obstack. The function
+ symbol_set_names, above, should be used instead where possible for more
+ efficient memory usage. */
+
+void
+symbol_init_demangled_name (struct general_symbol_info *gsymbol,
+ struct obstack *obstack)
+{
+ char *mangled = gsymbol->name;
+ char *demangled = NULL;
+
+ demangled = symbol_find_demangled_name (gsymbol, mangled);
+ if (gsymbol->language == language_cplus
+ || gsymbol->language == language_java)
+ {
+ if (demangled)
+ {
+ gsymbol->language_specific.cplus_specific.demangled_name
+ = obsavestring (demangled, strlen (demangled), obstack);
+ xfree (demangled);
+ }
+ else
+ gsymbol->language_specific.cplus_specific.demangled_name = NULL;
+ }
+ else
+ {
+ /* Unknown language; just clean up quietly. */
+ if (demangled)
+ xfree (demangled);
}
-#if 0
- /* OBSOLETE if (demangled == NULL */
- /* OBSOLETE && (gsymbol->language == language_chill */
- /* OBSOLETE || gsymbol->language == language_auto)) */
- /* OBSOLETE { */
- /* OBSOLETE demangled = */
- /* OBSOLETE chill_demangle (gsymbol->name); */
- /* OBSOLETE if (demangled != NULL) */
- /* OBSOLETE { */
- /* OBSOLETE gsymbol->language = language_chill; */
- /* OBSOLETE gsymbol->language_specific.chill_specific.demangled_name = */
- /* OBSOLETE obsavestring (demangled, strlen (demangled), obstack); */
- /* OBSOLETE xfree (demangled); */
- /* OBSOLETE } */
- /* OBSOLETE else */
- /* OBSOLETE { */
- /* OBSOLETE gsymbol->language_specific.chill_specific.demangled_name = NULL; */
- /* OBSOLETE } */
- /* OBSOLETE } */
-#endif
}
/* Return the demangled name for a symbol based on the language for
else
return NULL;
-
- /* OBSOLETE (SYMBOL_LANGUAGE (symbol) == language_chill */
- /* OBSOLETE ? SYMBOL_CHILL_DEMANGLED_NAME (symbol) */
}
/* Initialize the structure fields to zero values. */
attractive to put in some QUIT's (though I'm not really sure
whether it can run long enough to be really important). But there
are a few calls for which it would appear to be bad news to quit
- out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c, and
- nindy_frame_chain_valid in nindy-tdep.c. (Note that there is C++
- code below which can error(), but that probably doesn't affect
- these calls since they are looking for a known variable and thus
- can probably assume it will never hit the C++ code). */
+ out of here: find_proc_desc in alpha-tdep.c and mips-tdep.c. (Note
+ that there is C++ code below which can error(), but that probably
+ doesn't affect these calls since they are looking for a known
+ variable and thus can probably assume it will never hit the C++
+ code). */
struct symbol *
lookup_symbol (const char *name, const struct block *block,
int *is_a_field_of_this, struct symtab **symtab)
{
struct symbol *sym;
+ const struct block *static_block;
- /* FIXME: carlton/2002-11-05: This variable is here so that
- lookup_symbol_aux will sometimes return NULL after receiving a
- NULL return value from lookup_symbol_aux_minsyms, without
- proceeding on to the partial symtab and static variable tests. I
- suspect that that's a bad idea. */
-
- int force_return;
-
- /* Search specified block and its superiors. */
+ /* Search specified block and its superiors. Don't search
+ STATIC_BLOCK or GLOBAL_BLOCK. */
sym = lookup_symbol_aux_local (name, mangled_name, block, namespace,
- symtab);
+ symtab, &static_block);
if (sym != NULL)
return sym;
}
}
+ /* If there's a static block to search, search it next. */
+
+ /* NOTE: carlton/2002-12-05: There is a question as to whether or
+ not it would be appropriate to search the current global block
+ here as well. (That's what this code used to do before the
+ is_a_field_of_this check was moved up.) On the one hand, it's
+ redundant with the lookup_symbol_aux_symtabs search that happens
+ next. On the other hand, if decode_line_1 is passed an argument
+ like filename:var, then the user presumably wants 'var' to be
+ searched for in filename. On the third hand, there shouldn't be
+ multiple global variables all of which are named 'var', and it's
+ not like decode_line_1 has ever restricted its search to only
+ global variables in a single filename. All in all, only
+ searching the static block here seems best: it's correct and it's
+ cleanest. */
+
+ /* NOTE: carlton/2002-12-05: There's also a possible performance
+ issue here: if you usually search for global symbols in the
+ current file, then it would be slightly better to search the
+ current global block before searching all the symtabs. But there
+ are other factors that have a much greater effect on performance
+ than that one, so I don't think we should worry about that for
+ now. */
+
+ if (static_block != NULL)
+ {
+ sym = lookup_symbol_aux_block (name, mangled_name, static_block,
+ namespace, symtab);
+ if (sym != NULL)
+ return sym;
+ }
+
/* Now search all global blocks. Do the symtab's first, then
check the psymtab's. If a psymtab indicates the existence
of the desired name as a global, then do psymtab-to-symtab
a mangled variable that is stored in one of the minimal symbol tables.
Eventually, all global symbols might be resolved in this way. */
- force_return = 0;
-
sym = lookup_symbol_aux_minsyms (name, mangled_name,
namespace, is_a_field_of_this,
- symtab, &force_return);
+ symtab);
- if (sym != NULL || force_return == 1)
+ if (sym != NULL)
return sym;
#endif
*/
- force_return = 0;
-
sym = lookup_symbol_aux_minsyms (name, mangled_name,
namespace, is_a_field_of_this,
- symtab, &force_return);
+ symtab);
- if (sym != NULL || force_return == 1)
+ if (sym != NULL)
return sym;
#endif
return NULL;
}
-/* Check to see if the symbol is defined in BLOCK or its
- superiors. */
+/* Check to see if the symbol is defined in BLOCK or its superiors.
+ Don't search STATIC_BLOCK or GLOBAL_BLOCK. If we don't find a
+ match, store the address of STATIC_BLOCK in static_block. */
static struct symbol *
lookup_symbol_aux_local (const char *name, const char *mangled_name,
+ const struct block *block,
+ const namespace_enum namespace,
+ struct symtab **symtab,
+ const struct block **static_block)
+{
+ struct symbol *sym;
+
+ /* Check if either no block is specified or it's a global block. */
+
+ if (block == NULL || BLOCK_SUPERBLOCK (block) == NULL)
+ {
+ *static_block = NULL;
+ return NULL;
+ }
+
+ while (BLOCK_SUPERBLOCK (BLOCK_SUPERBLOCK (block)) != NULL)
+ {
+ sym = lookup_symbol_aux_block (name, mangled_name, block, namespace,
+ symtab);
+ if (sym != NULL)
+ return sym;
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ /* We've reached the static block. */
+
+ *static_block = block;
+ return NULL;
+}
+
+/* Look up a symbol in a block; if found, locate its symtab, fixup the
+ symbol, and set block_found appropriately. */
+
+static struct symbol *
+lookup_symbol_aux_block (const char *name, const char *mangled_name,
const struct block *block,
const namespace_enum namespace,
struct symtab **symtab)
struct blockvector *bv;
struct block *b;
struct symtab *s = NULL;
-
- while (block != 0)
+
+ sym = lookup_block_symbol (block, name, mangled_name, namespace);
+ if (sym)
{
- sym = lookup_block_symbol (block, name, mangled_name, namespace);
- if (sym)
+ block_found = block;
+ if (symtab != NULL)
{
- block_found = block;
- if (symtab != NULL)
+ /* Search the list of symtabs for one which contains the
+ address of the start of this block. */
+ ALL_SYMTABS (objfile, s)
{
- /* Search the list of symtabs for one which contains the
- address of the start of this block. */
- ALL_SYMTABS (objfile, s)
- {
- bv = BLOCKVECTOR (s);
- b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
- if (BLOCK_START (b) <= BLOCK_START (block)
- && BLOCK_END (b) > BLOCK_START (block))
- goto found;
- }
- found:
- *symtab = s;
+ bv = BLOCKVECTOR (s);
+ b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+ if (BLOCK_START (b) <= BLOCK_START (block)
+ && BLOCK_END (b) > BLOCK_START (block))
+ goto found;
}
-
- return fixup_symbol_section (sym, objfile);
+ found:
+ *symtab = s;
}
- block = BLOCK_SUPERBLOCK (block);
+
+ return fixup_symbol_section (sym, objfile);
}
return NULL;
tables. Eventually, all global symbols might be resolved in this
way. */
+/* NOTE: carlton/2002-12-05: At one point, this function was part of
+ lookup_symbol_aux, and what are now 'return' statements within
+ lookup_symbol_aux_minsyms returned from lookup_symbol_aux, even if
+ sym was NULL. As far as I can tell, this was basically accidental;
+ it didn't happen every time that msymbol was non-NULL, but only if
+ some additional conditions held as well, and it caused problems
+ with HP-generated symbol tables. */
+
static struct symbol *
lookup_symbol_aux_minsyms (const char *name,
const char *mangled_name,
const namespace_enum namespace,
int *is_a_field_of_this,
- struct symtab **symtab,
- int *force_return)
+ struct symtab **symtab)
{
struct symbol *sym;
struct blockvector *bv;
if (symtab != NULL && sym != NULL)
*symtab = s;
- *force_return = 1;
return fixup_symbol_section (sym, s->objfile);
}
else if (MSYMBOL_TYPE (msymbol) != mst_text
{
/* This is a mangled variable, look it up by its
mangled name. */
- *force_return = 1;
return lookup_symbol_aux (SYMBOL_NAME (msymbol), mangled_name,
NULL, namespace, is_a_field_of_this,
symtab);
{
struct partial_symbol *temp;
struct partial_symbol **start, **psym;
- struct partial_symbol **top, **bottom, **center;
+ struct partial_symbol **top, **real_top, **bottom, **center;
int length = (global ? pst->n_global_syms : pst->n_static_syms);
int do_linear_search = 1;
bottom = start;
top = start + length - 1;
+ real_top = top;
while (top > bottom)
{
center = bottom + (top - bottom) / 2;
/* djb - 2000-06-03 - Use SYMBOL_MATCHES_NAME, not a strcmp, so
we don't have to force a linear search on C++. Probably holds true
for JAVA as well, no way to check.*/
- while (SYMBOL_MATCHES_NAME (*top,name))
+ while (top <= real_top && SYMBOL_MATCHES_NAME (*top,name))
{
if (SYMBOL_NAMESPACE (*top) == namespace)
{
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. */
+ 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 && (!best || prev->pc > best->pc))
+ if (prev && prev->line && (!best || prev->pc > best->pc))
{
best = prev;
best_symtab = s;
{
if (0 == find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol)))
{
- if (kind == FUNCTIONS_NAMESPACE
- || lookup_symbol (SYMBOL_NAME (msymbol),
- (struct block *) NULL,
- VAR_NAMESPACE,
- 0, (struct symtab **) NULL) == NULL)
- found_misc = 1;
+ if (kind == FUNCTIONS_NAMESPACE)
+ {
+ found_misc = 1;
+ }
+ else
+ {
+ struct symbol *sym;
+
+ if (SYMBOL_DEMANGLED_NAME (msymbol) != NULL)
+ sym
+ = lookup_symbol_aux_minsyms (SYMBOL_DEMANGLED_NAME
+ (msymbol),
+ SYMBOL_NAME (msymbol),
+ VAR_NAMESPACE,
+ NULL, NULL);
+ else
+ sym
+ = lookup_symbol_aux_minsyms (SYMBOL_NAME (msymbol),
+ NULL,
+ VAR_NAMESPACE,
+ NULL, NULL);
+
+ if (sym == NULL)
+ found_misc = 1;
+ }
}
}
}