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

1.4     ! fgsch       1: /*     $OpenBSD: elf_syms.c,v 1.3 2002/03/15 17:49:51 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: };
                     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;
1.4     ! fgsch      82:        int error = 0;
1.1       art        83:        int fd;
                     84:
                     85:        if ((fd = open(name, O_RDONLY)) < 0)
1.4     ! fgsch      86:                return (1);
1.1       art        87:
                     88:        if (pread(fd, &ehdr, sizeof(Elf_Ehdr), 0) != sizeof(Elf_Ehdr))
1.4     ! fgsch      89:                error = 1;
1.1       art        90:
                     91: #ifndef __NetBSD__
1.4     ! fgsch      92:        if (!error && !IS_ELF(ehdr) ||
1.1       art        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)
1.4     ! fgsch      98:                error = 1;
1.1       art        99: #endif
                    100:
                    101:        close(fd);
                    102:
1.4     ! fgsch     103:        if (!error)
        !           104:                ps->ps_sops = &elf_sops;
1.1       art       105:
1.4     ! fgsch     106:        return (error);
1.1       art       107: }
                    108:
                    109: struct sym_table *
                    110: elf_open(const char *name)
                    111: {
                    112:        struct elf_symbol_handle *esh;
                    113:        Elf_Off symoff, stroff;
                    114:        Elf_Ehdr ehdr;
                    115:        Elf_Shdr *shdr;
                    116:        int i, fd;
                    117:
                    118:        /* Just a sanity check */
                    119:        if (sizeof(reg) != sizeof(Elf_Addr))
                    120:                errx(1, "sym_open: sizeof(reg) != sizeof(Elf_Addr)");
                    121:
                    122:        if ((esh = malloc(sizeof(*esh))) == NULL) {
                    123:                return (NULL);
                    124:        }
                    125:
                    126:        memset(esh, 0, sizeof(*esh));
                    127:        esh->esh_fd = -1;
                    128:
                    129:        if ((fd = esh->esh_fd = open(name, O_RDONLY)) < 0) {
                    130:                goto fail;
                    131:        }
                    132:
                    133:        if (pread(fd, &ehdr, sizeof(Elf_Ehdr), 0) != sizeof(Elf_Ehdr)) {
                    134:                goto fail;
                    135:        }
                    136: #ifndef __NetBSD__
                    137:        if (!IS_ELF(ehdr) ||
                    138:            ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS ||
                    139:            ehdr.e_ident[EI_DATA] != ELF_TARG_DATA ||
                    140:            ehdr.e_ident[EI_VERSION] != ELF_TARG_VER ||
                    141:            ehdr.e_machine != ELF_TARG_MACH ||
                    142:            ehdr.e_version != ELF_TARG_VER) {
                    143:                goto fail;
                    144:        }
                    145: #endif
                    146:
                    147:        if ((shdr = (Elf_Shdr *)mmap(NULL, ehdr.e_shentsize * ehdr.e_shnum,
                    148:            PROT_READ, MAP_SHARED, fd, ehdr.e_shoff)) == MAP_FAILED) {
                    149:                goto fail;
                    150:        }
                    151:
                    152:        for (i = 0; i < ehdr.e_shnum; i++) {
                    153:                if (shdr[i].sh_type == SHT_SYMTAB) {
                    154:                        symoff = shdr[i].sh_offset;
                    155:                        esh->esh_symsize = shdr[i].sh_size;
                    156:                        stroff = shdr[shdr[i].sh_link].sh_offset;
                    157:                        esh->esh_strsize = shdr[shdr[i].sh_link].sh_size;
                    158:                        break;
                    159:                }
                    160:        }
                    161:
                    162:        munmap(shdr, ehdr.e_shentsize * ehdr.e_shnum);
                    163:
                    164:        if (i == ehdr.e_shnum) {
                    165:                goto fail;
                    166:        }
                    167:
                    168:        if ((esh->esh_strtab = mmap(NULL, esh->esh_strsize, PROT_READ,
                    169:            MAP_SHARED, fd, stroff)) == MAP_FAILED) {
                    170:                goto fail;
                    171:        }
                    172:
                    173:        if ((esh->esh_symtab = mmap(NULL, esh->esh_symsize, PROT_READ,
                    174:            MAP_SHARED, fd, symoff)) == MAP_FAILED) {
                    175:                goto fail;
                    176:        }
                    177:
                    178:        return (ESH_TO_ST(esh));
                    179: fail:
                    180:
                    181:        elf_close(ESH_TO_ST(esh));
                    182:        return (NULL);
                    183: }
                    184:
                    185: void
                    186: elf_close(struct sym_table *st)
                    187: {
                    188:        struct elf_symbol_handle *esh = ST_TO_ESH(st);
                    189:
                    190:        if (esh->esh_fd != -1)
                    191:                close(esh->esh_fd);
                    192:
                    193:        munmap(esh->esh_strtab, esh->esh_strsize);
                    194:        munmap(esh->esh_symtab, esh->esh_symsize);
                    195:        free(esh);
                    196: }
                    197:
                    198: char *
                    199: elf_name_and_off(struct sym_table *st, reg pc, reg *offs)
                    200: {
                    201:        struct elf_symbol_handle *esh = ST_TO_ESH(st);
                    202:        Elf_Sym *s, *bests = NULL;
                    203:        Elf_Addr bestoff = 0;
                    204:        int nsyms, i;
                    205:        char *symn;
                    206:
1.3       art       207: #define SYMVAL(S) (unsigned long)((S)->st_value + st->st_offs)
1.1       art       208:
                    209:        nsyms = esh->esh_symsize / sizeof(Elf_Sym);
                    210:
                    211:        bests = NULL;
                    212:        for (i = 0; i < nsyms; i++) {
                    213:                s = &esh->esh_symtab[i];
                    214:
                    215:                if (s->st_value == 0 ||
                    216:                    s->st_shndx == 0 ||
                    217:                    (ELF_ST_BIND(s->st_info) != STB_GLOBAL &&
                    218:                     ELF_ST_BIND(s->st_info) != STB_WEAK &&
                    219:                     ELF_ST_BIND(s->st_info) != STB_LOCAL))
                    220:                        continue;
                    221:                symn = &esh->esh_strtab[s->st_name];
                    222:                if (SYMVAL(s) <= pc && SYMVAL(s) > bestoff &&
                    223:                    symn[0] != '\0' && strcmp(symn, "gcc2_compiled.")) {
                    224:                        bests = s;
                    225:                        bestoff = SYMVAL(s);
                    226:                }
                    227:        }
                    228:
                    229:        if ((s = bests) == NULL)
                    230:                return (NULL);
                    231:
                    232:        *offs = pc - SYMVAL(s);
                    233:
                    234:        return &esh->esh_strtab[s->st_name];
                    235: }
                    236:
                    237: static Elf_Sym *
                    238: elf_lookup_table(struct elf_symbol_handle *esh, const char *name)
                    239: {
                    240:        int nsyms, i;
                    241:        char *symn;
                    242:        Elf_Sym *s = NULL;
                    243:
                    244:        /* XXX - dumb, doesn't follow the rules (weak, hash, etc.). */
                    245:        nsyms = esh->esh_symsize / sizeof(Elf_Sym);
                    246:        for (i = 0; i < nsyms; i++) {
                    247:                s = &esh->esh_symtab[i];
                    248:                symn = &esh->esh_strtab[s->st_name];
                    249:                if (strcmp(name, symn) == 0)
                    250:                        break;
                    251:        }
                    252:        if (i == nsyms)
                    253:                return (NULL);
                    254:
                    255:        return (s);
                    256: }
                    257:
                    258: int
                    259: elf_lookup(struct pstate *ps, const char *name, reg *res)
                    260: {
                    261:        struct sym_table *st;
                    262:        Elf_Sym *s;
                    263:
                    264:        TAILQ_FOREACH(st, &ps->ps_syms, st_list) {
                    265:                if ((s = elf_lookup_table(ST_TO_ESH(st), name)) != NULL)
                    266:                        break;
                    267:        }
                    268:
                    269:        if (s != NULL) {
1.3       art       270:                *res = s->st_value + st->st_offs;
1.1       art       271:                return (0);
                    272:        }
                    273:
                    274:        return (-1);
                    275: }
                    276:
                    277: #ifndef __NetBSD__
                    278: struct elf_object_v1 {
                    279:        Elf_Addr load_addr;
                    280:        Elf_Addr load_offs;
                    281:        char *load_name;
                    282:        Elf_Dyn *load_dyn;
                    283:        struct elf_object_v1 *next;
                    284:        struct elf_object_v1 *prev;
                    285:        void *load_list;
                    286:        u_int32_t load_size;
                    287:        u_long info[DT_NUM + DT_PROCNUM];
                    288:        struct elf_object_v1 *dep_next;
                    289:        int status;
                    290:        Elf_Phdr *phdrp;
                    291:        int phdrc;
                    292:        int refcount;
                    293:        int obj_type;
                    294: #define EOBJ1_LDR 1
                    295: #define EOBJ1_EXE 2
                    296: #define EOBJ1_LIB 3
                    297: #define EOBJ1_DLO 4
                    298: };
                    299: #endif
                    300:
                    301: /*
                    302:  * dlopen breakpoint (XXX make this generic?)
                    303:  */
                    304: int
                    305: sym_bkpt(struct pstate *ps, void *arg)
                    306: {
                    307:        fprintf(stderr, "pmdb: shared lib changed\n");
                    308:
                    309:        sym_update(ps);
                    310:
                    311:        return BKPT_KEEP_CONT;
                    312: }
                    313:
                    314: /*
                    315:  * Called after execution started so that we can load any dynamic symbols.
                    316:  */
                    317: void
                    318: elf_update(struct pstate *ps)
                    319: {
                    320: #ifndef __NetBSD__
                    321:        pid_t pid = ps->ps_pid;
                    322:        struct elf_object_v1 eobj;
                    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:        }
1.3       art       333:        addr = s->st_value + ps->ps_sym_exe->st_offs;
1.1       art       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:
1.3       art       395:                if (st_open(ps, fname, eobj.load_offs) == NULL)
1.1       art       396:                        warn("symbol loading failed");
                    397:        }
                    398: #endif
                    399: }