simplesim-3.0/target-pisa/symbol.c

828 lines
22 KiB
C

/* symbol.c - program symbol and line data routines */
/* SimpleScalar(TM) Tool Suite
* Copyright (C) 1994-2003 by Todd M. Austin, Ph.D. and SimpleScalar, LLC.
* All Rights Reserved.
*
* THIS IS A LEGAL DOCUMENT, BY USING SIMPLESCALAR,
* YOU ARE AGREEING TO THESE TERMS AND CONDITIONS.
*
* No portion of this work may be used by any commercial entity, or for any
* commercial purpose, without the prior, written permission of SimpleScalar,
* LLC (info@simplescalar.com). Nonprofit and noncommercial use is permitted
* as described below.
*
* 1. SimpleScalar is provided AS IS, with no warranty of any kind, express
* or implied. The user of the program accepts full responsibility for the
* application of the program and the use of any results.
*
* 2. Nonprofit and noncommercial use is encouraged. SimpleScalar may be
* downloaded, compiled, executed, copied, and modified solely for nonprofit,
* educational, noncommercial research, and noncommercial scholarship
* purposes provided that this notice in its entirety accompanies all copies.
* Copies of the modified software can be delivered to persons who use it
* solely for nonprofit, educational, noncommercial research, and
* noncommercial scholarship purposes provided that this notice in its
* entirety accompanies all copies.
*
* 3. ALL COMMERCIAL USE, AND ALL USE BY FOR PROFIT ENTITIES, IS EXPRESSLY
* PROHIBITED WITHOUT A LICENSE FROM SIMPLESCALAR, LLC (info@simplescalar.com).
*
* 4. No nonprofit user may place any restrictions on the use of this software,
* including as modified by the user, by any other authorized user.
*
* 5. Noncommercial and nonprofit users may distribute copies of SimpleScalar
* in compiled or executable form as set forth in Section 2, provided that
* either: (A) it is accompanied by the corresponding machine-readable source
* code, or (B) it is accompanied by a written offer, with no time limit, to
* give anyone a machine-readable copy of the corresponding source code in
* return for reimbursement of the cost of distribution. This written offer
* must permit verbatim duplication by anyone, or (C) it is distributed by
* someone who received only the executable form, and is accompanied by a
* copy of the written offer of source code.
*
* 6. SimpleScalar was developed by Todd M. Austin, Ph.D. The tool suite is
* currently maintained by SimpleScalar LLC (info@simplescalar.com). US Mail:
* 2395 Timbercrest Court, Ann Arbor, MI 48105.
*
* Copyright (C) 1994-2003 by Todd M. Austin, Ph.D. and SimpleScalar, LLC.
*/
#include <stdio.h>
#include <stdlib.h>
#include "host.h"
#include "misc.h"
#ifdef BFD_LOADER
#include <bfd.h>
#else /* !BFD_LOADER */
#include "target-pisa/ecoff.h"
#endif /* BFD_LOADER */
#include "loader.h"
#include "symbol.h"
/* #define PRINT_SYMS */
/* symbol database in no particular order */
struct sym_sym_t *sym_db = NULL;
/* all symbol sorted by address */
int sym_nsyms = 0;
struct sym_sym_t **sym_syms = NULL;
/* all symbols sorted by name */
struct sym_sym_t **sym_syms_by_name = NULL;
/* text symbols sorted by address */
int sym_ntextsyms = 0;
struct sym_sym_t **sym_textsyms = NULL;
/* text symbols sorted by name */
struct sym_sym_t **sym_textsyms_by_name = NULL;
/* data symbols sorted by address */
int sym_ndatasyms = 0;
struct sym_sym_t **sym_datasyms = NULL;
/* data symbols sorted by name */
struct sym_sym_t **sym_datasyms_by_name = NULL;
/* symbols loaded? */
static int syms_loaded = FALSE;
#ifdef PRINT_SYMS
/* convert BFD symbols flags to a printable string */
static char * /* symbol flags string */
flags2str(unsigned int flags) /* bfd symbol flags */
{
static char buf[256];
char *p;
if (!flags)
return "";
p = buf;
*p = '\0';
if (flags & BSF_LOCAL)
{
*p++ = 'L';
*p++ = '|';
}
if (flags & BSF_GLOBAL)
{
*p++ = 'G';
*p++ = '|';
}
if (flags & BSF_DEBUGGING)
{
*p++ = 'D';
*p++ = '|';
}
if (flags & BSF_FUNCTION)
{
*p++ = 'F';
*p++ = '|';
}
if (flags & BSF_KEEP)
{
*p++ = 'K';
*p++ = '|';
}
if (flags & BSF_KEEP_G)
{
*p++ = 'k'; *p++ = '|';
}
if (flags & BSF_WEAK)
{
*p++ = 'W';
*p++ = '|';
}
if (flags & BSF_SECTION_SYM)
{
*p++ = 'S'; *p++ = '|';
}
if (flags & BSF_OLD_COMMON)
{
*p++ = 'O';
*p++ = '|';
}
if (flags & BSF_NOT_AT_END)
{
*p++ = 'N';
*p++ = '|';
}
if (flags & BSF_CONSTRUCTOR)
{
*p++ = 'C';
*p++ = '|';
}
if (flags & BSF_WARNING)
{
*p++ = 'w';
*p++ = '|';
}
if (flags & BSF_INDIRECT)
{
*p++ = 'I';
*p++ = '|';
}
if (flags & BSF_FILE)
{
*p++ = 'f';
*p++ = '|';
}
if (p == buf)
panic("no flags detected");
*--p = '\0';
return buf;
}
#endif /* PRINT_SYMS */
/* qsort helper function */
static int
acmp(struct sym_sym_t **sym1, struct sym_sym_t **sym2)
{
return (int)((*sym1)->addr - (*sym2)->addr);
}
/* qsort helper function */
static int
ncmp(struct sym_sym_t **sym1, struct sym_sym_t **sym2)
{
return strcmp((*sym1)->name, (*sym2)->name);
}
#define RELEVANT_SCOPE(SYM) \
(/* global symbol */ \
((SYM)->flags & BSF_GLOBAL) \
|| (/* local symbol */ \
(((SYM)->flags & (BSF_LOCAL|BSF_DEBUGGING)) == BSF_LOCAL) \
&& (SYM)->name[0] != '$') \
|| (/* compiler local */ \
load_locals \
&& ((/* basic block idents */ \
((SYM)->flags&(BSF_LOCAL|BSF_DEBUGGING))==(BSF_LOCAL|BSF_DEBUGGING)\
&& (SYM)->name[0] == '$') \
|| (/* local constant idents */ \
((SYM)->flags & (BSF_LOCAL|BSF_DEBUGGING)) == (BSF_LOCAL) \
&& (SYM)->name[0] == '$'))))
/* load symbols out of FNAME */
void
sym_loadsyms(char *fname, /* file name containing symbols */
int load_locals) /* load local symbols */
{
int i, debug_cnt;
#ifdef BFD_LOADER
bfd *abfd;
asymbol **syms;
int storage, i, nsyms, debug_cnt;
#else /* !BFD_LOADER */
int len;
FILE *fobj;
struct ecoff_filehdr fhdr;
struct ecoff_aouthdr ahdr;
struct ecoff_symhdr_t symhdr;
char *strtab = NULL;
struct ecoff_EXTR *extr;
#endif /* BFD_LOADER */
if (syms_loaded)
{
/* symbols are already loaded */
/* FIXME: can't handle symbols from multiple files */
return;
}
#ifdef BFD_LOADER
/* load the program into memory, try both endians */
if (!(abfd = bfd_openr(fname, "ss-coff-big")))
if (!(abfd = bfd_openr(fname, "ss-coff-little")))
fatal("cannot open executable `%s'", fname);
/* this call is mainly for its side effect of reading in the sections.
we follow the traditional behavior of `strings' in that we don't
complain if we don't recognize a file to be an object file. */
if (!bfd_check_format(abfd, bfd_object))
{
bfd_close(abfd);
fatal("cannot open executable `%s'", fname);
}
/* sanity check, endian should be the same as loader.c encountered */
if (abfd->xvec->byteorder_big_p != (unsigned)ld_target_big_endian)
panic("binary endian changed");
if ((bfd_get_file_flags(abfd) & (HAS_SYMS|HAS_LOCALS)))
{
/* file has locals, read them in */
storage = bfd_get_symtab_upper_bound(abfd);
if (storage <= 0)
fatal("HAS_SYMS is set, but `%s' still lacks symbols", fname);
syms = (asymbol **)calloc(storage, 1);
if (!syms)
fatal("out of virtual memory");
nsyms = bfd_canonicalize_symtab (abfd, syms);
if (nsyms <= 0)
fatal("HAS_SYMS is set, but `%s' still lacks symbols", fname);
/*
* convert symbols to local format
*/
/* first count symbols */
sym_ndatasyms = 0; sym_ntextsyms = 0;
for (i=0; i < nsyms; i++)
{
asymbol *sym = syms[i];
/* decode symbol type */
if (/* from the data section */
(!strcmp(sym->section->name, ".rdata")
|| !strcmp(sym->section->name, ".data")
|| !strcmp(sym->section->name, ".sdata")
|| !strcmp(sym->section->name, ".bss")
|| !strcmp(sym->section->name, ".sbss"))
/* from a scope we are interested in */
&& RELEVANT_SCOPE(sym))
{
/* data segment symbol */
sym_ndatasyms++;
#ifdef PRINT_SYMS
fprintf(stderr,
"+sym: %s sect: %s flags: %s value: 0x%08lx\n",
sym->name, sym->section->name, flags2str(sym->flags),
sym->value + sym->section->vma);
#endif /* PRINT_SYMS */
}
else if (/* from the text section */
!strcmp(sym->section->name, ".text")
/* from a scope we are interested in */
&& RELEVANT_SCOPE(sym))
{
/* text segment symbol */
sym_ntextsyms++;
#ifdef PRINT_SYMS
fprintf(stderr,
"+sym: %s sect: %s flags: %s value: 0x%08lx\n",
sym->name, sym->section->name, flags2str(sym->flags),
sym->value + sym->section->vma);
#endif /* PRINT_SYMS */
}
else
{
/* non-segment sections */
#ifdef PRINT_SYMS
fprintf(stderr,
"-sym: %s sect: %s flags: %s value: 0x%08lx\n",
sym->name, sym->section->name, flags2str(sym->flags),
sym->value + sym->section->vma);
#endif /* PRINT_SYMS */
}
}
sym_nsyms = sym_ntextsyms + sym_ndatasyms;
if (sym_nsyms <= 0)
fatal("`%s' has no text or data symbols", fname);
/* allocate symbol space */
sym_db = (struct sym_sym_t *)calloc(sym_nsyms, sizeof(struct sym_sym_t));
if (!sym_db)
fatal("out of virtual memory");
/* convert symbols to internal format */
for (debug_cnt=0, i=0; i < nsyms; i++)
{
asymbol *sym = syms[i];
/* decode symbol type */
if (/* from the data section */
(!strcmp(sym->section->name, ".rdata")
|| !strcmp(sym->section->name, ".data")
|| !strcmp(sym->section->name, ".sdata")
|| !strcmp(sym->section->name, ".bss")
|| !strcmp(sym->section->name, ".sbss"))
/* from a scope we are interested in */
&& RELEVANT_SCOPE(sym))
{
/* data segment symbol, insert into symbol database */
sym_db[debug_cnt].name = mystrdup((char *)sym->name);
sym_db[debug_cnt].seg = ss_data;
sym_db[debug_cnt].initialized =
(!strcmp(sym->section->name, ".rdata")
|| !strcmp(sym->section->name, ".data")
|| !strcmp(sym->section->name, ".sdata"));
sym_db[debug_cnt].pub = (sym->flags & BSF_GLOBAL);
sym_db[debug_cnt].local = (sym->name[0] == '$');
sym_db[debug_cnt].addr = sym->value + sym->section->vma;
debug_cnt++;
}
else if (/* from the text section */
!strcmp(sym->section->name, ".text")
/* from a scope we are interested in */
&& RELEVANT_SCOPE(sym))
{
/* text segment symbol, insert into symbol database */
sym_db[debug_cnt].name = mystrdup((char *)sym->name);
sym_db[debug_cnt].seg = ss_text;
sym_db[debug_cnt].initialized = /* seems reasonable */TRUE;
sym_db[debug_cnt].pub = (sym->flags & BSF_GLOBAL);
sym_db[debug_cnt].local = (sym->name[0] == '$');
sym_db[debug_cnt].addr = sym->value + sym->section->vma;
debug_cnt++;
}
else
{
/* non-segment sections */
}
}
/* sanity check */
if (debug_cnt != sym_nsyms)
panic("could not locate all counted symbols");
/* release bfd symbol storage */
free(syms);
}
/* done with file, close if */
if (!bfd_close(abfd))
fatal("could not close executable `%s'", fname);
#else /* !BFD_LOADER */
/* load the program into memory, try both endians */
#if defined(__CYGWIN32__) || defined(_MSC_VER)
fobj = fopen(fname, "rb");
#else
fobj = fopen(fname, "r");
#endif
if (!fobj)
fatal("cannot open executable `%s'", fname);
if (fread(&fhdr, sizeof(struct ecoff_filehdr), 1, fobj) < 1)
fatal("cannot read header from executable `%s'", fname);
/* record endian of target */
if (fhdr.f_magic != ECOFF_EB_MAGIC && fhdr.f_magic != ECOFF_EL_MAGIC)
fatal("bad magic number in executable `%s'", fname);
if (fread(&ahdr, sizeof(struct ecoff_aouthdr), 1, fobj) < 1)
fatal("cannot read AOUT header from executable `%s'", fname);
/* seek to the beginning of the symbolic header */
fseek(fobj, fhdr.f_symptr, 0);
if (fread(&symhdr, sizeof(struct ecoff_symhdr_t), 1, fobj) < 1)
fatal("could not read symbolic header from executable `%s'", fname);
if (symhdr.magic != ECOFF_magicSym)
fatal("bad magic number (0x%x) in symbolic header", symhdr.magic);
/* allocate space for the string table */
len = symhdr.issMax + symhdr.issExtMax;
strtab = (char *)calloc(len, sizeof(char));
if (!strtab)
fatal("out of virtual memory");
/* read all the symbol names into memory */
fseek(fobj, symhdr.cbSsOffset, 0);
if (fread(strtab, len, 1, fobj) < 0)
fatal("error while reading symbol table names");
/* allocate symbol space */
len = symhdr.isymMax + symhdr.iextMax;
if (len <= 0)
fatal("`%s' has no text or data symbols", fname);
sym_db = (struct sym_sym_t *)calloc(len, sizeof(struct sym_sym_t));
if (!sym_db)
fatal("out of virtual memory");
/* allocate space for the external symbol entries */
extr =
(struct ecoff_EXTR *)calloc(symhdr.iextMax, sizeof(struct ecoff_EXTR));
if (!extr)
fatal("out of virtual memory");
fseek(fobj, symhdr.cbExtOffset, 0);
if (fread(extr, sizeof(struct ecoff_EXTR), symhdr.iextMax, fobj) < 0)
fatal("error reading external symbol entries");
sym_nsyms = 0; sym_ndatasyms = 0; sym_ntextsyms = 0;
/* convert symbols to internal format */
for (i=0; i < symhdr.iextMax; i++)
{
int str_offset;
str_offset = symhdr.issMax + extr[i].asym.iss;
#if 0
printf("ext %2d: ifd = %2d, iss = %3d, value = %8x, st = %3x, "
"sc = %3x, index = %3x\n",
i, extr[i].ifd,
extr[i].asym.iss, extr[i].asym.value,
extr[i].asym.st, extr[i].asym.sc,
extr[i].asym.index);
printf(" %08x %2d %2d %s\n",
extr[i].asym.value,
extr[i].asym.st,
extr[i].asym.sc,
&strtab[str_offset]);
#endif
switch (extr[i].asym.st)
{
case ECOFF_stGlobal:
case ECOFF_stStatic:
/* from data segment */
sym_db[sym_nsyms].name = mystrdup(&strtab[str_offset]);
sym_db[sym_nsyms].seg = ss_data;
sym_db[sym_nsyms].initialized = /* FIXME: ??? */TRUE;
sym_db[sym_nsyms].pub = /* FIXME: ??? */TRUE;
sym_db[sym_nsyms].local = /* FIXME: ??? */FALSE;
sym_db[sym_nsyms].addr = extr[i].asym.value;
sym_nsyms++;
sym_ndatasyms++;
break;
case ECOFF_stProc:
case ECOFF_stStaticProc:
case ECOFF_stLabel:
/* from text segment */
sym_db[sym_nsyms].name = mystrdup(&strtab[str_offset]);
sym_db[sym_nsyms].seg = ss_text;
sym_db[sym_nsyms].initialized = /* FIXME: ??? */TRUE;
sym_db[sym_nsyms].pub = /* FIXME: ??? */TRUE;
sym_db[sym_nsyms].local = /* FIXME: ??? */FALSE;
sym_db[sym_nsyms].addr = extr[i].asym.value;
sym_nsyms++;
sym_ntextsyms++;
break;
default:
/* FIXME: ignored... */;
}
}
free(extr);
/* done with the executable, close it */
if (fclose(fobj))
fatal("could not close executable `%s'", fname);
#endif /* BFD_LOADER */
/*
* generate various sortings
*/
/* all symbols sorted by address and name */
sym_syms =
(struct sym_sym_t **)calloc(sym_nsyms, sizeof(struct sym_sym_t *));
if (!sym_syms)
fatal("out of virtual memory");
sym_syms_by_name =
(struct sym_sym_t **)calloc(sym_nsyms, sizeof(struct sym_sym_t *));
if (!sym_syms_by_name)
fatal("out of virtual memory");
for (debug_cnt=0, i=0; i<sym_nsyms; i++)
{
sym_syms[debug_cnt] = &sym_db[i];
sym_syms_by_name[debug_cnt] = &sym_db[i];
debug_cnt++;
}
/* sanity check */
if (debug_cnt != sym_nsyms)
panic("could not locate all symbols");
/* sort by address */
qsort(sym_syms, sym_nsyms, sizeof(struct sym_sym_t *), (void *)acmp);
/* sort by name */
qsort(sym_syms_by_name, sym_nsyms, sizeof(struct sym_sym_t *), (void *)ncmp);
/* text segment sorted by address and name */
sym_textsyms =
(struct sym_sym_t **)calloc(sym_ntextsyms, sizeof(struct sym_sym_t *));
if (!sym_textsyms)
fatal("out of virtual memory");
sym_textsyms_by_name =
(struct sym_sym_t **)calloc(sym_ntextsyms, sizeof(struct sym_sym_t *));
if (!sym_textsyms_by_name)
fatal("out of virtual memory");
for (debug_cnt=0, i=0; i<sym_nsyms; i++)
{
if (sym_db[i].seg == ss_text)
{
sym_textsyms[debug_cnt] = &sym_db[i];
sym_textsyms_by_name[debug_cnt] = &sym_db[i];
debug_cnt++;
}
}
/* sanity check */
if (debug_cnt != sym_ntextsyms)
panic("could not locate all text symbols");
/* sort by address */
qsort(sym_textsyms, sym_ntextsyms, sizeof(struct sym_sym_t *), (void *)acmp);
/* sort by name */
qsort(sym_textsyms_by_name, sym_ntextsyms,
sizeof(struct sym_sym_t *), (void *)ncmp);
/* data segment sorted by address and name */
sym_datasyms =
(struct sym_sym_t **)calloc(sym_ndatasyms, sizeof(struct sym_sym_t *));
if (!sym_datasyms)
fatal("out of virtual memory");
sym_datasyms_by_name =
(struct sym_sym_t **)calloc(sym_ndatasyms, sizeof(struct sym_sym_t *));
if (!sym_datasyms_by_name)
fatal("out of virtual memory");
for (debug_cnt=0, i=0; i<sym_nsyms; i++)
{
if (sym_db[i].seg == ss_data)
{
sym_datasyms[debug_cnt] = &sym_db[i];
sym_datasyms_by_name[debug_cnt] = &sym_db[i];
debug_cnt++;
}
}
/* sanity check */
if (debug_cnt != sym_ndatasyms)
panic("could not locate all data symbols");
/* sort by address */
qsort(sym_datasyms, sym_ndatasyms, sizeof(struct sym_sym_t *), (void *)acmp);
/* sort by name */
qsort(sym_datasyms_by_name, sym_ndatasyms,
sizeof(struct sym_sym_t *), (void *)ncmp);
/* compute symbol sizes */
for (i=0; i<sym_ntextsyms; i++)
{
sym_textsyms[i]->size =
(i != (sym_ntextsyms - 1)
? (sym_textsyms[i+1]->addr - sym_textsyms[i]->addr)
: ((ld_text_base + ld_text_size) - sym_textsyms[i]->addr));
}
for (i=0; i<sym_ndatasyms; i++)
{
sym_datasyms[i]->size =
(i != (sym_ndatasyms - 1)
? (sym_datasyms[i+1]->addr - sym_datasyms[i]->addr)
: ((ld_data_base + ld_data_size) - sym_datasyms[i]->addr));
}
/* symbols are now available for use */
syms_loaded = TRUE;
}
/* dump symbol SYM to output stream FD */
void
sym_dumpsym(struct sym_sym_t *sym, /* symbol to display */
FILE *fd) /* output stream */
{
fprintf(fd,
"sym `%s': %s seg, init-%s, pub-%s, local-%s, addr=0x%08x, size=%d\n",
sym->name,
sym->seg == ss_data ? "data" : "text",
sym->initialized ? "y" : "n",
sym->pub ? "y" : "n",
sym->local ? "y" : "n",
sym->addr,
sym->size);
}
/* dump all symbols to output stream FD */
void
sym_dumpsyms(FILE *fd) /* output stream */
{
int i;
for (i=0; i < sym_nsyms; i++)
sym_dumpsym(sym_syms[i], fd);
}
/* dump all symbol state to output stream FD */
void
sym_dumpstate(FILE *fd) /* output stream */
{
int i;
if (fd == NULL)
fd = stderr;
fprintf(fd, "** All symbols sorted by address:\n");
for (i=0; i < sym_nsyms; i++)
sym_dumpsym(sym_syms[i], fd);
fprintf(fd, "\n** All symbols sorted by name:\n");
for (i=0; i < sym_nsyms; i++)
sym_dumpsym(sym_syms_by_name[i], fd);
fprintf(fd, "** Text symbols sorted by address:\n");
for (i=0; i < sym_ntextsyms; i++)
sym_dumpsym(sym_textsyms[i], fd);
fprintf(fd, "\n** Text symbols sorted by name:\n");
for (i=0; i < sym_ntextsyms; i++)
sym_dumpsym(sym_textsyms_by_name[i], fd);
fprintf(fd, "** Data symbols sorted by address:\n");
for (i=0; i < sym_ndatasyms; i++)
sym_dumpsym(sym_datasyms[i], fd);
fprintf(fd, "\n** Data symbols sorted by name:\n");
for (i=0; i < sym_ndatasyms; i++)
sym_dumpsym(sym_datasyms_by_name[i], fd);
}
/* bind address ADDR to a symbol in symbol database DB, the address must
match exactly if EXACT is non-zero, the index of the symbol in the
requested symbol database is returned in *PINDEX if the pointer is
non-NULL */
struct sym_sym_t * /* symbol found, or NULL */
sym_bind_addr(md_addr_t addr, /* address of symbol to locate */
int *pindex, /* ptr to index result var */
int exact, /* require exact address match? */
enum sym_db_t db) /* symbol database to search */
{
int nsyms, low, high, pos;
struct sym_sym_t **syms;
switch (db)
{
case sdb_any:
syms = sym_syms;
nsyms = sym_nsyms;
break;
case sdb_text:
syms = sym_textsyms;
nsyms = sym_ntextsyms;
break;
case sdb_data:
syms = sym_datasyms;
nsyms = sym_ndatasyms;
break;
default:
panic("bogus symbol database");
}
/* any symbols to search? */
if (!nsyms)
{
if (pindex)
*pindex = -1;
return NULL;
}
/* binary search symbol database (sorted by address) */
low = 0;
high = nsyms-1;
pos = (low + high) >> 1;
while (!(/* exact match */
(exact && syms[pos]->addr == addr)
/* in bounds match */
|| (!exact
&& syms[pos]->addr <= addr
&& addr < (syms[pos]->addr + MAX(1, syms[pos]->size)))))
{
if (addr < syms[pos]->addr)
high = pos - 1;
else
low = pos + 1;
if (high >= low)
pos = (low + high) >> 1;
else
{
if (pindex)
*pindex = -1;
return NULL;
}
}
/* bound! */
if (pindex)
*pindex = pos;
return syms[pos];
}
/* bind name NAME to a symbol in symbol database DB, the index of the symbol
in the requested symbol database is returned in *PINDEX if the pointer is
non-NULL */
struct sym_sym_t * /* symbol found, or NULL */
sym_bind_name(char *name, /* symbol name to locate */
int *pindex, /* ptr to index result var */
enum sym_db_t db) /* symbol database to search */
{
int nsyms, low, high, pos, cmp;
struct sym_sym_t **syms;
switch (db)
{
case sdb_any:
syms = sym_syms_by_name;
nsyms = sym_nsyms;
break;
case sdb_text:
syms = sym_textsyms_by_name;
nsyms = sym_ntextsyms;
break;
case sdb_data:
syms = sym_datasyms_by_name;
nsyms = sym_ndatasyms;
break;
default:
panic("bogus symbol database");
}
/* any symbols to search? */
if (!nsyms)
{
if (pindex)
*pindex = -1;
return NULL;
}
/* binary search symbol database (sorted by name) */
low = 0;
high = nsyms-1;
pos = (low + high) >> 1;
while (!(/* exact string match */!(cmp = strcmp(syms[pos]->name, name))))
{
if (cmp > 0)
high = pos - 1;
else
low = pos + 1;
if (high >= low)
pos = (low + high) >> 1;
else
{
if (pindex)
*pindex = -1;
return NULL;
}
}
/* bound! */
if (pindex)
*pindex = pos;
return syms[pos];
}