Home | History | Annotate | Line # | Download | only in tprof
      1  1.3  riastrad /*	$NetBSD: ksyms.c,v 1.3 2024/04/01 18:33:24 riastradh Exp $	*/
      2  1.1       ryo 
      3  1.1       ryo /*
      4  1.1       ryo  * Copyright (c) 2010,2011,2012 YAMAMOTO Takashi,
      5  1.1       ryo  * All rights reserved.
      6  1.1       ryo  *
      7  1.1       ryo  * Redistribution and use in source and binary forms, with or without
      8  1.1       ryo  * modification, are permitted provided that the following conditions
      9  1.1       ryo  * are met:
     10  1.1       ryo  * 1. Redistributions of source code must retain the above copyright
     11  1.1       ryo  *    notice, this list of conditions and the following disclaimer.
     12  1.1       ryo  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1       ryo  *    notice, this list of conditions and the following disclaimer in the
     14  1.1       ryo  *    documentation and/or other materials provided with the distribution.
     15  1.1       ryo  *
     16  1.1       ryo  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  1.1       ryo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  1.1       ryo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  1.1       ryo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  1.1       ryo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  1.1       ryo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  1.1       ryo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  1.1       ryo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  1.1       ryo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  1.1       ryo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  1.1       ryo  * SUCH DAMAGE.
     27  1.1       ryo  */
     28  1.1       ryo 
     29  1.1       ryo #include <sys/cdefs.h>
     30  1.1       ryo #ifndef lint
     31  1.3  riastrad __RCSID("$NetBSD: ksyms.c,v 1.3 2024/04/01 18:33:24 riastradh Exp $");
     32  1.1       ryo #endif /* not lint */
     33  1.1       ryo 
     34  1.1       ryo #include <assert.h>
     35  1.1       ryo #include <err.h>
     36  1.1       ryo #include <fcntl.h>
     37  1.1       ryo #include <gelf.h>
     38  1.1       ryo #include <libelf.h>
     39  1.1       ryo #include <paths.h>
     40  1.1       ryo #include <stdlib.h>
     41  1.1       ryo #include <string.h>
     42  1.1       ryo #include <unistd.h>
     43  1.1       ryo #include <util.h>
     44  1.1       ryo #include "ksyms.h"
     45  1.1       ryo 
     46  1.2       ryo static struct sym **syms = NULL;
     47  1.2       ryo static size_t nsyms = 0;
     48  1.1       ryo 
     49  1.1       ryo static int
     50  1.1       ryo compare_value(const void *p1, const void *p2)
     51  1.1       ryo {
     52  1.1       ryo 	const struct sym *s1 = *(const struct sym * const *)p1;
     53  1.1       ryo 	const struct sym *s2 = *(const struct sym * const *)p2;
     54  1.1       ryo 
     55  1.1       ryo 	if (s1->value > s2->value) {
     56  1.1       ryo 		return -1;
     57  1.1       ryo 	} else if (s1->value < s2->value) {
     58  1.1       ryo 		return 1;
     59  1.1       ryo 	}
     60  1.1       ryo 	/*
     61  1.1       ryo 	 * to produce a stable result, it's better not to return 0
     62  1.1       ryo 	 * even for __strong_alias.
     63  1.1       ryo 	 */
     64  1.1       ryo 	if (s1->size > s2->size) {
     65  1.1       ryo 		return -1;
     66  1.1       ryo 	} else if (s1->size < s2->size) {
     67  1.1       ryo 		return 1;
     68  1.1       ryo 	}
     69  1.1       ryo 	return strcmp(s1->name, s2->name);
     70  1.1       ryo }
     71  1.1       ryo 
     72  1.2       ryo struct sym **
     73  1.2       ryo ksymload(size_t *nsymp)
     74  1.1       ryo {
     75  1.1       ryo 	Elf *e;
     76  1.1       ryo 	Elf_Scn *s;
     77  1.1       ryo 	GElf_Shdr sh_store;
     78  1.1       ryo 	GElf_Shdr *sh;
     79  1.1       ryo 	Elf_Data *d;
     80  1.1       ryo 	int fd;
     81  1.1       ryo 	size_t size, i;
     82  1.1       ryo 
     83  1.1       ryo 	fd = open(_PATH_KSYMS, O_RDONLY);
     84  1.1       ryo 	if (fd == -1) {
     85  1.1       ryo 		err(EXIT_FAILURE, "open " _PATH_KSYMS);
     86  1.1       ryo 	}
     87  1.1       ryo 	if (elf_version(EV_CURRENT) == EV_NONE) {
     88  1.1       ryo 		goto elffail;
     89  1.1       ryo 	}
     90  1.1       ryo 	e = elf_begin(fd, ELF_C_READ, NULL);
     91  1.1       ryo 	if (e == NULL) {
     92  1.1       ryo 		goto elffail;
     93  1.1       ryo 	}
     94  1.1       ryo 	for (s = elf_nextscn(e, NULL); s != NULL; s = elf_nextscn(e, s)) {
     95  1.1       ryo 		sh = gelf_getshdr(s, &sh_store);
     96  1.1       ryo 		if (sh == NULL) {
     97  1.1       ryo 			goto elffail;
     98  1.1       ryo 		}
     99  1.1       ryo 		if (sh->sh_type == SHT_SYMTAB) {
    100  1.1       ryo 			break;
    101  1.1       ryo 		}
    102  1.1       ryo 	}
    103  1.1       ryo 	if (s == NULL) {
    104  1.1       ryo 		errx(EXIT_FAILURE, "no symtab");
    105  1.1       ryo 	}
    106  1.1       ryo 	d = elf_getdata(s, NULL);
    107  1.1       ryo 	if (d == NULL) {
    108  1.1       ryo 		goto elffail;
    109  1.1       ryo 	}
    110  1.1       ryo 	assert(sh->sh_size == d->d_size);
    111  1.1       ryo 	size = sh->sh_size / sh->sh_entsize;
    112  1.1       ryo 	for (i = 1; i < size; i++) {
    113  1.1       ryo 		GElf_Sym st_store;
    114  1.1       ryo 		GElf_Sym *st;
    115  1.1       ryo 		struct sym *sym;
    116  1.1       ryo 
    117  1.1       ryo 		st = gelf_getsym(d, (int)i, &st_store);
    118  1.1       ryo 		if (st == NULL) {
    119  1.1       ryo 			goto elffail;
    120  1.1       ryo 		}
    121  1.3  riastrad 		if (GELF_ST_TYPE(st->st_info) != STT_FUNC) {
    122  1.1       ryo 			continue;
    123  1.1       ryo 		}
    124  1.1       ryo 		sym = emalloc(sizeof(*sym));
    125  1.1       ryo 		sym->name = estrdup(elf_strptr(e, sh->sh_link, st->st_name));
    126  1.1       ryo 		sym->value = (uint64_t)st->st_value;
    127  1.1       ryo 		sym->size = st->st_size;
    128  1.1       ryo 		nsyms++;
    129  1.1       ryo 		syms = erealloc(syms, sizeof(*syms) * nsyms);
    130  1.1       ryo 		syms[nsyms - 1] = sym;
    131  1.1       ryo 	}
    132  1.1       ryo 	elf_end(e);
    133  1.1       ryo 	close(fd);
    134  1.1       ryo 	qsort(syms, nsyms, sizeof(*syms), compare_value);
    135  1.2       ryo 	if (nsymp != NULL)
    136  1.2       ryo 		*nsymp = nsyms;
    137  1.2       ryo 	return syms;
    138  1.1       ryo elffail:
    139  1.1       ryo 	errx(EXIT_FAILURE, "libelf: %s", elf_errmsg(elf_errno()));
    140  1.1       ryo }
    141  1.1       ryo 
    142  1.1       ryo const char *
    143  1.2       ryo ksymlookup(uint64_t value, uint64_t *offset, size_t *n)
    144  1.1       ryo {
    145  1.1       ryo 	size_t hi;
    146  1.1       ryo 	size_t lo;
    147  1.1       ryo 	size_t i;
    148  1.1       ryo 
    149  1.1       ryo 	/*
    150  1.1       ryo 	 * try to find the smallest i for which syms[i]->value <= value.
    151  1.1       ryo 	 * syms[] is ordered by syms[]->value in the descending order.
    152  1.1       ryo 	 */
    153  1.1       ryo 
    154  1.1       ryo 	hi = nsyms - 1;
    155  1.1       ryo 	lo = 0;
    156  1.1       ryo 	while (lo < hi) {
    157  1.1       ryo 		const size_t mid = (lo + hi) / 2;
    158  1.1       ryo 		const struct sym *sym = syms[mid];
    159  1.1       ryo 
    160  1.1       ryo 		assert(syms[lo]->value >= sym->value);
    161  1.1       ryo 		assert(sym->value >= syms[hi]->value);
    162  1.1       ryo 		if (sym->value <= value) {
    163  1.1       ryo 			hi = mid;
    164  1.1       ryo 			continue;
    165  1.1       ryo 		}
    166  1.1       ryo 		lo = mid + 1;
    167  1.1       ryo 	}
    168  1.1       ryo 	assert(lo == nsyms - 1 || syms[lo]->value <= value);
    169  1.1       ryo 	assert(lo == 0 || syms[lo - 1]->value > value);
    170  1.1       ryo 	for (i = lo; i < nsyms; i++) {
    171  1.1       ryo 		const struct sym *sym = syms[i];
    172  1.1       ryo 
    173  1.1       ryo 		if (sym->value <= value &&
    174  1.1       ryo 		    (sym->size == 0 || value - sym->value <= sym->size )) {
    175  1.1       ryo 			*offset = value - sym->value;
    176  1.2       ryo 			if (n != NULL)
    177  1.2       ryo 				*n = i;
    178  1.1       ryo 			return sym->name;
    179  1.1       ryo 		}
    180  1.1       ryo 		if (sym->size != 0 && sym->value + sym->size < value) {
    181  1.1       ryo 			break;
    182  1.1       ryo 		}
    183  1.1       ryo 	}
    184  1.1       ryo 	return NULL;
    185  1.1       ryo }
    186