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