/* $PMDB: symbol.c,v 1.5 2002/03/07 14:27:08 art Exp $ */ /* * Copyright (c) 2002 Artur Grabowski * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "pmdb.h" #include "symbol.h" /* * Initialize the executable and the symbol table. */ void sym_init_exec(struct pstate *ps, const char *name) { ps->ps_sops = NULL; ps->ps_sym_exe = NULL; TAILQ_INIT(&ps->ps_syms); #ifdef PMDB_ELF if (sym_check_elf(name, ps)) #endif #ifdef PMDB_AOUT if (sym_check_aout(name, ps)) #endif warnx("sym_init_exec: %s is not a supported file format", name); if (ps->ps_sops) { ps->ps_sym_exe = st_open(ps, name); if (ps->ps_sym_exe) ps->ps_sym_exe->st_flags |= ST_EXEC; } } /* * Destroy all symbol tables. */ void sym_destroy(struct pstate *ps) { struct sym_table *st; while ((st = TAILQ_FIRST(&ps->ps_syms)) != NULL) { TAILQ_REMOVE(&ps->ps_syms, st, st_list); (*ps->ps_sops->sop_close)(st); } ps->ps_sym_exe = NULL; } /* * We have reasons to believe that the symbol tables we have are not consistent * with the running binary. Update. */ void sym_update(struct pstate *ps) { (*ps->ps_sops->sop_update)(ps); } char * sym_name_and_offset(struct pstate *ps, reg pc, char *nam, size_t len, reg *off) { struct sym_table *st; int bestoffisset = 0; reg bestoff, noff; char *res; TAILQ_FOREACH(st, &ps->ps_syms, st_list) { res = (*ps->ps_sops->sop_name_and_off)(st, pc, &noff); if (res == NULL) continue; if (noff < bestoff || !bestoffisset) { bestoffisset = 1; bestoff = noff; strlcpy(nam, res, len); } } if (!bestoffisset || !strcmp(nam, "_end")) return (NULL); *off = bestoff; return (nam); } int sym_lookup(struct pstate *ps, const char *name, reg *res) { /* * We let the sop do the table walking itself since it might have * preferences about what symbols to pick (weak and stuff). */ return ((*ps->ps_sops->sop_lookup)(ps, name, res)); } char * sym_print(struct pstate *ps, reg pc, char *buf, size_t buflen) { char namebuf[1024], *name; reg offs; name = sym_name_and_offset(ps, pc, namebuf, sizeof(namebuf), &offs); if (name == NULL) { snprintf(buf, buflen, "0x%lx", pc); } else { snprintf(buf, buflen, "%s+0x%lx(0x%lx)", name, offs, pc); } return (buf); } /* * Open a symbol table and install it in the list. Don't do anything if * it's already there. */ struct sym_table * st_open(struct pstate *ps, const char *name) { struct sym_table *st; TAILQ_FOREACH(st, &ps->ps_syms, st_list) { if (!strcmp(name, st->st_fname)) return (st); } warnx("Loading symbols from %s", name); if ((st = (*ps->ps_sops->sop_open)(name)) != NULL) { TAILQ_INSERT_TAIL(&ps->ps_syms, st, st_list); strlcpy(st->st_fname, name, sizeof(st->st_fname)); } return (st); }