Annotation of src/usr.bin/pmdb/aout_syms.c, Revision 1.1
1.1 ! art 1: /* $PMDB: aout_syms.c,v 1.17 2002/03/11 21:46:12 art Exp $ */
! 2: /*
! 3: * Copyright (c) 2002 Federico Schwindt <fgsch@openbsd.org>
! 4: * All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: *
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. The name of the author may not be used to endorse or promote products
! 13: * derived from this software without specific prior written permission.
! 14: *
! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
! 16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
! 17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
! 18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
! 19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
! 21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
! 22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
! 23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! 24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 25: */
! 26:
! 27: #include <stdio.h>
! 28: #include <stdlib.h>
! 29: #include <unistd.h>
! 30: #include <fcntl.h>
! 31: #include <string.h>
! 32: #include <err.h>
! 33:
! 34: #include <sys/param.h>
! 35: #include <sys/ptrace.h>
! 36: #include <sys/mman.h>
! 37:
! 38: #include <sys/types.h>
! 39: #include <a.out.h>
! 40: #include <link.h>
! 41:
! 42: #include "pmdb.h"
! 43: #include "symbol.h"
! 44:
! 45: #if defined(__OpenBSD__) && (OpenBSD < 200106)
! 46: /* OpenBSD prior to 2.9 have a broken pread on big-endian archs. */
! 47: #define IGNORE_PREAD_ERRORS
! 48: #endif
! 49:
! 50: struct aout_symbol_handle {
! 51: struct sym_table ash_st;
! 52: int ash_fd;
! 53: char *ash_strtab;
! 54: u_int32_t ash_strsize;
! 55: struct nlist *ash_symtab;
! 56: int ash_symsize;
! 57: int ash_offs;
! 58: };
! 59:
! 60: #define ASH_TO_ST(ash) (&(ash)->ash_st)
! 61: #define ST_TO_ASH(st) ((struct aout_symbol_handle *)(st))
! 62:
! 63: struct sym_table *aout_open(const char *);
! 64: void aout_close(struct sym_table *);
! 65: char *aout_name_and_off(struct sym_table *, reg, reg *);
! 66: int aout_lookup(struct pstate *, const char *, reg *);
! 67: void aout_update(struct pstate *);
! 68:
! 69: struct sym_ops aout_sops = {
! 70: aout_open,
! 71: aout_close,
! 72: aout_name_and_off,
! 73: aout_lookup,
! 74: aout_update
! 75: };
! 76:
! 77: int
! 78: sym_check_aout(const char *name, struct pstate *ps)
! 79: {
! 80: struct exec ahdr;
! 81: int fd;
! 82:
! 83: if ((fd = open(name, O_RDONLY)) < 0)
! 84: return (-1);
! 85:
! 86: if (pread(fd, &ahdr, sizeof(ahdr), 0) != sizeof(ahdr)) {
! 87: #ifndef IGNORE_PREAD_ERRORS
! 88: return (-1);
! 89: #endif
! 90: }
! 91:
! 92: if (N_BADMAG(ahdr)) {
! 93: return (-1);
! 94: }
! 95:
! 96: close(fd);
! 97:
! 98: ps->ps_sops = &aout_sops;
! 99:
! 100: return (0);
! 101: }
! 102:
! 103: struct sym_table *
! 104: aout_open(const char *name)
! 105: {
! 106: struct aout_symbol_handle *ash;
! 107: u_int32_t symoff, stroff;
! 108: struct exec ahdr;
! 109:
! 110: if ((ash = malloc(sizeof(*ash))) == NULL) {
! 111: return NULL;
! 112: }
! 113:
! 114: memset(ash, 0, sizeof(*ash));
! 115: ash->ash_fd = -1;
! 116:
! 117: if ((ash->ash_fd = open(name, O_RDONLY)) < 0) {
! 118: warn("open(%s)", name);
! 119: goto fail;
! 120: }
! 121:
! 122: if (pread(ash->ash_fd, &ahdr, sizeof(ahdr), 0) != sizeof(ahdr)) {
! 123: #ifndef IGNORE_PREAD_ERRORS
! 124: warn("pread(header)");
! 125: goto fail;
! 126: #endif
! 127: }
! 128:
! 129: if (N_BADMAG(ahdr)) {
! 130: warnx("Bad magic.");
! 131: goto fail;
! 132: }
! 133:
! 134: symoff = N_SYMOFF(ahdr);
! 135: ash->ash_symsize = ahdr.a_syms;
! 136: stroff = N_STROFF(ahdr);
! 137:
! 138: if (pread(ash->ash_fd, &ash->ash_strsize, sizeof(u_int32_t),
! 139: stroff) != sizeof(u_int32_t)) {
! 140: #ifndef IGNORE_PREAD_ERRORS
! 141: warn("pread(strsize)");
! 142: goto fail;
! 143: #endif
! 144: }
! 145:
! 146: if ((ash->ash_strtab = mmap(NULL, ash->ash_strsize, PROT_READ,
! 147: MAP_SHARED, ash->ash_fd, stroff)) == MAP_FAILED) {
! 148: warn("mmap(strtab)");
! 149: goto fail;
! 150: }
! 151:
! 152: if ((ash->ash_symtab = mmap(NULL, ash->ash_symsize, PROT_READ,
! 153: MAP_SHARED, ash->ash_fd, symoff)) == MAP_FAILED) {
! 154: warn("mmap(symtab)");
! 155: goto fail;
! 156: }
! 157:
! 158: return (ASH_TO_ST(ash));
! 159: fail:
! 160:
! 161: aout_close(ASH_TO_ST(ash));
! 162: return (NULL);
! 163: }
! 164:
! 165: void
! 166: aout_close(struct sym_table *st)
! 167: {
! 168: struct aout_symbol_handle *ash = ST_TO_ASH(st);
! 169:
! 170: if (ash->ash_fd != -1)
! 171: close(ash->ash_fd);
! 172:
! 173: munmap(ash->ash_strtab, ash->ash_strsize);
! 174: munmap(ash->ash_symtab, ash->ash_symsize);
! 175: free(ash);
! 176: }
! 177:
! 178: char *
! 179: aout_name_and_off(struct sym_table *st, reg pc, reg *offs)
! 180: {
! 181: struct aout_symbol_handle *ash = ST_TO_ASH(st);
! 182: struct nlist *s, *bests = NULL;
! 183: int bestoff = 0;
! 184: int nsyms, i;
! 185: char *symn;
! 186:
! 187: #define SYMVAL(S) (unsigned long)((S)->n_value + ash->ash_offs)
! 188:
! 189: nsyms = ash->ash_symsize / sizeof(struct nlist);
! 190:
! 191: bests = NULL;
! 192: for (i = 0; i < nsyms; i++) {
! 193: s = &ash->ash_symtab[i];
! 194:
! 195: if (s->n_value == 0 ||
! 196: s->n_un.n_strx == 0)
! 197: continue;
! 198:
! 199: symn = &ash->ash_strtab[s->n_un.n_strx];
! 200: if (SYMVAL(s) <= pc && SYMVAL(s) > bestoff &&
! 201: symn[0] != '\0' && strcmp(symn, "gcc2_compiled.")) {
! 202: bests = s;
! 203: bestoff = SYMVAL(s);
! 204: }
! 205: }
! 206:
! 207: if ((s = bests) == NULL)
! 208: return (NULL);
! 209:
! 210: *offs = pc - SYMVAL(s);
! 211:
! 212: return &ash->ash_strtab[s->n_un.n_strx];
! 213: }
! 214:
! 215: static struct nlist *
! 216: aout_lookup_table(struct aout_symbol_handle *ash, const char *name)
! 217: {
! 218: int nsyms, i;
! 219: char *symn;
! 220: struct nlist *s = NULL;
! 221:
! 222: nsyms = ash->ash_symsize / sizeof(struct nlist);
! 223: for (i = 0; i < nsyms; i++) {
! 224: s = &ash->ash_symtab[i];
! 225: symn = &ash->ash_strtab[s->n_un.n_strx];
! 226: if (strcmp(name, symn) == 0)
! 227: break;
! 228: }
! 229:
! 230: if (i == nsyms)
! 231: return (NULL);
! 232:
! 233: return (s);
! 234: }
! 235:
! 236: int
! 237: aout_lookup(struct pstate *ps, const char *name, reg *res)
! 238: {
! 239: struct sym_table *st;
! 240: struct nlist *s;
! 241: int first = 1;
! 242: char *sname = (char *)name;
! 243:
! 244: restart:
! 245: TAILQ_FOREACH(st, &ps->ps_syms, st_list) {
! 246: if ((s = aout_lookup_table(ST_TO_ASH(st), sname)) != NULL)
! 247: break;
! 248: }
! 249:
! 250: if (!first)
! 251: free(sname);
! 252:
! 253: if (s == NULL) {
! 254: if (first) {
! 255: asprintf(&sname, "_%s", sname);
! 256: if (sname != NULL) {
! 257: first = 0;
! 258: goto restart;
! 259: }
! 260: }
! 261:
! 262: return (-1);
! 263: }
! 264:
! 265: *res = s->n_value + ST_TO_ASH(st)->ash_offs;
! 266: return (0);
! 267: }
! 268:
! 269: /*
! 270: * Called after execution started so that we can load any dynamic symbols.
! 271: */
! 272: void
! 273: aout_update(struct pstate *ps)
! 274: {
! 275: pid_t pid = ps->ps_pid;
! 276: struct _dynamic dyn;
! 277: struct so_debug sdeb;
! 278: struct section_dispatch_table sdt;
! 279: struct so_map som;
! 280: off_t somp;
! 281: reg addr;
! 282: struct nlist *s;
! 283:
! 284: if ((s = aout_lookup_table(ST_TO_ASH(ps->ps_sym_exe), "__DYNAMIC")) == NULL) {
! 285: warnx("Can't find __DYNAMIC");
! 286: return;
! 287: }
! 288: addr = s->n_value + ST_TO_ASH(ps->ps_sym_exe)->ash_offs;
! 289:
! 290: if (read_from_pid(pid, addr, &dyn, sizeof(dyn)) < 0) {
! 291: warn("Can't read __DYNAMIC");
! 292: return;
! 293: }
! 294:
! 295: if (dyn.d_version != LD_VERSION_BSD) {
! 296: warn("Can't handle __DYNAMIC version %d", dyn.d_version);
! 297: return;
! 298: }
! 299:
! 300: if (read_from_pid(pid, (off_t)(reg)dyn.d_debug, &sdeb, sizeof(sdeb)) < 0) {
! 301: warn("Can't read __DYNAMIC.d_debug");
! 302: return;
! 303: }
! 304:
! 305: if (sdeb.dd_version != 0) {
! 306: warn("Can't handle so_debug version %d", sdeb.dd_version);
! 307: return;
! 308: }
! 309:
! 310: if (read_from_pid(pid, (off_t)(reg)dyn.d_un.d_sdt, &sdt, sizeof(sdt)) < 0) {
! 311: warn("Can't read section dispatch table");
! 312: return;
! 313: }
! 314:
! 315: somp = (off_t)(reg)sdt.sdt_loaded;
! 316: while (somp) {
! 317: struct sym_table *st;
! 318: char fname[MAXPATHLEN];
! 319: int i;
! 320:
! 321: if (read_from_pid(pid, somp, &som, sizeof(som)) < 0) {
! 322: warn("Can't read so_map");
! 323: break;
! 324: }
! 325: somp = (off_t)(reg)som.som_next;
! 326: if (read_from_pid(pid, (off_t)(reg)som.som_path, fname,
! 327: sizeof(fname)) < 0) {
! 328: warn("Can't read so filename");
! 329: continue;
! 330: }
! 331:
! 332: /* sanity check the file name */
! 333: for (i = 0; i < MAXPATHLEN; i++)
! 334: if (fname[i] == '\0')
! 335: break;
! 336: if (i == MAXPATHLEN) {
! 337: warnx("so filename invalid");
! 338: continue;
! 339: }
! 340:
! 341: st = st_open(ps, fname);
! 342: if (st == NULL) {
! 343: warn("symbol loading failed");
! 344: continue;
! 345: }
! 346: ST_TO_ASH(st)->ash_offs = (int)som.som_addr;
! 347: }
! 348: }