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