elf.c revision 38928
138928Sjdp#include <sys/types.h>
238928Sjdp#include <sys/mman.h>
338928Sjdp#include <sys/stat.h>
438928Sjdp
538928Sjdp#include <elf.h>
638928Sjdp#include <err.h>
738928Sjdp#include <fcntl.h>
838928Sjdp#include <string.h>
938928Sjdp#include <unistd.h>
1038928Sjdp
1138928Sjdp#include "gprof.h"
1238928Sjdp
1338928Sjdpstatic bool wantsym(const Elf_Sym *, const char *);
1438928Sjdp
1538928Sjdp/* Things which get -E excluded by default. */
1638928Sjdpstatic char	*excludes[] = { ".mcount", "_mcleanup", NULL };
1738928Sjdp
1838928Sjdpint
1938928Sjdpelf_getnfile(const char *filename, char ***defaultEs)
2038928Sjdp{
2138928Sjdp    int fd;
2238928Sjdp    Elf_Ehdr h;
2338928Sjdp    struct stat s;
2438928Sjdp    void *mapbase;
2538928Sjdp    const char *base;
2638928Sjdp    const Elf_Shdr *shdrs;
2738928Sjdp    const Elf_Shdr *sh_symtab;
2838928Sjdp    const Elf_Shdr *sh_strtab;
2938928Sjdp    const char *strtab;
3038928Sjdp    const Elf_Sym *symtab;
3138928Sjdp    int symtabct;
3238928Sjdp    int i;
3338928Sjdp
3438928Sjdp    if ((fd = open(filename, O_RDONLY)) == -1)
3538928Sjdp	err(1, "%s", filename);
3638928Sjdp    if (read(fd, &h, sizeof h) != sizeof h || !IS_ELF(h)) {
3738928Sjdp	close(fd);
3838928Sjdp	return -1;
3938928Sjdp    }
4038928Sjdp    if (fstat(fd, &s) == -1)
4138928Sjdp	err(1, "Cannot fstat %s", filename);
4238928Sjdp    if ((mapbase = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0)) ==
4338928Sjdp      MAP_FAILED)
4438928Sjdp	err(1, "Cannot mmap %s", filename);
4538928Sjdp    close(fd);
4638928Sjdp
4738928Sjdp    base = (const char *)mapbase;
4838928Sjdp    shdrs = (const Elf_Shdr *)(base + h.e_shoff);
4938928Sjdp
5038928Sjdp    /* Find the symbol table and associated string table section. */
5138928Sjdp    for (i = 1;  i < h.e_shnum;  i++)
5238928Sjdp	if (shdrs[i].sh_type == SHT_SYMTAB)
5338928Sjdp	    break;
5438928Sjdp    if (i == h.e_shnum)
5538928Sjdp	errx(1, "%s has no symbol table", filename);
5638928Sjdp    sh_symtab = &shdrs[i];
5738928Sjdp    sh_strtab = &shdrs[sh_symtab->sh_link];
5838928Sjdp
5938928Sjdp    symtab = (const Elf_Sym *)(base + sh_symtab->sh_offset);
6038928Sjdp    symtabct = sh_symtab->sh_size / sh_symtab->sh_entsize;
6138928Sjdp    strtab = (const char *)(base + sh_strtab->sh_offset);
6238928Sjdp
6338928Sjdp    /* Count the symbols that we're interested in. */
6438928Sjdp    nname = 0;
6538928Sjdp    for (i = 1;  i < symtabct;  i++)
6638928Sjdp	if (wantsym(&symtab[i], strtab))
6738928Sjdp	    nname++;
6838928Sjdp
6938928Sjdp    /* Allocate memory for them, plus a terminating entry. */
7038928Sjdp    if ((nl = (nltype *)calloc(nname + 1, sizeof(nltype))) == NULL)
7138928Sjdp	errx(1, "Insufficient memory for symbol table");
7238928Sjdp
7338928Sjdp    /* Read them in. */
7438928Sjdp    npe = nl;
7538928Sjdp    for (i = 1;  i < symtabct;  i++) {
7638928Sjdp	const Elf_Sym *sym = &symtab[i];
7738928Sjdp
7838928Sjdp	if (wantsym(sym, strtab)) {
7938928Sjdp	    npe->value = sym->st_value;
8038928Sjdp	    npe->name = strtab + sym->st_name;
8138928Sjdp	    npe++;
8238928Sjdp	}
8338928Sjdp    }
8438928Sjdp    npe->value = -1;
8538928Sjdp
8638928Sjdp    *defaultEs = excludes;
8738928Sjdp    return 0;
8838928Sjdp}
8938928Sjdp
9038928Sjdpstatic bool
9138928Sjdpwantsym(const Elf_Sym *sym, const char *strtab)
9238928Sjdp{
9338928Sjdp    int type;
9438928Sjdp    int bind;
9538928Sjdp
9638928Sjdp    type = ELF_ST_TYPE(sym->st_info);
9738928Sjdp    bind = ELF_ST_BIND(sym->st_info);
9838928Sjdp
9938928Sjdp    if (type != STT_FUNC ||
10038928Sjdp      bind == STB_WEAK ||
10138928Sjdp      (aflag && bind == STB_LOCAL) ||
10238928Sjdp      (uflag && strchr(strtab + sym->st_name, '.') != NULL))
10338928Sjdp	return 0;
10438928Sjdp
10538928Sjdp    return 1;
10638928Sjdp}
107