[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.2

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