aboutsummaryrefslogtreecommitdiff
path: root/usr.bin/gprof/elf.c
diff options
context:
space:
mode:
authorJohn Polstra <jdp@FreeBSD.org>1998-09-07 23:32:00 +0000
committerJohn Polstra <jdp@FreeBSD.org>1998-09-07 23:32:00 +0000
commit5584f22bb3f6664a71dae0b7a83cc974ca130265 (patch)
tree137a82c0e0ab75e721a6bb180779a0c227a579d6 /usr.bin/gprof/elf.c
parentbbfd14472486ef1ecf6b26d4720da3b1b4dfd7af (diff)
downloadsrc-5584f22bb3f6664a71dae0b7a83cc974ca130265.tar.gz
src-5584f22bb3f6664a71dae0b7a83cc974ca130265.zip
Make profiling work for ELF. gprof now autodetects the format of
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.
Notes
Notes: svn path=/head/; revision=38928
Diffstat (limited to 'usr.bin/gprof/elf.c')
-rw-r--r--usr.bin/gprof/elf.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/usr.bin/gprof/elf.c b/usr.bin/gprof/elf.c
new file mode 100644
index 000000000000..3a59f53d1b63
--- /dev/null
+++ b/usr.bin/gprof/elf.c
@@ -0,0 +1,106 @@
+#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;
+}