xref: /openbsd/usr.bin/gprof/elf.c (revision 9f79a698)
190a99070Sart /*-
290a99070Sart  * Copyright (c) 1983, 1993
390a99070Sart  *	The Regents of the University of California.  All rights reserved.
490a99070Sart  *
590a99070Sart  * Redistribution and use in source and binary forms, with or without
690a99070Sart  * modification, are permitted provided that the following conditions
790a99070Sart  * are met:
890a99070Sart  * 1. Redistributions of source code must retain the above copyright
990a99070Sart  *    notice, this list of conditions and the following disclaimer.
1090a99070Sart  * 2. Redistributions in binary form must reproduce the above copyright
1190a99070Sart  *    notice, this list of conditions and the following disclaimer in the
1290a99070Sart  *    documentation and/or other materials provided with the distribution.
13f75387cbSmillert  * 3. Neither the name of the University nor the names of its contributors
1490a99070Sart  *    may be used to endorse or promote products derived from this software
1590a99070Sart  *    without specific prior written permission.
1690a99070Sart  *
1790a99070Sart  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1890a99070Sart  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1990a99070Sart  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2090a99070Sart  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2190a99070Sart  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2290a99070Sart  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2390a99070Sart  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2490a99070Sart  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2590a99070Sart  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2690a99070Sart  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2790a99070Sart  * SUCH DAMAGE.
2890a99070Sart  */
2990a99070Sart 
3090a99070Sart #include <sys/types.h>
3190a99070Sart #include <sys/mman.h>
3290a99070Sart #include <sys/stat.h>
3390a99070Sart 
34*9f79a698Smpi #include <elf.h>
3590a99070Sart #include <err.h>
3690a99070Sart #include <fcntl.h>
3790a99070Sart #include <string.h>
3890a99070Sart #include <unistd.h>
3990a99070Sart 
4090a99070Sart #include "gprof.h"
4190a99070Sart 
4290a99070Sart static bool wantsym(const Elf_Sym *, const char *);
4390a99070Sart 
4490a99070Sart /* Things which get -E excluded by default. */
4590a99070Sart static char	*excludes[] = { ".mcount", "_mcleanup", NULL };
4690a99070Sart 
4790a99070Sart int
getnfile(const char * filename,char *** defaultEs)4890a99070Sart getnfile(const char *filename, char ***defaultEs)
4990a99070Sart {
5090a99070Sart     int fd;
5190a99070Sart     Elf_Ehdr h;
5290a99070Sart     struct stat s;
5390a99070Sart     void *mapbase;
5490a99070Sart     const char *base;
5590a99070Sart     const Elf_Shdr *shdrs;
5690a99070Sart     const Elf_Shdr *sh_symtab;
5790a99070Sart     const Elf_Shdr *sh_strtab;
5890a99070Sart     const char *strtab;
5990a99070Sart     const Elf_Sym *symtab;
6090a99070Sart     int symtabct;
6190a99070Sart     int i;
6290a99070Sart 
6390a99070Sart     if ((fd = open(filename, O_RDONLY)) == -1)
6490a99070Sart 	err(1, "%s", filename);
6590a99070Sart     if (read(fd, &h, sizeof h) != sizeof h || !IS_ELF(h)) {
6690a99070Sart 	close(fd);
6790a99070Sart 	return -1;
6890a99070Sart     }
6990a99070Sart     if (fstat(fd, &s) == -1)
7090a99070Sart 	err(1, "Cannot fstat %s", filename);
7190a99070Sart     if ((mapbase = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0)) ==
7290a99070Sart       MAP_FAILED)
7390a99070Sart 	err(1, "Cannot mmap %s", filename);
7490a99070Sart     close(fd);
7590a99070Sart 
7690a99070Sart     base = (const char *)mapbase;
7790a99070Sart     shdrs = (const Elf_Shdr *)(base + h.e_shoff);
7890a99070Sart 
7990a99070Sart     /* Find the symbol table and associated string table section. */
8090a99070Sart     for (i = 1;  i < h.e_shnum;  i++)
8190a99070Sart 	if (shdrs[i].sh_type == SHT_SYMTAB)
8290a99070Sart 	    break;
8390a99070Sart     if (i == h.e_shnum)
8490a99070Sart 	errx(1, "%s has no symbol table", filename);
8590a99070Sart     sh_symtab = &shdrs[i];
8690a99070Sart     sh_strtab = &shdrs[sh_symtab->sh_link];
8790a99070Sart 
8890a99070Sart     symtab = (const Elf_Sym *)(base + sh_symtab->sh_offset);
8990a99070Sart     symtabct = sh_symtab->sh_size / sh_symtab->sh_entsize;
9090a99070Sart     strtab = (const char *)(base + sh_strtab->sh_offset);
9190a99070Sart 
9290a99070Sart     /* Count the symbols that we're interested in. */
9390a99070Sart     nname = 0;
9490a99070Sart     for (i = 1;  i < symtabct;  i++)
9590a99070Sart 	if (wantsym(&symtab[i], strtab))
9690a99070Sart 	    nname++;
9790a99070Sart 
984fa0ad6aSmarc #ifdef DEBUG
994fa0ad6aSmarc     if (debug & ELFDEBUG) {
1004fa0ad6aSmarc 	    printf("[getnfile] symtab at %p, strtab at %p\n", symtab, strtab);
1014fa0ad6aSmarc 	    printf("[getnfile] %d of %d symbols wanted\n", nname, symtabct);
1024fa0ad6aSmarc     }
1034fa0ad6aSmarc #endif
1044fa0ad6aSmarc 
10590a99070Sart     /* Allocate memory for them, plus a terminating entry. */
106cfff592fSderaadt     if ((nl = calloc(nname + 1, sizeof(nltype))) == NULL)
10790a99070Sart 	errx(1, "Insufficient memory for symbol table");
10890a99070Sart 
10990a99070Sart     /* Read them in. */
11090a99070Sart     npe = nl;
11190a99070Sart     for (i = 1;  i < symtabct;  i++) {
11290a99070Sart 	const Elf_Sym *sym = &symtab[i];
11390a99070Sart 
11490a99070Sart 	if (wantsym(sym, strtab)) {
11590a99070Sart 	    npe->value = sym->st_value;
11690a99070Sart 	    npe->name = strtab + sym->st_name;
1174fa0ad6aSmarc #ifdef DEBUG
1184fa0ad6aSmarc 	    if (debug & ELFDEBUG)
1194fa0ad6aSmarc 		    printf("[getnfile] symbol %d: %s -> %lx\n", i,
1204fa0ad6aSmarc 			   npe->name ? npe->name : "(none)", npe->value);
1214fa0ad6aSmarc #endif
12290a99070Sart 	    npe++;
12390a99070Sart 	}
12490a99070Sart     }
12590a99070Sart     npe->value = -1;
12690a99070Sart 
12790a99070Sart     *defaultEs = excludes;
12890a99070Sart     return 0;
12990a99070Sart }
13090a99070Sart 
13190a99070Sart static bool
wantsym(const Elf_Sym * sym,const char * strtab)13290a99070Sart wantsym(const Elf_Sym *sym, const char *strtab)
13390a99070Sart {
13490a99070Sart     int type;
13590a99070Sart     int bind;
13690a99070Sart 
13790a99070Sart     type = ELF_ST_TYPE(sym->st_info);
13890a99070Sart     bind = ELF_ST_BIND(sym->st_info);
13990a99070Sart 
14090a99070Sart     if (type != STT_FUNC || (aflag && bind == STB_LOCAL))
14190a99070Sart #if 0
14290a99070Sart  ||
14390a99070Sart       (uflag && strchr(strtab + sym->st_name, '.') != NULL))
14490a99070Sart #endif
14590a99070Sart 	return 0;
14690a99070Sart 
147db13cdc6Sckuethe #ifdef __arm__
148db13cdc6Sckuethe     /* ignore what gas calls "mapping symbols" */
149db13cdc6Sckuethe     {
150db13cdc6Sckuethe 	const char *c = strtab + sym->st_name;
151db13cdc6Sckuethe 	if (c[0] == '$')
152db13cdc6Sckuethe 	    return 0;
153db13cdc6Sckuethe     }
154db13cdc6Sckuethe #endif
155db13cdc6Sckuethe 
15690a99070Sart     return 1;
15790a99070Sart }
158