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