elf.c revision 38928
11556Srgrimes#include <sys/types.h>
21556Srgrimes#include <sys/mman.h>
31556Srgrimes#include <sys/stat.h>
41556Srgrimes
51556Srgrimes#include <elf.h>
61556Srgrimes#include <err.h>
71556Srgrimes#include <fcntl.h>
81556Srgrimes#include <string.h>
91556Srgrimes#include <unistd.h>
101556Srgrimes
111556Srgrimes#include "gprof.h"
121556Srgrimes
131556Srgrimesstatic bool wantsym(const Elf_Sym *, const char *);
141556Srgrimes
151556Srgrimes/* Things which get -E excluded by default. */
161556Srgrimesstatic char	*excludes[] = { ".mcount", "_mcleanup", NULL };
171556Srgrimes
181556Srgrimesint
191556Srgrimeself_getnfile(const char *filename, char ***defaultEs)
201556Srgrimes{
211556Srgrimes    int fd;
221556Srgrimes    Elf_Ehdr h;
231556Srgrimes    struct stat s;
241556Srgrimes    void *mapbase;
251556Srgrimes    const char *base;
261556Srgrimes    const Elf_Shdr *shdrs;
271556Srgrimes    const Elf_Shdr *sh_symtab;
28127499Sgad    const Elf_Shdr *sh_strtab;
29127499Sgad    const char *strtab;
30127499Sgad    const Elf_Sym *symtab;
31127499Sgad    int symtabct;
32127499Sgad    int i;
33127499Sgad
34127499Sgad    if ((fd = open(filename, O_RDONLY)) == -1)
351556Srgrimes	err(1, "%s", filename);
361556Srgrimes    if (read(fd, &h, sizeof h) != sizeof h || !IS_ELF(h)) {
371556Srgrimes	close(fd);
3890143Smarkm	return -1;
391556Srgrimes    }
401556Srgrimes    if (fstat(fd, &s) == -1)
411556Srgrimes	err(1, "Cannot fstat %s", filename);
421556Srgrimes    if ((mapbase = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0)) ==
4390143Smarkm      MAP_FAILED)
441556Srgrimes	err(1, "Cannot mmap %s", filename);
4536049Scharnier    close(fd);
4690143Smarkm
4736049Scharnier    base = (const char *)mapbase;
48110391Scharnier    shdrs = (const Elf_Shdr *)(base + h.e_shoff);
4999110Sobrien
5099110Sobrien    /* Find the symbol table and associated string table section. */
511556Srgrimes    for (i = 1;  i < h.e_shnum;  i++)
521556Srgrimes	if (shdrs[i].sh_type == SHT_SYMTAB)
53127546Sgad	    break;
543296Sdg    if (i == h.e_shnum)
551556Srgrimes	errx(1, "%s has no symbol table", filename);
561556Srgrimes    sh_symtab = &shdrs[i];
571556Srgrimes    sh_strtab = &shdrs[sh_symtab->sh_link];
581556Srgrimes
591556Srgrimes    symtab = (const Elf_Sym *)(base + sh_symtab->sh_offset);
601556Srgrimes    symtabct = sh_symtab->sh_size / sh_symtab->sh_entsize;
61127149Sgad    strtab = (const char *)(base + sh_strtab->sh_offset);
621556Srgrimes
63127499Sgad    /* Count the symbols that we're interested in. */
641556Srgrimes    nname = 0;
6513514Smpp    for (i = 1;  i < symtabct;  i++)
6673367Sache	if (wantsym(&symtab[i], strtab))
671556Srgrimes	    nname++;
6890143Smarkm
691556Srgrimes    /* Allocate memory for them, plus a terminating entry. */
701556Srgrimes    if ((nl = (nltype *)calloc(nname + 1, sizeof(nltype))) == NULL)
711556Srgrimes	errx(1, "Insufficient memory for symbol table");
721556Srgrimes
731556Srgrimes    /* Read them in. */
741556Srgrimes    npe = nl;
751556Srgrimes    for (i = 1;  i < symtabct;  i++) {
76127499Sgad	const Elf_Sym *sym = &symtab[i];
77127499Sgad
7866377Sbrian	if (wantsym(sym, strtab)) {
79127537Sgad	    npe->value = sym->st_value;
80127555Sgad	    npe->name = strtab + sym->st_name;
81127537Sgad	    npe++;
82127537Sgad	}
83127555Sgad    }
84127537Sgad    npe->value = -1;
85127537Sgad
86127537Sgad    *defaultEs = excludes;
87129914Sgad    return 0;
88129971Sgad}
89129971Sgad
90129914Sgadstatic bool
91129971Sgadwantsym(const Elf_Sym *sym, const char *strtab)
92129914Sgad{
93127537Sgad    int type;
94127537Sgad    int bind;
95127537Sgad
96127537Sgad    type = ELF_ST_TYPE(sym->st_info);
97127537Sgad    bind = ELF_ST_BIND(sym->st_info);
98127537Sgad
99127537Sgad    if (type != STT_FUNC ||
100127537Sgad      bind == STB_WEAK ||
101130999Sgad      (aflag && bind == STB_LOCAL) ||
1021556Srgrimes      (uflag && strchr(strtab + sym->st_name, '.') != NULL))
103127537Sgad	return 0;
104127537Sgad
105127537Sgad    return 1;
106127537Sgad}
107127537Sgad