ksyms.c revision 1.1
11.1Sryo/* $NetBSD: ksyms.c,v 1.1 2022/12/01 00:41:10 ryo Exp $ */ 21.1Sryo 31.1Sryo/* 41.1Sryo * Copyright (c) 2010,2011,2012 YAMAMOTO Takashi, 51.1Sryo * All rights reserved. 61.1Sryo * 71.1Sryo * Redistribution and use in source and binary forms, with or without 81.1Sryo * modification, are permitted provided that the following conditions 91.1Sryo * are met: 101.1Sryo * 1. Redistributions of source code must retain the above copyright 111.1Sryo * notice, this list of conditions and the following disclaimer. 121.1Sryo * 2. Redistributions in binary form must reproduce the above copyright 131.1Sryo * notice, this list of conditions and the following disclaimer in the 141.1Sryo * documentation and/or other materials provided with the distribution. 151.1Sryo * 161.1Sryo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 171.1Sryo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 181.1Sryo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 191.1Sryo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 201.1Sryo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 211.1Sryo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 221.1Sryo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 231.1Sryo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 241.1Sryo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251.1Sryo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261.1Sryo * SUCH DAMAGE. 271.1Sryo */ 281.1Sryo 291.1Sryo#include <sys/cdefs.h> 301.1Sryo#ifndef lint 311.1Sryo__RCSID("$NetBSD: ksyms.c,v 1.1 2022/12/01 00:41:10 ryo Exp $"); 321.1Sryo#endif /* not lint */ 331.1Sryo 341.1Sryo#include <assert.h> 351.1Sryo#include <err.h> 361.1Sryo#include <fcntl.h> 371.1Sryo#include <gelf.h> 381.1Sryo#include <libelf.h> 391.1Sryo#include <paths.h> 401.1Sryo#include <stdlib.h> 411.1Sryo#include <string.h> 421.1Sryo#include <unistd.h> 431.1Sryo#include <util.h> 441.1Sryo#include "ksyms.h" 451.1Sryo 461.1Sryostruct sym **syms = NULL; 471.1Sryosize_t nsyms = 0; 481.1Sryo 491.1Sryostatic int 501.1Sryocompare_value(const void *p1, const void *p2) 511.1Sryo{ 521.1Sryo const struct sym *s1 = *(const struct sym * const *)p1; 531.1Sryo const struct sym *s2 = *(const struct sym * const *)p2; 541.1Sryo 551.1Sryo if (s1->value > s2->value) { 561.1Sryo return -1; 571.1Sryo } else if (s1->value < s2->value) { 581.1Sryo return 1; 591.1Sryo } 601.1Sryo /* 611.1Sryo * to produce a stable result, it's better not to return 0 621.1Sryo * even for __strong_alias. 631.1Sryo */ 641.1Sryo if (s1->size > s2->size) { 651.1Sryo return -1; 661.1Sryo } else if (s1->size < s2->size) { 671.1Sryo return 1; 681.1Sryo } 691.1Sryo return strcmp(s1->name, s2->name); 701.1Sryo} 711.1Sryo 721.1Sryovoid 731.1Sryoksymload(void) 741.1Sryo{ 751.1Sryo Elf *e; 761.1Sryo Elf_Scn *s; 771.1Sryo GElf_Shdr sh_store; 781.1Sryo GElf_Shdr *sh; 791.1Sryo Elf_Data *d; 801.1Sryo int fd; 811.1Sryo size_t size, i; 821.1Sryo 831.1Sryo fd = open(_PATH_KSYMS, O_RDONLY); 841.1Sryo if (fd == -1) { 851.1Sryo err(EXIT_FAILURE, "open " _PATH_KSYMS); 861.1Sryo } 871.1Sryo if (elf_version(EV_CURRENT) == EV_NONE) { 881.1Sryo goto elffail; 891.1Sryo } 901.1Sryo e = elf_begin(fd, ELF_C_READ, NULL); 911.1Sryo if (e == NULL) { 921.1Sryo goto elffail; 931.1Sryo } 941.1Sryo for (s = elf_nextscn(e, NULL); s != NULL; s = elf_nextscn(e, s)) { 951.1Sryo sh = gelf_getshdr(s, &sh_store); 961.1Sryo if (sh == NULL) { 971.1Sryo goto elffail; 981.1Sryo } 991.1Sryo if (sh->sh_type == SHT_SYMTAB) { 1001.1Sryo break; 1011.1Sryo } 1021.1Sryo } 1031.1Sryo if (s == NULL) { 1041.1Sryo errx(EXIT_FAILURE, "no symtab"); 1051.1Sryo } 1061.1Sryo d = elf_getdata(s, NULL); 1071.1Sryo if (d == NULL) { 1081.1Sryo goto elffail; 1091.1Sryo } 1101.1Sryo assert(sh->sh_size == d->d_size); 1111.1Sryo size = sh->sh_size / sh->sh_entsize; 1121.1Sryo for (i = 1; i < size; i++) { 1131.1Sryo GElf_Sym st_store; 1141.1Sryo GElf_Sym *st; 1151.1Sryo struct sym *sym; 1161.1Sryo 1171.1Sryo st = gelf_getsym(d, (int)i, &st_store); 1181.1Sryo if (st == NULL) { 1191.1Sryo goto elffail; 1201.1Sryo } 1211.1Sryo if (ELF_ST_TYPE(st->st_info) != STT_FUNC) { 1221.1Sryo continue; 1231.1Sryo } 1241.1Sryo sym = emalloc(sizeof(*sym)); 1251.1Sryo sym->name = estrdup(elf_strptr(e, sh->sh_link, st->st_name)); 1261.1Sryo sym->value = (uint64_t)st->st_value; 1271.1Sryo sym->size = st->st_size; 1281.1Sryo nsyms++; 1291.1Sryo syms = erealloc(syms, sizeof(*syms) * nsyms); 1301.1Sryo syms[nsyms - 1] = sym; 1311.1Sryo } 1321.1Sryo elf_end(e); 1331.1Sryo close(fd); 1341.1Sryo qsort(syms, nsyms, sizeof(*syms), compare_value); 1351.1Sryo return; 1361.1Sryoelffail: 1371.1Sryo errx(EXIT_FAILURE, "libelf: %s", elf_errmsg(elf_errno())); 1381.1Sryo} 1391.1Sryo 1401.1Sryoconst char * 1411.1Sryoksymlookup(uint64_t value, uint64_t *offset) 1421.1Sryo{ 1431.1Sryo size_t hi; 1441.1Sryo size_t lo; 1451.1Sryo size_t i; 1461.1Sryo 1471.1Sryo /* 1481.1Sryo * try to find the smallest i for which syms[i]->value <= value. 1491.1Sryo * syms[] is ordered by syms[]->value in the descending order. 1501.1Sryo */ 1511.1Sryo 1521.1Sryo hi = nsyms - 1; 1531.1Sryo lo = 0; 1541.1Sryo while (lo < hi) { 1551.1Sryo const size_t mid = (lo + hi) / 2; 1561.1Sryo const struct sym *sym = syms[mid]; 1571.1Sryo 1581.1Sryo assert(syms[lo]->value >= sym->value); 1591.1Sryo assert(sym->value >= syms[hi]->value); 1601.1Sryo if (sym->value <= value) { 1611.1Sryo hi = mid; 1621.1Sryo continue; 1631.1Sryo } 1641.1Sryo lo = mid + 1; 1651.1Sryo } 1661.1Sryo assert(lo == nsyms - 1 || syms[lo]->value <= value); 1671.1Sryo assert(lo == 0 || syms[lo - 1]->value > value); 1681.1Sryo for (i = lo; i < nsyms; i++) { 1691.1Sryo const struct sym *sym = syms[i]; 1701.1Sryo 1711.1Sryo if (sym->value <= value && 1721.1Sryo (sym->size == 0 || value - sym->value <= sym->size )) { 1731.1Sryo *offset = value - sym->value; 1741.1Sryo return sym->name; 1751.1Sryo } 1761.1Sryo if (sym->size != 0 && sym->value + sym->size < value) { 1771.1Sryo break; 1781.1Sryo } 1791.1Sryo } 1801.1Sryo return NULL; 1811.1Sryo} 182