summaryrefslogtreecommitdiffstats
path: root/usr.bin/gprof/elf.c
diff options
context:
space:
mode:
authorjdp <jdp@FreeBSD.org>1998-09-07 23:32:00 +0000
committerjdp <jdp@FreeBSD.org>1998-09-07 23:32:00 +0000
commit5b11e2a2f4237604a3b79eae0bd8f58cd296fca5 (patch)
tree3406d2b2dff7ee0b157826eb5429d6e93491b1a8 /usr.bin/gprof/elf.c
parent06aec80098f1b2500b86064347079545f0d01eaf (diff)
downloadFreeBSD-src-5b11e2a2f4237604a3b79eae0bd8f58cd296fca5.zip
FreeBSD-src-5b11e2a2f4237604a3b79eae0bd8f58cd296fca5.tar.gz
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.
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 0000000..3a59f53
--- /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;
+}
OpenPOWER on IntegriCloud