1*287472b3SEd Maste /* $NetBSD: symtab.c,v 1.1 2012/05/26 22:02:29 christos Exp $ */ 2*287472b3SEd Maste 3*287472b3SEd Maste /*- 4*287472b3SEd Maste * Copyright (c) 2012 The NetBSD Foundation, Inc. 5*287472b3SEd Maste * All rights reserved. 6*287472b3SEd Maste * 7*287472b3SEd Maste * This code is derived from software contributed to The NetBSD Foundation 8*287472b3SEd Maste * by Christos Zoulas. 9*287472b3SEd Maste * 10*287472b3SEd Maste * Redistribution and use in source and binary forms, with or without 11*287472b3SEd Maste * modification, are permitted provided that the following conditions 12*287472b3SEd Maste * are met: 13*287472b3SEd Maste * 1. Redistributions of source code must retain the above copyright 14*287472b3SEd Maste * notice, this list of conditions and the following disclaimer. 15*287472b3SEd Maste * 2. Redistributions in binary form must reproduce the above copyright 16*287472b3SEd Maste * notice, this list of conditions and the following disclaimer in the 17*287472b3SEd Maste * documentation and/or other materials provided with the distribution. 18*287472b3SEd Maste * 19*287472b3SEd Maste * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20*287472b3SEd Maste * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21*287472b3SEd Maste * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22*287472b3SEd Maste * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23*287472b3SEd Maste * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24*287472b3SEd Maste * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25*287472b3SEd Maste * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26*287472b3SEd Maste * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27*287472b3SEd Maste * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28*287472b3SEd Maste * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29*287472b3SEd Maste * POSSIBILITY OF SUCH DAMAGE. 30*287472b3SEd Maste */ 31*287472b3SEd Maste #include <sys/cdefs.h> 32*287472b3SEd Maste __RCSID("$NetBSD: symtab.c,v 1.1 2012/05/26 22:02:29 christos Exp $"); 33*287472b3SEd Maste 34*287472b3SEd Maste #include <stdlib.h> 35*287472b3SEd Maste #include <stdio.h> 36*287472b3SEd Maste #include <string.h> 37*287472b3SEd Maste #include <err.h> 38*287472b3SEd Maste #include <dlfcn.h> 39*287472b3SEd Maste 40*287472b3SEd Maste #include <libelf.h> 41*287472b3SEd Maste #include <gelf.h> 42*287472b3SEd Maste #ifndef ELF_ST_BIND 43*287472b3SEd Maste #define ELF_ST_BIND(x) ((x) >> 4) 44*287472b3SEd Maste #endif 45*287472b3SEd Maste #ifndef ELF_ST_TYPE 46*287472b3SEd Maste #define ELF_ST_TYPE(x) (((unsigned int)x) & 0xf) 47*287472b3SEd Maste #endif 48*287472b3SEd Maste 49*287472b3SEd Maste 50*287472b3SEd Maste #include "symtab.h" 51*287472b3SEd Maste 52*287472b3SEd Maste struct symbol { 53*287472b3SEd Maste char *st_name; 54*287472b3SEd Maste uintptr_t st_value; 55*287472b3SEd Maste uintptr_t st_info; 56*287472b3SEd Maste }; 57*287472b3SEd Maste 58*287472b3SEd Maste struct symtab { 59*287472b3SEd Maste size_t nsymbols; 60*287472b3SEd Maste struct symbol *symbols; 61*287472b3SEd Maste }; 62*287472b3SEd Maste 63*287472b3SEd Maste static int 64*287472b3SEd Maste address_compare(const void *a, const void *b) 65*287472b3SEd Maste { 66*287472b3SEd Maste const struct symbol *sa = a; 67*287472b3SEd Maste const struct symbol *sb = b; 68*287472b3SEd Maste return (int)(intmax_t)(sa->st_value - sb->st_value); 69*287472b3SEd Maste } 70*287472b3SEd Maste 71*287472b3SEd Maste void 72*287472b3SEd Maste symtab_destroy(symtab_t *s) 73*287472b3SEd Maste { 74*287472b3SEd Maste if (s == NULL) 75*287472b3SEd Maste return; 76*287472b3SEd Maste for (size_t i = 0; i < s->nsymbols; i++) 77*287472b3SEd Maste free(s->symbols[i].st_name); 78*287472b3SEd Maste free(s->symbols); 79*287472b3SEd Maste free(s); 80*287472b3SEd Maste } 81*287472b3SEd Maste 82*287472b3SEd Maste symtab_t * 83*287472b3SEd Maste symtab_create(int fd, int bind, int type) 84*287472b3SEd Maste { 85*287472b3SEd Maste Elf *elf; 86*287472b3SEd Maste symtab_t *st; 87*287472b3SEd Maste Elf_Scn *scn = NULL; 88*287472b3SEd Maste 89*287472b3SEd Maste if (elf_version(EV_CURRENT) == EV_NONE) { 90*287472b3SEd Maste warnx("Elf Library is out of date."); 91*287472b3SEd Maste return NULL; 92*287472b3SEd Maste } 93*287472b3SEd Maste 94*287472b3SEd Maste elf = elf_begin(fd, ELF_C_READ, NULL); 95*287472b3SEd Maste if (elf == NULL) { 96*287472b3SEd Maste warnx("Error opening elf file: %s", elf_errmsg(elf_errno())); 97*287472b3SEd Maste return NULL; 98*287472b3SEd Maste } 99*287472b3SEd Maste st = calloc(1, sizeof(*st)); 100*287472b3SEd Maste if (st == NULL) { 101*287472b3SEd Maste warnx("Error allocating symbol table"); 102*287472b3SEd Maste elf_end(elf); 103*287472b3SEd Maste return NULL; 104*287472b3SEd Maste } 105*287472b3SEd Maste 106*287472b3SEd Maste while ((scn = elf_nextscn(elf, scn)) != NULL) { 107*287472b3SEd Maste GElf_Shdr shdr; 108*287472b3SEd Maste Elf_Data *edata; 109*287472b3SEd Maste size_t ns; 110*287472b3SEd Maste struct symbol *s; 111*287472b3SEd Maste 112*287472b3SEd Maste gelf_getshdr(scn, &shdr); 113*287472b3SEd Maste if(shdr.sh_type != SHT_SYMTAB) 114*287472b3SEd Maste continue; 115*287472b3SEd Maste 116*287472b3SEd Maste edata = elf_getdata(scn, NULL); 117*287472b3SEd Maste ns = shdr.sh_size / shdr.sh_entsize; 118*287472b3SEd Maste s = calloc(ns, sizeof(*s)); 119*287472b3SEd Maste if (s == NULL) { 120*287472b3SEd Maste warn("Cannot allocate %zu symbols", ns); 121*287472b3SEd Maste goto out; 122*287472b3SEd Maste } 123*287472b3SEd Maste st->symbols = s; 124*287472b3SEd Maste 125*287472b3SEd Maste for (size_t i = 0; i < ns; i++) { 126*287472b3SEd Maste GElf_Sym sym; 127*287472b3SEd Maste gelf_getsym(edata, (int)i, &sym); 128*287472b3SEd Maste 129*287472b3SEd Maste if (bind != -1 && 130*287472b3SEd Maste (unsigned)bind != ELF_ST_BIND(sym.st_info)) 131*287472b3SEd Maste continue; 132*287472b3SEd Maste 133*287472b3SEd Maste if (type != -1 && 134*287472b3SEd Maste (unsigned)type != ELF_ST_TYPE(sym.st_info)) 135*287472b3SEd Maste continue; 136*287472b3SEd Maste 137*287472b3SEd Maste s->st_value = sym.st_value; 138*287472b3SEd Maste s->st_info = sym.st_info; 139*287472b3SEd Maste s->st_name = strdup( 140*287472b3SEd Maste elf_strptr(elf, shdr.sh_link, sym.st_name)); 141*287472b3SEd Maste if (s->st_name == NULL) 142*287472b3SEd Maste goto out; 143*287472b3SEd Maste s++; 144*287472b3SEd Maste } 145*287472b3SEd Maste st->nsymbols = s - st->symbols; 146*287472b3SEd Maste if (st->nsymbols == 0) { 147*287472b3SEd Maste warnx("No symbols found"); 148*287472b3SEd Maste goto out; 149*287472b3SEd Maste } 150*287472b3SEd Maste qsort(st->symbols, st->nsymbols, sizeof(*st->symbols), 151*287472b3SEd Maste address_compare); 152*287472b3SEd Maste elf_end(elf); 153*287472b3SEd Maste return st; 154*287472b3SEd Maste } 155*287472b3SEd Maste out: 156*287472b3SEd Maste symtab_destroy(st); 157*287472b3SEd Maste elf_end(elf); 158*287472b3SEd Maste return NULL; 159*287472b3SEd Maste } 160*287472b3SEd Maste 161*287472b3SEd Maste 162*287472b3SEd Maste int 163*287472b3SEd Maste symtab_find(const symtab_t *st, const void *p, Dl_info *dli) 164*287472b3SEd Maste { 165*287472b3SEd Maste struct symbol *s = st->symbols; 166*287472b3SEd Maste size_t ns = st->nsymbols; 167*287472b3SEd Maste size_t hi = ns; 168*287472b3SEd Maste size_t lo = 0; 169*287472b3SEd Maste size_t mid = ns / 2; 170*287472b3SEd Maste uintptr_t dd, sd, me = (uintptr_t)p; 171*287472b3SEd Maste 172*287472b3SEd Maste for (;;) { 173*287472b3SEd Maste if (s[mid].st_value < me) 174*287472b3SEd Maste lo = mid; 175*287472b3SEd Maste else if (s[mid].st_value > me) 176*287472b3SEd Maste hi = mid; 177*287472b3SEd Maste else 178*287472b3SEd Maste break; 179*287472b3SEd Maste if (hi - lo == 1) { 180*287472b3SEd Maste mid = lo; 181*287472b3SEd Maste break; 182*287472b3SEd Maste } 183*287472b3SEd Maste mid = (hi + lo) / 2; 184*287472b3SEd Maste } 185*287472b3SEd Maste dd = me - (uintptr_t)dli->dli_saddr; 186*287472b3SEd Maste sd = me - s[mid].st_value; 187*287472b3SEd Maste if (dd > sd) { 188*287472b3SEd Maste dli->dli_saddr = (void *)s[mid].st_value; 189*287472b3SEd Maste dli->dli_sname = s[mid].st_name; 190*287472b3SEd Maste } 191*287472b3SEd Maste return 1; 192*287472b3SEd Maste } 193