[BACK]Return to elf_syms.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / pmdb

Annotation of src/usr.bin/pmdb/elf_syms.c, Revision 1.3

1.3     ! art         1: /*     $OpenBSD: elf_syms.c,v 1.2 2002/03/15 16:41:06 jason Exp $      */
1.1       art         2: /*
                      3:  * Copyright (c) 2002 Artur Grabowski <art@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 <nlist.h>
                     39: #ifdef __NetBSD__
                     40: #include <machine/elf_machdep.h>
                     41: #define ELFSIZE ARCH_ELFSIZE
                     42: #include <sys/exec_elf.h>
                     43: #else
                     44: #include <elf_abi.h>
                     45: #endif
                     46: #include <link.h>
                     47:
                     48: #include "pmdb.h"
                     49: #include "symbol.h"
                     50: #include "break.h"
                     51:
                     52: struct elf_symbol_handle {
                     53:        struct sym_table esh_st;
                     54:        int             esh_fd;
                     55:        char            *esh_strtab;
                     56:        Elf_Word        esh_strsize;
                     57:        Elf_Sym         *esh_symtab;
                     58:        Elf_Word        esh_symsize;
                     59: };
                     60:
                     61: #define ESH_TO_ST(esh) (&(esh)->esh_st)
                     62: #define ST_TO_ESH(st) ((struct elf_symbol_handle *)(st))
                     63:
                     64: struct sym_table *elf_open(const char *);
                     65: void elf_close(struct sym_table *);
                     66: char *elf_name_and_off(struct sym_table *, reg, reg *);
                     67: int elf_lookup(struct pstate *, const char *, reg *);
                     68: void elf_update(struct pstate *);
                     69:
                     70: struct sym_ops elf_sops = {
                     71:        elf_open,
                     72:        elf_close,
                     73:        elf_name_and_off,
                     74:        elf_lookup,
                     75:        elf_update
                     76: };
                     77:
                     78: int
                     79: sym_check_elf(const char *name, struct pstate *ps)
                     80: {
                     81:        Elf_Ehdr ehdr;
                     82:        int fd;
                     83:
                     84:        if ((fd = open(name, O_RDONLY)) < 0)
                     85:                return (-1);
                     86:
                     87:        if (pread(fd, &ehdr, sizeof(Elf_Ehdr), 0) != sizeof(Elf_Ehdr))
                     88:                return (-1);
                     89:
                     90: #ifndef __NetBSD__
                     91:        if (!IS_ELF(ehdr) ||
                     92:            ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS ||
                     93:            ehdr.e_ident[EI_DATA] != ELF_TARG_DATA ||
                     94:            ehdr.e_ident[EI_VERSION] != ELF_TARG_VER ||
                     95:            ehdr.e_machine != ELF_TARG_MACH ||
                     96:            ehdr.e_version != ELF_TARG_VER)
                     97:                return (-1);
                     98: #endif
                     99:
                    100:        close(fd);
                    101:
                    102:        ps->ps_sops = &elf_sops;
                    103:
                    104:        return (0);
                    105: }
                    106:
                    107: struct sym_table *
                    108: elf_open(const char *name)
                    109: {
                    110:        struct elf_symbol_handle *esh;
                    111:        Elf_Off symoff, stroff;
                    112:        Elf_Ehdr ehdr;
                    113:        Elf_Shdr *shdr;
                    114:        int i, fd;
                    115:
                    116:        /* Just a sanity check */
                    117:        if (sizeof(reg) != sizeof(Elf_Addr))
                    118:                errx(1, "sym_open: sizeof(reg) != sizeof(Elf_Addr)");
                    119:
                    120:        if ((esh = malloc(sizeof(*esh))) == NULL) {
                    121:                return (NULL);
                    122:        }
                    123:
                    124:        memset(esh, 0, sizeof(*esh));
                    125:        esh->esh_fd = -1;
                    126:
                    127:        if ((fd = esh->esh_fd = open(name, O_RDONLY)) < 0) {
                    128:                goto fail;
                    129:        }
                    130:
                    131:        if (pread(fd, &ehdr, sizeof(Elf_Ehdr), 0) != sizeof(Elf_Ehdr)) {
                    132:                goto fail;
                    133:        }
                    134: #ifndef __NetBSD__
                    135:        if (!IS_ELF(ehdr) ||
                    136:            ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS ||
                    137:            ehdr.e_ident[EI_DATA] != ELF_TARG_DATA ||
                    138:            ehdr.e_ident[EI_VERSION] != ELF_TARG_VER ||
                    139:            ehdr.e_machine != ELF_TARG_MACH ||
                    140:            ehdr.e_version != ELF_TARG_VER) {
                    141:                goto fail;
                    142:        }
                    143: #endif
                    144:
                    145:        if ((shdr = (Elf_Shdr *)mmap(NULL, ehdr.e_shentsize * ehdr.e_shnum,
                    146:            PROT_READ, MAP_SHARED, fd, ehdr.e_shoff)) == MAP_FAILED) {
                    147:                goto fail;
                    148:        }
                    149:
                    150:        for (i = 0; i < ehdr.e_shnum; i++) {
                    151:                if (shdr[i].sh_type == SHT_SYMTAB) {
                    152:                        symoff = shdr[i].sh_offset;
                    153:                        esh->esh_symsize = shdr[i].sh_size;
                    154:                        stroff = shdr[shdr[i].sh_link].sh_offset;
                    155:                        esh->esh_strsize = shdr[shdr[i].sh_link].sh_size;
                    156:                        break;
                    157:                }
                    158:        }
                    159:
                    160:        munmap(shdr, ehdr.e_shentsize * ehdr.e_shnum);
                    161:
                    162:        if (i == ehdr.e_shnum) {
                    163:                goto fail;
                    164:        }
                    165:
                    166:        if ((esh->esh_strtab = mmap(NULL, esh->esh_strsize, PROT_READ,
                    167:            MAP_SHARED, fd, stroff)) == MAP_FAILED) {
                    168:                goto fail;
                    169:        }
                    170:
                    171:        if ((esh->esh_symtab = mmap(NULL, esh->esh_symsize, PROT_READ,
                    172:            MAP_SHARED, fd, symoff)) == MAP_FAILED) {
                    173:                goto fail;
                    174:        }
                    175:
                    176:        return (ESH_TO_ST(esh));
                    177: fail:
                    178:
                    179:        elf_close(ESH_TO_ST(esh));
                    180:        return (NULL);
                    181: }
                    182:
                    183: void
                    184: elf_close(struct sym_table *st)
                    185: {
                    186:        struct elf_symbol_handle *esh = ST_TO_ESH(st);
                    187:
                    188:        if (esh->esh_fd != -1)
                    189:                close(esh->esh_fd);
                    190:
                    191:        munmap(esh->esh_strtab, esh->esh_strsize);
                    192:        munmap(esh->esh_symtab, esh->esh_symsize);
                    193:        free(esh);
                    194: }
                    195:
                    196: char *
                    197: elf_name_and_off(struct sym_table *st, reg pc, reg *offs)
                    198: {
                    199:        struct elf_symbol_handle *esh = ST_TO_ESH(st);
                    200:        Elf_Sym *s, *bests = NULL;
                    201:        Elf_Addr bestoff = 0;
                    202:        int nsyms, i;
                    203:        char *symn;
                    204:
1.3     ! art       205: #define SYMVAL(S) (unsigned long)((S)->st_value + st->st_offs)
1.1       art       206:
                    207:        nsyms = esh->esh_symsize / sizeof(Elf_Sym);
                    208:
                    209:        bests = NULL;
                    210:        for (i = 0; i < nsyms; i++) {
                    211:                s = &esh->esh_symtab[i];
                    212:
                    213:                if (s->st_value == 0 ||
                    214:                    s->st_shndx == 0 ||
                    215:                    (ELF_ST_BIND(s->st_info) != STB_GLOBAL &&
                    216:                     ELF_ST_BIND(s->st_info) != STB_WEAK &&
                    217:                     ELF_ST_BIND(s->st_info) != STB_LOCAL))
                    218:                        continue;
                    219:                symn = &esh->esh_strtab[s->st_name];
                    220:                if (SYMVAL(s) <= pc && SYMVAL(s) > bestoff &&
                    221:                    symn[0] != '\0' && strcmp(symn, "gcc2_compiled.")) {
                    222:                        bests = s;
                    223:                        bestoff = SYMVAL(s);
                    224:                }
                    225:        }
                    226:
                    227:        if ((s = bests) == NULL)
                    228:                return (NULL);
                    229:
                    230:        *offs = pc - SYMVAL(s);
                    231:
                    232:        return &esh->esh_strtab[s->st_name];
                    233: }
                    234:
                    235: static Elf_Sym *
                    236: elf_lookup_table(struct elf_symbol_handle *esh, const char *name)
                    237: {
                    238:        int nsyms, i;
                    239:        char *symn;
                    240:        Elf_Sym *s = NULL;
                    241:
                    242:        /* XXX - dumb, doesn't follow the rules (weak, hash, etc.). */
                    243:        nsyms = esh->esh_symsize / sizeof(Elf_Sym);
                    244:        for (i = 0; i < nsyms; i++) {
                    245:                s = &esh->esh_symtab[i];
                    246:                symn = &esh->esh_strtab[s->st_name];
                    247:                if (strcmp(name, symn) == 0)
                    248:                        break;
                    249:        }
                    250:        if (i == nsyms)
                    251:                return (NULL);
                    252:
                    253:        return (s);
                    254: }
                    255:
                    256: int
                    257: elf_lookup(struct pstate *ps, const char *name, reg *res)
                    258: {
                    259:        struct sym_table *st;
                    260:        Elf_Sym *s;
                    261:
                    262:        TAILQ_FOREACH(st, &ps->ps_syms, st_list) {
                    263:                if ((s = elf_lookup_table(ST_TO_ESH(st), name)) != NULL)
                    264:                        break;
                    265:        }
                    266:
                    267:        if (s != NULL) {
1.3     ! art       268:                *res = s->st_value + st->st_offs;
1.1       art       269:                return (0);
                    270:        }
                    271:
                    272:        return (-1);
                    273: }
                    274:
                    275: #ifndef __NetBSD__
                    276: struct elf_object_v1 {
                    277:        Elf_Addr load_addr;
                    278:        Elf_Addr load_offs;
                    279:        char *load_name;
                    280:        Elf_Dyn *load_dyn;
                    281:        struct elf_object_v1 *next;
                    282:        struct elf_object_v1 *prev;
                    283:        void *load_list;
                    284:        u_int32_t load_size;
                    285:        u_long info[DT_NUM + DT_PROCNUM];
                    286:        struct elf_object_v1 *dep_next;
                    287:        int status;
                    288:        Elf_Phdr *phdrp;
                    289:        int phdrc;
                    290:        int refcount;
                    291:        int obj_type;
                    292: #define EOBJ1_LDR 1
                    293: #define EOBJ1_EXE 2
                    294: #define EOBJ1_LIB 3
                    295: #define EOBJ1_DLO 4
                    296: };
                    297: #endif
                    298:
                    299: /*
                    300:  * dlopen breakpoint (XXX make this generic?)
                    301:  */
                    302: int
                    303: sym_bkpt(struct pstate *ps, void *arg)
                    304: {
                    305:        fprintf(stderr, "pmdb: shared lib changed\n");
                    306:
                    307:        sym_update(ps);
                    308:
                    309:        return BKPT_KEEP_CONT;
                    310: }
                    311:
                    312: /*
                    313:  * Called after execution started so that we can load any dynamic symbols.
                    314:  */
                    315: void
                    316: elf_update(struct pstate *ps)
                    317: {
                    318: #ifndef __NetBSD__
                    319:        pid_t pid = ps->ps_pid;
                    320:        struct elf_object_v1 eobj;
                    321:        struct r_debug rdeb;
                    322:        reg addr;
                    323:        Elf_Dyn dyn;
                    324:        static int bkpt_set;
                    325:        Elf_Sym *s;
                    326:
                    327:        if ((s = elf_lookup_table(ST_TO_ESH(ps->ps_sym_exe), "_DYNAMIC")) == NULL) {
                    328:                warnx("Can't find _DYNAMIC");
                    329:                return;
                    330:        }
1.3     ! art       331:        addr = s->st_value + ps->ps_sym_exe->st_offs;
1.1       art       332:
                    333:        do {
                    334:                if (read_from_pid(pid, addr, &dyn, sizeof(dyn)) < 0) {
                    335:                        warnx("Can't read _DYNAMIC");
                    336:                        return;
                    337:                }
                    338:                addr += sizeof(dyn);
                    339:        } while (dyn.d_tag != 0 && dyn.d_tag != DT_DEBUG);
                    340:
                    341:        if (dyn.d_tag == 0) {
                    342:                warnx("Can't find DT_DEBUG");
                    343:                return;
                    344:        }
                    345:
                    346:        if (read_from_pid(pid, dyn.d_un.d_ptr, &rdeb, sizeof(rdeb)) < 0) {
                    347:                warnx("Can't read DT_DEBUG");
                    348:                return;
                    349:        }
                    350:
                    351:        if (rdeb.r_version != 1) {
                    352:                warn("Can't handle debug map version %d", rdeb.r_version);
                    353:                return;
                    354:        }
                    355:        if (rdeb.r_state != RT_CONSISTENT) {
                    356:                warn("debug map not consistent: %d", rdeb.r_state);
                    357:                return;
                    358:        }
                    359:
                    360:        if (!bkpt_set) {
                    361:                if (bkpt_add_cb(ps, rdeb.r_brk, sym_bkpt, NULL))
                    362:                        warn("sym_exec: can't set bkpt");
                    363:                bkpt_set = 1;
                    364:        }
                    365:
                    366:        addr = (Elf_Addr)rdeb.r_map;
                    367:        while (addr != 0 && addr != -1) {
                    368:                char fname[MAXPATHLEN];
                    369:                int i;
                    370:
                    371:                if (read_from_pid(pid, addr, &eobj, sizeof(eobj)) < 0) {
                    372:                        warnx("Can't read symbols...");
                    373:                        return;
                    374:                }
                    375:
                    376:                addr = (Elf_Addr)eobj.next;
                    377:
                    378:                if (eobj.load_name == NULL || eobj.load_name == (char *)-1)
                    379:                        continue;
                    380:                if (read_from_pid(pid, (Elf_Addr)eobj.load_name, fname,
                    381:                    sizeof(fname)) < 0) {
                    382:                        warnx("Can't read symbols...");
                    383:                        return;
                    384:                }
                    385:
                    386:                /* sanity check the file name */
                    387:                for (i = 0; i < MAXPATHLEN; i++)
                    388:                        if (fname[i] == '\0')
                    389:                                break;
                    390:                if (i == MAXPATHLEN)
                    391:                        continue;
                    392:
1.3     ! art       393:                if (st_open(ps, fname, eobj.load_offs) == NULL)
1.1       art       394:                        warn("symbol loading failed");
                    395:        }
                    396: #endif
                    397: }