omitrbp

Find kernel functions that omit the frame pointer
git clone git://git.margiolis.net/omitrbp.git
Log | Files | Refs | README | LICENSE

omitrbp.c (4029B)


      1 #include <sys/param.h>
      2 #include <sys/sysctl.h>
      3 
      4 #include <err.h>
      5 #include <fcntl.h>
      6 #include <gelf.h>
      7 #include <libelf.h>
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 #include <unistd.h>
     12 
     13 struct section {
     14 	GElf_Shdr	sh;
     15 	Elf_Scn		*scn;
     16 	const char	*name;
     17 };
     18 
     19 static struct section *sl;
     20 static size_t shnum;
     21 static int first_instr = 0;
     22 
     23 static void
     24 print_rbp_ommited(const char *func, uint64_t lo, uint64_t hi)
     25 {
     26 	Elf_Data *d;
     27 	struct section *s;
     28 	uint8_t *buf;
     29 	uint64_t addr;
     30 	int i;
     31 
     32 	for (i = 1; i < shnum; i++) {
     33 		s = &sl[i];
     34 		if (strcmp(s->name, ".text") != 0 ||
     35 		    s->sh.sh_type != SHT_PROGBITS)
     36 			continue;
     37 		(void)elf_errno();
     38 		if ((d = elf_getdata(s->scn, NULL)) == NULL) {
     39 			if (elf_errno() != 0)
     40 				warnx("elf_getdata(): %s", elf_errmsg(-1));
     41 			continue;
     42 		}
     43 		if (d->d_size <= 0 || d->d_buf == NULL)
     44 			continue;
     45 		buf = d->d_buf;
     46 		addr = s->sh.sh_addr + d->d_off;
     47 		while (addr != lo) {
     48 			addr++;
     49 			buf++;
     50 		}
     51 		if (first_instr) {
     52 			if (*buf != 0x55)
     53 				puts(func);
     54 		} else {
     55 			int found = 0;
     56 
     57 			while (addr != hi) {
     58 				if (*buf == 0x55)
     59 					found = 1;
     60 				addr++;
     61 				buf++;
     62 			}
     63 			if (!found)
     64 				puts(func);
     65 		}
     66 		return;
     67 	}
     68 }
     69 
     70 int
     71 main(int argc, char *argv[])
     72 {
     73 	Elf *elf;
     74 	Elf_Scn *scn;
     75 	Elf_Data *d;
     76 	GElf_Shdr sh;
     77 	GElf_Sym sym;
     78 	struct section *s;
     79 	uint64_t lo, hi;
     80 	uint32_t stab;
     81 	const char *name, *func;
     82 	char bootfile[BUFSIZ];
     83 	size_t shstrndx, ndx, slen;
     84 	int fd, len, i, j, ch;
     85 
     86 	while ((ch = getopt(argc, argv, "f")) != -1) {
     87 		switch (ch) {
     88 		case 'f':
     89 			first_instr = 1;
     90 			break;
     91 		case '?':
     92 		default:
     93 			fprintf(stderr, "usage: %s [-f]\n", argv[0]);
     94 			exit(1);
     95 		}
     96 	}
     97 	argc -= optind;
     98 	argv += optind;
     99 
    100 	slen = sizeof(bootfile);
    101 	if (sysctlbyname("kern.bootfile", bootfile, &slen, NULL, 0) != 0)
    102 		strlcpy(bootfile, "/boot/kernel/kernel", sizeof(bootfile));
    103 
    104 	if (elf_version(EV_CURRENT) == EV_NONE)
    105 		errx(1, "elf_version(): %s", elf_errmsg(-1));
    106 	if ((fd = open(bootfile, O_RDONLY)) < 0)
    107 		err(1, "open(%s)", bootfile);
    108 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
    109 		errx(1, "elf_begin(): %s", elf_errmsg(-1));
    110 	if (elf_kind(elf) == ELF_K_NONE)
    111 		errx(1, "not an ELF file: %s", bootfile);
    112 
    113 	if (!elf_getshnum(elf, &shnum))
    114 		errx(1, "elf_getshnum(): %s", elf_errmsg(-1));
    115 	if ((sl = malloc(shnum * sizeof(struct section))) == NULL)
    116 		err(1, "malloc");
    117 	if (!elf_getshstrndx(elf, &shstrndx))
    118 		errx(1, "elf_getshstrndx(): %s", elf_errmsg(-1));
    119 	if ((scn = elf_getscn(elf, 0)) == NULL)
    120 		errx(1, "elf_getscn(): %s", elf_errmsg(-1));
    121 	(void)elf_errno();
    122 
    123 	do {
    124 		if (gelf_getshdr(scn, &sh) == NULL) {
    125 			warnx("gelf_getshdr(): %s", elf_errmsg(-1));
    126 			(void)elf_errno();
    127 			continue;
    128 		}
    129 		if ((name = elf_strptr(elf, shstrndx, sh.sh_name)) == NULL)
    130 			(void)elf_errno();
    131 		if ((ndx = elf_ndxscn(scn)) == SHN_UNDEF && elf_errno() != 0) {
    132 			warnx("elf_ndxscn(): %s", elf_errmsg(-1));
    133 			continue;
    134 		}
    135 		if (ndx >= shnum)
    136 			continue;
    137 		s = &sl[ndx];
    138 		s->scn = scn;
    139 		s->sh = sh;
    140 		s->name = name;
    141 	} while ((scn = elf_nextscn(elf, scn)) != NULL);
    142 	if (elf_errno() != 0)
    143 		warnx("elf_nextscn(): %s", elf_errmsg(-1));
    144 
    145 	for (i = 1; i < shnum; i++) {
    146 		s = &sl[i];
    147 		if (s->sh.sh_type != SHT_SYMTAB && s->sh.sh_type != SHT_DYNSYM)
    148 			continue;
    149 		if (s->sh.sh_link >= shnum)
    150 			continue;
    151 		stab = s->sh.sh_link;
    152 		len = (int)(s->sh.sh_size / s->sh.sh_entsize);
    153 		(void)elf_errno();
    154 		if ((d = elf_getdata(s->scn, NULL)) == NULL) {
    155 			if (elf_errno() != 0)
    156 				warnx("elf_getdata(): %s", elf_errmsg(-1));
    157 			continue;
    158 		}
    159 		if (d->d_size <= 0)
    160 			continue;
    161 		if (s->sh.sh_entsize == 0)
    162 			continue;
    163 		else if (len > INT_MAX)
    164 			continue;
    165 		for (j = 0; j < len; j++) {
    166 			if (gelf_getsym(d, j, &sym) != &sym) {
    167 				warnx("gelf_getsym(): %s", elf_errmsg(-1));
    168 				continue;
    169 			}
    170 			if (GELF_ST_TYPE(sym.st_info) != STT_FUNC)
    171 				continue;
    172 			lo = sym.st_value;
    173 			hi = sym.st_value + sym.st_size;
    174 			if ((func = elf_strptr(elf, stab, sym.st_name)) != NULL)
    175 				print_rbp_ommited(func, lo, hi);
    176 		}
    177 	}
    178 
    179 	free(sl);
    180 	close(fd);
    181 	elf_end(elf);
    182 
    183 	return (0);
    184 }