mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-29 12:03:03 +00:00
5584f22bb3
the executable file, so it will work for both a.out and ELF format files. I have split the object format specific code into separate source files. It's cleaner than it was before, but it's still pretty crufty. Don't cheat on your make world for this update. A lot of things have to be rebuilt for it to work, including the compiler and all of the profiled libraries.
107 lines
2.5 KiB
C
107 lines
2.5 KiB
C
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <elf.h>
|
|
#include <err.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "gprof.h"
|
|
|
|
static bool wantsym(const Elf_Sym *, const char *);
|
|
|
|
/* Things which get -E excluded by default. */
|
|
static char *excludes[] = { ".mcount", "_mcleanup", NULL };
|
|
|
|
int
|
|
elf_getnfile(const char *filename, char ***defaultEs)
|
|
{
|
|
int fd;
|
|
Elf_Ehdr h;
|
|
struct stat s;
|
|
void *mapbase;
|
|
const char *base;
|
|
const Elf_Shdr *shdrs;
|
|
const Elf_Shdr *sh_symtab;
|
|
const Elf_Shdr *sh_strtab;
|
|
const char *strtab;
|
|
const Elf_Sym *symtab;
|
|
int symtabct;
|
|
int i;
|
|
|
|
if ((fd = open(filename, O_RDONLY)) == -1)
|
|
err(1, "%s", filename);
|
|
if (read(fd, &h, sizeof h) != sizeof h || !IS_ELF(h)) {
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
if (fstat(fd, &s) == -1)
|
|
err(1, "Cannot fstat %s", filename);
|
|
if ((mapbase = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0)) ==
|
|
MAP_FAILED)
|
|
err(1, "Cannot mmap %s", filename);
|
|
close(fd);
|
|
|
|
base = (const char *)mapbase;
|
|
shdrs = (const Elf_Shdr *)(base + h.e_shoff);
|
|
|
|
/* Find the symbol table and associated string table section. */
|
|
for (i = 1; i < h.e_shnum; i++)
|
|
if (shdrs[i].sh_type == SHT_SYMTAB)
|
|
break;
|
|
if (i == h.e_shnum)
|
|
errx(1, "%s has no symbol table", filename);
|
|
sh_symtab = &shdrs[i];
|
|
sh_strtab = &shdrs[sh_symtab->sh_link];
|
|
|
|
symtab = (const Elf_Sym *)(base + sh_symtab->sh_offset);
|
|
symtabct = sh_symtab->sh_size / sh_symtab->sh_entsize;
|
|
strtab = (const char *)(base + sh_strtab->sh_offset);
|
|
|
|
/* Count the symbols that we're interested in. */
|
|
nname = 0;
|
|
for (i = 1; i < symtabct; i++)
|
|
if (wantsym(&symtab[i], strtab))
|
|
nname++;
|
|
|
|
/* Allocate memory for them, plus a terminating entry. */
|
|
if ((nl = (nltype *)calloc(nname + 1, sizeof(nltype))) == NULL)
|
|
errx(1, "Insufficient memory for symbol table");
|
|
|
|
/* Read them in. */
|
|
npe = nl;
|
|
for (i = 1; i < symtabct; i++) {
|
|
const Elf_Sym *sym = &symtab[i];
|
|
|
|
if (wantsym(sym, strtab)) {
|
|
npe->value = sym->st_value;
|
|
npe->name = strtab + sym->st_name;
|
|
npe++;
|
|
}
|
|
}
|
|
npe->value = -1;
|
|
|
|
*defaultEs = excludes;
|
|
return 0;
|
|
}
|
|
|
|
static bool
|
|
wantsym(const Elf_Sym *sym, const char *strtab)
|
|
{
|
|
int type;
|
|
int bind;
|
|
|
|
type = ELF_ST_TYPE(sym->st_info);
|
|
bind = ELF_ST_BIND(sym->st_info);
|
|
|
|
if (type != STT_FUNC ||
|
|
bind == STB_WEAK ||
|
|
(aflag && bind == STB_LOCAL) ||
|
|
(uflag && strchr(strtab + sym->st_name, '.') != NULL))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|