diff options
Diffstat (limited to 'gdb/minsyms.c')
-rw-r--r-- | gdb/minsyms.c | 491 |
1 files changed, 491 insertions, 0 deletions
diff --git a/gdb/minsyms.c b/gdb/minsyms.c new file mode 100644 index 0000000..3040bf5 --- /dev/null +++ b/gdb/minsyms.c @@ -0,0 +1,491 @@ +/* GDB routines for manipulating the minimal symbol tables. + Copyright 1992 Free Software Foundation, Inc. + Contributed by Cygnus Support, using pieces from other GDB modules. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* This file contains support routines for creating, manipulating, and + destroying minimal symbol tables. + + Minimal symbol tables are used to hold some very basic information about + all defined global symbols (text, data, bss, abs, etc). The only two + required pieces of information are the symbol's name and the address + associated with that symbol. + + In many cases, even if a file was compiled with no special options for + debugging at all, as long as was not stripped it will contain sufficient + information to build useful minimal symbol tables using this structure. + + Even when a file contains enough debugging information to build a full + symbol table, these minimal symbols are still useful for quickly mapping + between names and addresses, and vice versa. They are also sometimes used + to figure out what full symbol table entries need to be read in. */ + + +#include <stdio.h> +#include "defs.h" +#include "symtab.h" +#include "bfd.h" +#include "symfile.h" + +/* Accumulate the minimal symbols for each objfile in bunches of BUNCH_SIZE. + At the end, copy them all into one newly allocated location on an objfile's + symbol obstack. */ + +#define BUNCH_SIZE 127 + +struct msym_bunch +{ + struct msym_bunch *next; + struct minimal_symbol contents[BUNCH_SIZE]; +}; + +/* Bunch currently being filled up. + The next field points to chain of filled bunches. */ + +static struct msym_bunch *msym_bunch; + +/* Number of slots filled in current bunch. */ + +static int msym_bunch_index; + +/* Total number of minimal symbols recorded so far for the objfile. */ + +static int msym_count; + +/* Prototypes for local functions. */ + +static int +compare_minimal_symbols PARAMS ((const void *, const void *)); + +static int +compact_minimal_symbols PARAMS ((struct minimal_symbol *, int)); + +/* Call the function specified by FUNC for each currently available minimal + symbol, for as long as this function continues to return NULL. If the + function ever returns non-NULL, then the iteration over the minimal + symbols is terminated,, the result is returned to the caller. + + The function called has full control over the form and content of the + information returned via the non-NULL result, which may be as simple as a + pointer to the minimal symbol that the iteration terminated on, or as + complex as a pointer to a private structure containing multiple results. */ + +PTR +iterate_over_msymbols (func, arg1, arg2, arg3) + PTR (*func) PARAMS ((struct objfile *, struct minimal_symbol *, + PTR, PTR, PTR)); + PTR arg1; + PTR arg2; + PTR arg3; +{ + register struct objfile *objfile; + register struct minimal_symbol *msymbol; + char *result = NULL; + + for (objfile = object_files; + objfile != NULL && result == NULL; + objfile = objfile -> next) + { + for (msymbol = objfile -> msymbols; + msymbol != NULL && msymbol -> name != NULL && result == NULL; + msymbol++) + { + result = (*func)(objfile, msymbol, arg1, arg2, arg3); + } + } + return (result); +} + +/* Look through all the current minimal symbol tables and find the first + minimal symbol that matches NAME. If OBJF is non-NULL, it specifies a + particular objfile and the search is limited to that objfile. Returns + a pointer to the minimal symbol that matches, or NULL if no match is found. + + Note: One instance where their may be duplicate minimal symbols with + the same name is when the symbol tables for a shared library and the + symbol tables for an executable contain global symbols with the same + names (the dynamic linker deals with the duplication). */ + +struct minimal_symbol * +lookup_minimal_symbol (name, objf) + register const char *name; + struct objfile *objf; +{ + struct objfile *objfile; + struct minimal_symbol *msymbol; + struct minimal_symbol *found_symbol = NULL; + + for (objfile = object_files; + objfile != NULL && found_symbol == NULL; + objfile = objfile -> next) + { + if (objf == NULL || objf == objfile) + { + for (msymbol = objfile -> msymbols; + msymbol != NULL && msymbol -> name != NULL && + found_symbol == NULL; + msymbol++) + { + if (strcmp (msymbol -> name, name) == 0) + { + found_symbol = msymbol; + } + } + } + } + return (found_symbol); +} + + +/* Search through the minimal symbol table for each objfile and find the + symbol whose address is the largest address that is still less than or + equal to PC. Returns a pointer to the minimal symbol if such a symbol + is found, or NULL if PC is not in a suitable range. Note that we need + to look through ALL the minimal symbol tables before deciding on the + symbol that comes closest to the specified PC. */ + +struct minimal_symbol * +lookup_minimal_symbol_by_pc (pc) + register CORE_ADDR pc; +{ + register int lo; + register int hi; + register int new; + register struct objfile *objfile; + register struct minimal_symbol *msymbol; + register struct minimal_symbol *best_symbol = NULL; + + for (objfile = object_files; + objfile != NULL; + objfile = objfile -> next) + { + /* If this objfile has a minimal symbol table, go search it using + a binary search. Note that a minimal symbol table always consists + of at least two symbols, a "real" symbol and the terminating + "null symbol". If there are no real symbols, then there is no + minimal symbol table at all. */ + + if ((msymbol = objfile -> msymbols) != NULL) + { + lo = 0; + hi = objfile -> minimal_symbol_count - 2; + + /* This code assumes that the minimal symbols are sorted by + ascending address values. If the pc value is greater than or + equal to the first symbol's address, then some symbol in this + minimal symbol table is a suitable candidate for being the + "best" symbol. This includes the last real symbol, for cases + where the pc value is larger than any address in this vector. + + By iterating until the address associated with the current + hi index (the endpoint of the test interval) is less than + or equal to the desired pc value, we accomplish two things: + (1) the case where the pc value is larger than any minimal + symbol address is trivially solved, (2) the address associated + with the hi index is always the one we want when the interation + terminates. In essence, we are iterating the test interval + down until the pc value is pushed out of it from the high end. + + Warning: this code is trickier than it would appear at first. */ + + if (pc >= msymbol[lo].address) + { + while (msymbol[hi].address > pc) + { + /* pc is still strictly less than highest address */ + /* Note "new" will always be >= lo */ + new = (lo + hi) / 2; + if ((msymbol[new].address >= pc) || (lo == new)) + { + hi = new; + } + else + { + lo = new; + } + } + /* The minimal symbol indexed by hi now is the best one in this + objfile's minimal symbol table. See if it is the best one + overall. */ + + if ((best_symbol == NULL) || + (best_symbol -> address < msymbol[hi].address)) + { + best_symbol = &msymbol[hi]; + } + } + } + } + return (best_symbol); +} + +/* Prepare to start collecting minimal symbols. Note that presetting + msym_bunch_index to BUNCH_SIZE causes the first call to save a minimal + symbol to allocate the memory for the first bunch. */ + +void +init_minimal_symbol_collection () +{ + msym_count = 0; + msym_bunch = NULL; + msym_bunch_index = BUNCH_SIZE; +} + +void +prim_record_minimal_symbol (name, address, ms_type) + const char *name; + CORE_ADDR address; + enum minimal_symbol_type ms_type; +{ + register struct msym_bunch *new; + + if (msym_bunch_index == BUNCH_SIZE) + { + new = (struct msym_bunch *) xmalloc (sizeof (struct msym_bunch)); + msym_bunch_index = 0; + new -> next = msym_bunch; + msym_bunch = new; + } + msym_bunch -> contents[msym_bunch_index].name = (char *) name; + msym_bunch -> contents[msym_bunch_index].address = address; + msym_bunch -> contents[msym_bunch_index].info = NULL; + msym_bunch -> contents[msym_bunch_index].type = ms_type; + msym_bunch_index++; + msym_count++; +} + +/* Compare two minimal symbols by address and return a signed result based + on unsigned comparisons, so that we sort into unsigned numeric order. */ + +static int +compare_minimal_symbols (fn1p, fn2p) + const PTR fn1p; + const PTR fn2p; +{ + register const struct minimal_symbol *fn1; + register const struct minimal_symbol *fn2; + + fn1 = (const struct minimal_symbol *) fn1p; + fn2 = (const struct minimal_symbol *) fn2p; + + if (fn1 -> address < fn2 -> address) + { + return (-1); + } + else if (fn1 -> address > fn2 -> address) + { + return (1); + } + else + { + return (0); + } +} + +/* Discard the currently collected minimal symbols, if any. If we wish + to save them for later use, we must have already copied them somewhere + else before calling this function. + + FIXME: We could allocate the minimal symbol bunches on their own + obstack and then simply blow the obstack away when we are done with + it. Is it worth the extra trouble though? */ + +/* ARGSUSED */ +void +discard_minimal_symbols (foo) + int foo; +{ + register struct msym_bunch *next; + + while (msym_bunch != NULL) + { + next = msym_bunch -> next; + free (msym_bunch); + msym_bunch = next; + } +} + +/* Compact duplicate entries out of a minimal symbol table by walking + through the table and compacting out entries with duplicate addresses + and matching names. + + When files contain multiple sources of symbol information, it is + possible for the minimal symbol table to contain many duplicate entries. + As an example, SVR4 systems use ELF formatted object files, which + usually contain at least two different types of symbol tables (a + standard ELF one and a smaller dynamic linking table), as well as + DWARF debugging information for files compiled with -g. + + Without compacting, the minimal symbol table for gdb itself contains + over a 1000 duplicates, about a third of the total table size. Aside + from the potential trap of not noticing that two successive entries + identify the same location, this duplication impacts the time required + to linearly scan the table, which is done in a number of places. So + just do one linear scan here and toss out the duplicates. + + Note that we are not concerned here about recovering the space that + is potentially freed up, because the strings themselves are allocated + on the symbol_obstack, and will get automatically freed when the symbol + table is freed. Also, the unused minimal symbols at the end of the + compacted region will get freed automatically as well by whomever + is responsible for deallocating the entire minimal symbol table. We + can't diddle with the pointer anywhy, so don't worry about the + wasted space. + + Also note we only go up to the next to last entry within the loop + and then copy the last entry explicitly after the loop terminates. + + Since the different sources of information for each symbol may + have different levels of "completeness", we may have duplicates + that have one entry with type "mst_unknown" and the other with a + known type. So if the one we are leaving alone has type mst_unknown, + overwrite its type with the type from the one we are compacting out. */ + +static int +compact_minimal_symbols (msymbol, mcount) + struct minimal_symbol *msymbol; + int mcount; +{ + struct minimal_symbol *copyfrom; + struct minimal_symbol *copyto; + + if (mcount > 0) + { + copyfrom = copyto = msymbol; + while (copyfrom < msymbol + mcount - 1) + { + if (copyfrom -> address == (copyfrom + 1) -> address + && (strcmp (copyfrom -> name, (copyfrom + 1) -> name) == 0)) + { + if ((copyfrom + 1) -> type == mst_unknown) + { + (copyfrom + 1) -> type = copyfrom -> type; + } + copyfrom++; + } + else + { + *copyto++ = *copyfrom++; + } + } + *copyto++ = *copyfrom++; + mcount = copyto - msymbol; + } + return (mcount); +} + +/* INCLINK nonzero means bunches are from an incrementally-linked file. + Add them to the existing bunches. + Otherwise INCLINK is zero, and we start from scratch. + + FIXME: INCLINK is currently unused, and is a holdover from when all + these symbols were stored in a shared, globally available table. If + it turns out we still need to be able to incrementally add minimal + symbols to an existing minimal symbol table for a given objfile, then + we will need to slightly modify this code so that when INCLINK is + nonzero we copy the existing table to a work area that is allocated + large enough for all the symbols and add the new ones to the end. */ + +void +install_minimal_symbols (inclink, objfile) + int inclink; + struct objfile *objfile; +{ + register int bindex; + register int mcount; + register struct msym_bunch *bunch; + register struct minimal_symbol *msymbols; + int nbytes; + + if (msym_count > 0) + { + /* Allocate a temporary work area into which we will gather the + bunches of minimal symbols, sort them, and then compact out + duplicate entries. Once we have a final table, it will be attached + to the specified objfile. */ + + msymbols = (struct minimal_symbol *) + xmalloc (msym_count * sizeof (struct minimal_symbol)); + mcount = 0; + + /* Walk through the list of minimal symbol bunches, adding each symbol + to the new contiguous array of symbols. Note that we start with the + current, possibly partially filled bunch (thus we use the current + msym_bunch_index for the first bunch we copy over), and thereafter + each bunch is full. */ + + for (bunch = msym_bunch; bunch != NULL; bunch = bunch -> next) + { + for (bindex = 0; bindex < msym_bunch_index; bindex++, mcount++) + { + msymbols[mcount] = bunch -> contents[bindex]; +#ifdef NAMES_HAVE_UNDERSCORE + if (msymbols[mcount].name[0] == '_') + { + msymbols[mcount].name++; + } +#endif +#ifdef SOME_NAMES_HAVE_DOT + if (msymbols[mcount].name[0] == '.') + { + msymbols[mcount].name++; + } +#endif + } + msym_bunch_index = BUNCH_SIZE; + } + + /* Sort the minimal symbols by address. */ + + qsort (msymbols, mcount, sizeof (struct minimal_symbol), + compare_minimal_symbols); + + /* Compact out any duplicates. The table is reallocated to a + smaller size, even though it is unnecessary here, as we are just + going to move everything to an obstack anyway. */ + + mcount = compact_minimal_symbols (msymbols, mcount); + + /* Attach the minimal symbol table to the specified objfile, allocating + the table entries in the symbol_obstack. Note that the strings them- + selves are already located in the symbol_obstack. We also terminate + the minimal symbol table with a "null symbol", which is *not* included + in the size of the table. This makes it easier to find the end of + the table when we are handed a pointer to some symbol in the middle + of it. */ + + objfile -> minimal_symbol_count = mcount; + nbytes = (mcount + 1) * sizeof (struct minimal_symbol); + objfile -> msymbols = (struct minimal_symbol *) + obstack_alloc (&objfile -> symbol_obstack, nbytes); + memcpy (objfile -> msymbols, msymbols, nbytes); + free (msymbols); + + /* Zero out the fields in the "null symbol" allocated at the end + of the array. Note that the symbol count does *not* include + this null symbol, which is why it is indexed by mcount and not + mcount-1. */ + + objfile -> msymbols[mcount].name = NULL; + objfile -> msymbols[mcount].address = 0; + objfile -> msymbols[mcount].info = NULL; + objfile -> msymbols[mcount].type = mst_unknown; + } +} + |