/* $OpenBSD: symbol.c,v 1.7 2003/03/28 23:33:27 mickey 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 #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) { /* XXX - this 0 doesn't have to be correct.. */ ps->ps_sym_exe = st_open(ps, name, 0); 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; if (!(ps->ps_flags & PSF_SYMBOLS)) return; 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 { if (offs) snprintf(buf, buflen, "%s+0x%lx(0x%lx)", name, offs, pc); else snprintf(buf, buflen, "%s(0x%lx)", name, 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, reg offs) { struct sym_table *st; TAILQ_FOREACH(st, &ps->ps_syms, st_list) { if (!strcmp(name, st->st_fname) && (st->st_offs == offs)) return (st); } warnx("Loading symbols from %s at 0x%lx", name, offs); 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)); st->st_offs = offs; } return (st); } /* * Load a symbol table from file argv[1] at offset argv[2]. */ int cmd_sym_load(int argc, char **argv, void *arg) { struct pstate *ps = arg; char *fname, *ep; reg offs; fname = argv[1]; errno = 0; offs = strtol(argv[2], &ep, 0); if (argv[2][0] == '\0' || *ep != '\0' || errno == ERANGE) { fprintf(stderr, "%s is not a valid offset\n", argv[2]); return (0); } if (st_open(ps, fname, offs) == NULL) { warnx("symbol loading failed"); } return (0); }