aboutsummaryrefslogtreecommitdiff
path: root/gdb/minsyms.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/minsyms.c')
-rw-r--r--gdb/minsyms.c491
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;
+ }
+}
+