17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7a5d89c4Sab196087 * Common Development and Distribution License (the "License").
6*7a5d89c4Sab196087 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
2192ed1782Smike_s
227c478bd9Sstevel@tonic-gate /*
23*7a5d89c4Sab196087 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
2492ed1782Smike_s * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate #include "gprof.h"
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <sys/file.h>
327c478bd9Sstevel@tonic-gate #include <fcntl.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <string.h>
357c478bd9Sstevel@tonic-gate #include <sysexits.h>
367c478bd9Sstevel@tonic-gate #include <libelf.h>
377c478bd9Sstevel@tonic-gate #include "gelf.h"
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate #ifdef DEBUG
407c478bd9Sstevel@tonic-gate static void debug_dup_del(nltype *, nltype *);
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gate #define DPRINTF(msg, file) if (debug & ELFDEBUG) \
4392ed1782Smike_s (void) printf(msg, file);
447c478bd9Sstevel@tonic-gate
457c478bd9Sstevel@tonic-gate #define PRINTF(msg) if (debug & ELFDEBUG) \
4692ed1782Smike_s (void) printf(msg);
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate #define DEBUG_DUP_DEL(keeper, louser) if (debug & ELFDEBUG) \
497c478bd9Sstevel@tonic-gate debug_dup_del(keeper, louser);
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate #else
527c478bd9Sstevel@tonic-gate #define DPRINTF(msg, file)
537c478bd9Sstevel@tonic-gate #define PRINTF(msg)
547c478bd9Sstevel@tonic-gate #define DEBUG_DUP_DEL(keeper, louser)
557c478bd9Sstevel@tonic-gate #endif
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate size_t textbegin, textsize;
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate /* Prototype definitions first */
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate static void process(char *filename, int fd);
6292ed1782Smike_s static void get_symtab(Elf *elf, mod_info_t *module);
6392ed1782Smike_s static void get_textseg(Elf *elf, int fd);
647c478bd9Sstevel@tonic-gate static void save_aout_info(char *);
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate static void
fatal_error(char * error)677c478bd9Sstevel@tonic-gate fatal_error(char *error)
687c478bd9Sstevel@tonic-gate {
6992ed1782Smike_s (void) fprintf(stderr,
7092ed1782Smike_s "Fatal ELF error: %s (%s)\n", error, elf_errmsg(-1));
717c478bd9Sstevel@tonic-gate exit(EX_SOFTWARE);
727c478bd9Sstevel@tonic-gate }
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate bool
is_shared_obj(char * name)757c478bd9Sstevel@tonic-gate is_shared_obj(char *name)
767c478bd9Sstevel@tonic-gate {
777c478bd9Sstevel@tonic-gate int fd;
787c478bd9Sstevel@tonic-gate Elf *elf;
797c478bd9Sstevel@tonic-gate GElf_Ehdr ehdr;
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate if ((fd = open(name, O_RDONLY)) == -1) {
8292ed1782Smike_s (void) fprintf(stderr, "%s: can't open `%s'\n", whoami, name);
837c478bd9Sstevel@tonic-gate exit(EX_NOINPUT);
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate if (elf_version(EV_CURRENT) == EV_NONE)
877c478bd9Sstevel@tonic-gate fatal_error("libelf is out of date");
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
907c478bd9Sstevel@tonic-gate fatal_error("can't read as ELF file");
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL)
937c478bd9Sstevel@tonic-gate fatal_error("can't read ehdr");
947c478bd9Sstevel@tonic-gate
9592ed1782Smike_s (void) elf_end(elf);
9692ed1782Smike_s (void) close(fd);
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate if (ehdr.e_type == ET_DYN)
997c478bd9Sstevel@tonic-gate return (TRUE);
1007c478bd9Sstevel@tonic-gate else
1017c478bd9Sstevel@tonic-gate return (FALSE);
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate static void
save_aout_info(char * aoutname)1057c478bd9Sstevel@tonic-gate save_aout_info(char *aoutname)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate struct stat buf;
1087c478bd9Sstevel@tonic-gate extern fl_info_t aout_info;
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate if (stat(aoutname, &buf) == -1) {
11192ed1782Smike_s (void) fprintf(stderr, "%s: can't get info on `%s'\n",
1127c478bd9Sstevel@tonic-gate whoami, aoutname);
1137c478bd9Sstevel@tonic-gate exit(EX_NOINPUT);
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate aout_info.dev = buf.st_dev;
1177c478bd9Sstevel@tonic-gate aout_info.ino = buf.st_ino;
1187c478bd9Sstevel@tonic-gate aout_info.mtime = buf.st_mtime;
1197c478bd9Sstevel@tonic-gate aout_info.size = buf.st_size;
1207c478bd9Sstevel@tonic-gate }
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate void
getnfile(char * aoutname)1237c478bd9Sstevel@tonic-gate getnfile(char *aoutname)
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate int fd;
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate DPRINTF(" Attempting to open %s \n", aoutname);
1287c478bd9Sstevel@tonic-gate if ((fd = open((aoutname), O_RDONLY)) == -1) {
1297c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: can't open `%s'\n",
1307c478bd9Sstevel@tonic-gate whoami, aoutname);
1317c478bd9Sstevel@tonic-gate exit(EX_NOINPUT);
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate process(aoutname, fd);
1347c478bd9Sstevel@tonic-gate save_aout_info(aoutname);
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate (void) close(fd);
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate static GElf_Addr
get_txtorigin(Elf * elf)1407c478bd9Sstevel@tonic-gate get_txtorigin(Elf *elf)
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate GElf_Ehdr ehdr;
1437c478bd9Sstevel@tonic-gate GElf_Phdr phdr;
1447c478bd9Sstevel@tonic-gate GElf_Half ndx;
1457c478bd9Sstevel@tonic-gate GElf_Addr txt_origin = 0;
1467c478bd9Sstevel@tonic-gate bool first_load_seg = TRUE;
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL)
1497c478bd9Sstevel@tonic-gate fatal_error("can't read ehdr");
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate for (ndx = 0; ndx < ehdr.e_phnum; ndx++) {
1527c478bd9Sstevel@tonic-gate if (gelf_getphdr(elf, ndx, &phdr) == NULL)
1537c478bd9Sstevel@tonic-gate continue;
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate if ((phdr.p_type == PT_LOAD) && !(phdr.p_flags & PF_W)) {
1567c478bd9Sstevel@tonic-gate if (first_load_seg || phdr.p_vaddr < txt_origin)
1577c478bd9Sstevel@tonic-gate txt_origin = phdr.p_vaddr;
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate if (first_load_seg)
1607c478bd9Sstevel@tonic-gate first_load_seg = FALSE;
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate return (txt_origin);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate void
process_namelist(mod_info_t * module)1687c478bd9Sstevel@tonic-gate process_namelist(mod_info_t *module)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate int fd;
1717c478bd9Sstevel@tonic-gate Elf *elf;
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate if ((fd = open(module->name, O_RDONLY)) == -1) {
1747c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: can't read %s\n",
1757c478bd9Sstevel@tonic-gate whoami, module->name);
17692ed1782Smike_s (void) fprintf(stderr, "Exiting due to error(s)...\n");
1777c478bd9Sstevel@tonic-gate exit(EX_NOINPUT);
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate /*
1817c478bd9Sstevel@tonic-gate * libelf's version already verified in processing a.out,
1827c478bd9Sstevel@tonic-gate * so directly do elf_begin()
1837c478bd9Sstevel@tonic-gate */
1847c478bd9Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
1857c478bd9Sstevel@tonic-gate fatal_error("can't read as ELF file");
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate module->next = NULL;
1887c478bd9Sstevel@tonic-gate module->txt_origin = get_txtorigin(elf);
18992ed1782Smike_s get_symtab(elf, module);
1907c478bd9Sstevel@tonic-gate module->active = TRUE;
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate /*
1947c478bd9Sstevel@tonic-gate * Get the ELF header and, if it exists, call get_symtab()
1957c478bd9Sstevel@tonic-gate * to begin processing of the file; otherwise, return from
1967c478bd9Sstevel@tonic-gate * processing the file with a warning.
1977c478bd9Sstevel@tonic-gate */
1987c478bd9Sstevel@tonic-gate static void
process(char * filename,int fd)1997c478bd9Sstevel@tonic-gate process(char *filename, int fd)
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate Elf *elf;
2027c478bd9Sstevel@tonic-gate extern bool cflag;
2037c478bd9Sstevel@tonic-gate extern bool Bflag;
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate if (elf_version(EV_CURRENT) == EV_NONE)
2067c478bd9Sstevel@tonic-gate fatal_error("libelf is out of date");
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
2097c478bd9Sstevel@tonic-gate fatal_error("can't read as ELF file");
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate if (gelf_getclass(elf) == ELFCLASS64)
2127c478bd9Sstevel@tonic-gate Bflag = TRUE;
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate /*
2157c478bd9Sstevel@tonic-gate * Initialize active modules list. Note that we set the end
2167c478bd9Sstevel@tonic-gate * address while reading the symbol table, in get_symtab
2177c478bd9Sstevel@tonic-gate */
2187c478bd9Sstevel@tonic-gate modules.id = 1;
2197c478bd9Sstevel@tonic-gate modules.next = NULL;
2207c478bd9Sstevel@tonic-gate modules.txt_origin = get_txtorigin(elf);
2217c478bd9Sstevel@tonic-gate modules.load_base = modules.txt_origin;
22292ed1782Smike_s if ((modules.name = malloc(strlen(filename) + 1)) == NULL) {
22392ed1782Smike_s (void) fprintf(stderr, "%s: can't malloc %d bytes",
2247c478bd9Sstevel@tonic-gate whoami, strlen(filename) + 1);
2257c478bd9Sstevel@tonic-gate exit(EX_UNAVAILABLE);
2267c478bd9Sstevel@tonic-gate }
22792ed1782Smike_s (void) strcpy(modules.name, filename);
2287c478bd9Sstevel@tonic-gate
22992ed1782Smike_s get_symtab(elf, &modules);
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate modules.load_end = modules.data_end;
2327c478bd9Sstevel@tonic-gate modules.active = TRUE;
2337c478bd9Sstevel@tonic-gate n_modules = 1;
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate if (cflag)
23692ed1782Smike_s get_textseg(elf, fd);
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate static void
get_textseg(Elf * elf,int fd)24092ed1782Smike_s get_textseg(Elf *elf, int fd)
2417c478bd9Sstevel@tonic-gate {
2427c478bd9Sstevel@tonic-gate GElf_Ehdr ehdr;
2437c478bd9Sstevel@tonic-gate GElf_Phdr phdr;
2447c478bd9Sstevel@tonic-gate GElf_Half i;
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL)
2477c478bd9Sstevel@tonic-gate fatal_error("can't read ehdr");
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate for (i = 0; i < ehdr.e_phnum; i++) {
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate if (gelf_getphdr(elf, i, &phdr) == NULL)
2527c478bd9Sstevel@tonic-gate continue;
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate if (!(phdr.p_flags & PF_W) && (phdr.p_filesz > textsize)) {
2557c478bd9Sstevel@tonic-gate size_t chk;
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate * We could have multiple loadable text segments;
2597c478bd9Sstevel@tonic-gate * keep the largest we find.
2607c478bd9Sstevel@tonic-gate */
2617c478bd9Sstevel@tonic-gate if (textspace)
2627c478bd9Sstevel@tonic-gate free(textspace);
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate * gprof is a 32-bit program; if this text segment
2667c478bd9Sstevel@tonic-gate * has a > 32-bit offset or length, it's too big.
2677c478bd9Sstevel@tonic-gate */
2687c478bd9Sstevel@tonic-gate chk = (size_t)phdr.p_vaddr + (size_t)phdr.p_filesz;
2697c478bd9Sstevel@tonic-gate if (phdr.p_vaddr + phdr.p_filesz != (GElf_Xword)chk)
2707c478bd9Sstevel@tonic-gate fatal_error("text segment too large for -c");
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate textbegin = (size_t)phdr.p_vaddr;
2737c478bd9Sstevel@tonic-gate textsize = (size_t)phdr.p_filesz;
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate textspace = malloc(textsize);
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate if (lseek(fd, (off_t)phdr.p_offset, SEEK_SET) !=
2787c478bd9Sstevel@tonic-gate (off_t)phdr.p_offset)
2797c478bd9Sstevel@tonic-gate fatal_error("cannot seek to text section");
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate if (read(fd, textspace, textsize) != textsize)
2827c478bd9Sstevel@tonic-gate fatal_error("cannot read text");
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate if (textsize == 0)
2877c478bd9Sstevel@tonic-gate fatal_error("can't find text segment");
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate
2907c478bd9Sstevel@tonic-gate #ifdef DEBUG
2917c478bd9Sstevel@tonic-gate static void
debug_dup_del(nltype * keeper,nltype * louser)2927c478bd9Sstevel@tonic-gate debug_dup_del(nltype * keeper, nltype * louser)
2937c478bd9Sstevel@tonic-gate {
29492ed1782Smike_s (void) printf("remove_dup_syms: discarding sym %s over sym %s\n",
2957c478bd9Sstevel@tonic-gate louser->name, keeper->name);
2967c478bd9Sstevel@tonic-gate }
29792ed1782Smike_s #endif /* DEBUG */
2987c478bd9Sstevel@tonic-gate
2997c478bd9Sstevel@tonic-gate static void
remove_dup_syms(nltype * nl,sztype * sym_count)3007c478bd9Sstevel@tonic-gate remove_dup_syms(nltype *nl, sztype *sym_count)
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate int i;
3037c478bd9Sstevel@tonic-gate int index;
3047c478bd9Sstevel@tonic-gate int nextsym;
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate nltype * orig_list;
3077c478bd9Sstevel@tonic-gate if ((orig_list = malloc(sizeof (nltype) * *sym_count)) == NULL) {
30892ed1782Smike_s (void) fprintf(stderr,
30992ed1782Smike_s "gprof: remove_dup_syms: malloc failed\n");
31092ed1782Smike_s (void) fprintf(stderr, "Exiting due to error(s)...\n");
3117c478bd9Sstevel@tonic-gate exit(EX_UNAVAILABLE);
3127c478bd9Sstevel@tonic-gate }
31392ed1782Smike_s (void) memcpy(orig_list, nl, sizeof (nltype) * *sym_count);
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate for (i = 0, index = 0, nextsym = 1; nextsym < *sym_count; nextsym++) {
3167c478bd9Sstevel@tonic-gate int i_type;
3177c478bd9Sstevel@tonic-gate int n_bind;
3187c478bd9Sstevel@tonic-gate int n_type;
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate /*
3217c478bd9Sstevel@tonic-gate * If orig_list[nextsym] points to a new symvalue, then we
3227c478bd9Sstevel@tonic-gate * will copy our keeper and move on to the next symbol.
3237c478bd9Sstevel@tonic-gate */
3247c478bd9Sstevel@tonic-gate if ((orig_list + i)->value < (orig_list + nextsym)->value) {
3257c478bd9Sstevel@tonic-gate *(nl + index++) = *(orig_list +i);
3267c478bd9Sstevel@tonic-gate i = nextsym;
3277c478bd9Sstevel@tonic-gate continue;
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate * If these two symbols have the same info, then we
3327c478bd9Sstevel@tonic-gate * keep the first and keep checking for dups.
3337c478bd9Sstevel@tonic-gate */
3347c478bd9Sstevel@tonic-gate if ((orig_list + i)->syminfo ==
3357c478bd9Sstevel@tonic-gate (orig_list + nextsym)->syminfo) {
3367c478bd9Sstevel@tonic-gate DEBUG_DUP_DEL(orig_list + i, orig_list + nextsym);
3377c478bd9Sstevel@tonic-gate continue;
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate n_bind = ELF32_ST_BIND((orig_list + nextsym)->syminfo);
3407c478bd9Sstevel@tonic-gate i_type = ELF32_ST_TYPE((orig_list + i)->syminfo);
3417c478bd9Sstevel@tonic-gate n_type = ELF32_ST_TYPE((orig_list + nextsym)->syminfo);
3427c478bd9Sstevel@tonic-gate
3437c478bd9Sstevel@tonic-gate /*
3447c478bd9Sstevel@tonic-gate * If they have the same type we take the stronger
3457c478bd9Sstevel@tonic-gate * bound function.
3467c478bd9Sstevel@tonic-gate */
3477c478bd9Sstevel@tonic-gate if (i_type == n_type) {
3487c478bd9Sstevel@tonic-gate if (n_bind == STB_WEAK) {
3497c478bd9Sstevel@tonic-gate DEBUG_DUP_DEL((orig_list + i),
3507c478bd9Sstevel@tonic-gate (orig_list + nextsym));
3517c478bd9Sstevel@tonic-gate continue;
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate DEBUG_DUP_DEL((orig_list + nextsym),
3547c478bd9Sstevel@tonic-gate (orig_list + i));
3557c478bd9Sstevel@tonic-gate i = nextsym;
3567c478bd9Sstevel@tonic-gate continue;
3577c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate
3597c478bd9Sstevel@tonic-gate /*
3607c478bd9Sstevel@tonic-gate * If the first symbol isn't of type NOTYPE then it must
3617c478bd9Sstevel@tonic-gate * be the keeper.
3627c478bd9Sstevel@tonic-gate */
3637c478bd9Sstevel@tonic-gate if (i_type != STT_NOTYPE) {
3647c478bd9Sstevel@tonic-gate DEBUG_DUP_DEL((orig_list + i),
3657c478bd9Sstevel@tonic-gate (orig_list + nextsym));
3667c478bd9Sstevel@tonic-gate continue;
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate /*
3707c478bd9Sstevel@tonic-gate * Throw away the first one and take the new
3717c478bd9Sstevel@tonic-gate * symbol
3727c478bd9Sstevel@tonic-gate */
3737c478bd9Sstevel@tonic-gate DEBUG_DUP_DEL((orig_list + nextsym), (orig_list + i));
3747c478bd9Sstevel@tonic-gate i = nextsym;
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate if ((orig_list + i)->value > (nl + index - 1)->value)
3787c478bd9Sstevel@tonic-gate *(nl + index++) = *(orig_list +i);
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate *sym_count = index;
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate /*
3847c478bd9Sstevel@tonic-gate * compare either by name or by value for sorting.
3857c478bd9Sstevel@tonic-gate * This is the comparison function called by qsort to
3867c478bd9Sstevel@tonic-gate * sort the symbols either by name or value when requested.
3877c478bd9Sstevel@tonic-gate */
3887c478bd9Sstevel@tonic-gate static int
compare(const void * arg1,const void * arg2)38992ed1782Smike_s compare(const void *arg1, const void *arg2)
3907c478bd9Sstevel@tonic-gate {
39192ed1782Smike_s nltype *a = (nltype *)arg1;
39292ed1782Smike_s nltype *b = (nltype *)arg2;
39392ed1782Smike_s
3947c478bd9Sstevel@tonic-gate if (a->value > b->value)
3957c478bd9Sstevel@tonic-gate return (1);
3967c478bd9Sstevel@tonic-gate else
3977c478bd9Sstevel@tonic-gate return ((a->value == b->value) - 1);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate static int
is_function(Elf * elf,GElf_Sym * sym)4017c478bd9Sstevel@tonic-gate is_function(Elf *elf, GElf_Sym *sym)
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate Elf_Scn *scn;
4047c478bd9Sstevel@tonic-gate GElf_Shdr shdr;
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate /*
4077c478bd9Sstevel@tonic-gate * With shared objects, it is possible we come across a function
4087c478bd9Sstevel@tonic-gate * that's global, but is undefined. The definition is probably
4097c478bd9Sstevel@tonic-gate * elsewhere, so we'll have to skip it as far as this object is
4107c478bd9Sstevel@tonic-gate * concerned.
4117c478bd9Sstevel@tonic-gate */
4127c478bd9Sstevel@tonic-gate if (sym->st_shndx == SHN_UNDEF)
4137c478bd9Sstevel@tonic-gate return (0);
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) {
4167c478bd9Sstevel@tonic-gate if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL)
4177c478bd9Sstevel@tonic-gate return (1);
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate if (GELF_ST_BIND(sym->st_info) == STB_WEAK)
4207c478bd9Sstevel@tonic-gate return (1);
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate if (!aflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL)
4237c478bd9Sstevel@tonic-gate return (1);
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate /*
4277c478bd9Sstevel@tonic-gate * It's not a function; determine if it's in an executable section.
4287c478bd9Sstevel@tonic-gate */
4297c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym->st_info) != STT_NOTYPE)
4307c478bd9Sstevel@tonic-gate return (0);
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate /*
4337c478bd9Sstevel@tonic-gate * If it isn't global, and it isn't weak, and it either isn't
4347c478bd9Sstevel@tonic-gate * local or the "all flag" isn't set, then get out.
4357c478bd9Sstevel@tonic-gate */
4367c478bd9Sstevel@tonic-gate if (GELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
4377c478bd9Sstevel@tonic-gate GELF_ST_BIND(sym->st_info) != STB_WEAK &&
4387c478bd9Sstevel@tonic-gate (GELF_ST_BIND(sym->st_info) != STB_LOCAL || aflag))
4397c478bd9Sstevel@tonic-gate return (0);
4407c478bd9Sstevel@tonic-gate
4417c478bd9Sstevel@tonic-gate if (sym->st_shndx >= SHN_LORESERVE)
4427c478bd9Sstevel@tonic-gate return (0);
4437c478bd9Sstevel@tonic-gate
4447c478bd9Sstevel@tonic-gate scn = elf_getscn(elf, sym->st_shndx);
44592ed1782Smike_s (void) gelf_getshdr(scn, &shdr);
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate if (!(shdr.sh_flags & SHF_EXECINSTR))
4487c478bd9Sstevel@tonic-gate return (0);
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate return (1);
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate static void
get_symtab(Elf * elf,mod_info_t * module)45492ed1782Smike_s get_symtab(Elf *elf, mod_info_t *module)
4557c478bd9Sstevel@tonic-gate {
456*7a5d89c4Sab196087 Elf_Scn *scn = NULL, *sym_pri = NULL, *sym_aux = NULL;
4577c478bd9Sstevel@tonic-gate GElf_Word strndx = 0;
4587c478bd9Sstevel@tonic-gate sztype nsyms, i;
459*7a5d89c4Sab196087 Elf_Data *symdata_pri;
460*7a5d89c4Sab196087 Elf_Data *symdata_aux;
461*7a5d89c4Sab196087 GElf_Xword nsyms_pri, nsyms_aux = 0;
4627c478bd9Sstevel@tonic-gate nltype *etext = NULL;
4637c478bd9Sstevel@tonic-gate nltype *l_nl, *l_npe;
4647c478bd9Sstevel@tonic-gate sztype l_nname;
4657c478bd9Sstevel@tonic-gate extern sztype total_names;
466*7a5d89c4Sab196087 int symtab_found = 0;
4677c478bd9Sstevel@tonic-gate
468*7a5d89c4Sab196087
469*7a5d89c4Sab196087 /*
470*7a5d89c4Sab196087 * Scan the section headers looking for a symbol table. Our
471*7a5d89c4Sab196087 * preference is to use .symtab, because it contains the full
472*7a5d89c4Sab196087 * set of symbols. If we find it, we stop looking immediately
473*7a5d89c4Sab196087 * and use it. In the absence of a .symtab section, we are
474*7a5d89c4Sab196087 * willing to use the dynamic symbol table (.dynsym), possibly
475*7a5d89c4Sab196087 * augmented by the .SUNW_ldynsym, which contains local symbols.
476*7a5d89c4Sab196087 */
477*7a5d89c4Sab196087 while ((symtab_found == 0) && ((scn = elf_nextscn(elf, scn)) != NULL)) {
4787c478bd9Sstevel@tonic-gate GElf_Shdr shdr;
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate if (gelf_getshdr(scn, &shdr) == NULL)
4817c478bd9Sstevel@tonic-gate continue;
4827c478bd9Sstevel@tonic-gate
483*7a5d89c4Sab196087 switch (shdr.sh_type) {
484*7a5d89c4Sab196087 case SHT_SYMTAB:
485*7a5d89c4Sab196087 nsyms_pri = shdr.sh_size / shdr.sh_entsize;
4867c478bd9Sstevel@tonic-gate strndx = shdr.sh_link;
487*7a5d89c4Sab196087 sym_pri = scn;
488*7a5d89c4Sab196087 /* Throw away .SUNW_ldynsym. It is for .dynsym only */
489*7a5d89c4Sab196087 nsyms_aux = 0;
490*7a5d89c4Sab196087 sym_aux = NULL;
491*7a5d89c4Sab196087 /* We have found the best symbol table. Stop looking */
492*7a5d89c4Sab196087 symtab_found = 1;
493*7a5d89c4Sab196087 break;
4947c478bd9Sstevel@tonic-gate
495*7a5d89c4Sab196087 case SHT_DYNSYM:
496*7a5d89c4Sab196087 /* We will use .dynsym if no .symtab is found */
497*7a5d89c4Sab196087 nsyms_pri = shdr.sh_size / shdr.sh_entsize;
498*7a5d89c4Sab196087 strndx = shdr.sh_link;
499*7a5d89c4Sab196087 sym_pri = scn;
500*7a5d89c4Sab196087 break;
501*7a5d89c4Sab196087
502*7a5d89c4Sab196087 case SHT_SUNW_LDYNSYM:
503*7a5d89c4Sab196087 /* Auxiliary table, used with .dynsym */
504*7a5d89c4Sab196087 nsyms_aux = shdr.sh_size / shdr.sh_entsize;
505*7a5d89c4Sab196087 sym_aux = scn;
5067c478bd9Sstevel@tonic-gate break;
5077c478bd9Sstevel@tonic-gate }
508*7a5d89c4Sab196087 }
5097c478bd9Sstevel@tonic-gate
510*7a5d89c4Sab196087 if (sym_pri == NULL || strndx == 0)
5117c478bd9Sstevel@tonic-gate fatal_error("can't find symbol table.\n");
5127c478bd9Sstevel@tonic-gate
513*7a5d89c4Sab196087 nsyms = (sztype)(nsyms_pri + nsyms_aux);
514*7a5d89c4Sab196087 if ((nsyms_pri + nsyms_aux) != (GElf_Xword)nsyms)
515*7a5d89c4Sab196087 fatal_error(
516*7a5d89c4Sab196087 "32-bit gprof cannot handle more than 2^32 symbols");
517*7a5d89c4Sab196087
518*7a5d89c4Sab196087 if ((symdata_pri = elf_getdata(sym_pri, NULL)) == NULL)
5197c478bd9Sstevel@tonic-gate fatal_error("can't read symbol data.\n");
5207c478bd9Sstevel@tonic-gate
521*7a5d89c4Sab196087 if ((sym_aux != NULL) &&
522*7a5d89c4Sab196087 ((symdata_aux = elf_getdata(sym_aux, NULL)) == NULL))
523*7a5d89c4Sab196087 fatal_error("can't read .SUNW_ldynsym symbol data.\n");
524*7a5d89c4Sab196087
5257c478bd9Sstevel@tonic-gate if ((l_nl = l_npe = (nltype *)calloc(nsyms + PRF_SYMCNT,
5267c478bd9Sstevel@tonic-gate sizeof (nltype))) == NULL)
5277c478bd9Sstevel@tonic-gate fatal_error("cannot allocate symbol data.\n");
5287c478bd9Sstevel@tonic-gate
5297c478bd9Sstevel@tonic-gate /*
5307c478bd9Sstevel@tonic-gate * Now we need to cruise through the symbol table eliminating
5317c478bd9Sstevel@tonic-gate * all non-functions from consideration, and making strings
5327c478bd9Sstevel@tonic-gate * real.
5337c478bd9Sstevel@tonic-gate */
5347c478bd9Sstevel@tonic-gate l_nname = 0;
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate for (i = 1; i < nsyms; i++) {
5377c478bd9Sstevel@tonic-gate GElf_Sym gsym;
5387c478bd9Sstevel@tonic-gate char *name;
5397c478bd9Sstevel@tonic-gate
540*7a5d89c4Sab196087 /*
541*7a5d89c4Sab196087 * Look up the symbol. In the case where we have a
542*7a5d89c4Sab196087 * .SUNW_ldynsym/.dynsym pair, we treat them as a single
543*7a5d89c4Sab196087 * logical table, with the data from .SUNW_ldynsym coming
544*7a5d89c4Sab196087 * before the data in .dynsym.
545*7a5d89c4Sab196087 */
546*7a5d89c4Sab196087 if (i >= nsyms_aux)
547*7a5d89c4Sab196087 (void) gelf_getsym(symdata_pri, i - nsyms_aux, &gsym);
548*7a5d89c4Sab196087 else
549*7a5d89c4Sab196087 (void) gelf_getsym(symdata_aux, i, &gsym);
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate name = elf_strptr(elf, strndx, gsym.st_name);
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate /*
5547c478bd9Sstevel@tonic-gate * We're interested in this symbol if it's a function or
5557c478bd9Sstevel@tonic-gate * if it's the symbol "_etext"
5567c478bd9Sstevel@tonic-gate */
5577c478bd9Sstevel@tonic-gate if (is_function(elf, &gsym) || strcmp(name, PRF_ETEXT) == 0) {
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate l_npe->name = name;
5607c478bd9Sstevel@tonic-gate l_npe->value = gsym.st_value;
5617c478bd9Sstevel@tonic-gate l_npe->sz = gsym.st_size;
5627c478bd9Sstevel@tonic-gate l_npe->syminfo = gsym.st_info;
5637c478bd9Sstevel@tonic-gate l_npe->module = module;
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate if (strcmp(name, PRF_ETEXT) == 0)
5667c478bd9Sstevel@tonic-gate etext = l_npe;
5677c478bd9Sstevel@tonic-gate
5687c478bd9Sstevel@tonic-gate if (lflag == TRUE &&
5697c478bd9Sstevel@tonic-gate GELF_ST_BIND(gsym.st_info) == STB_LOCAL) {
5707c478bd9Sstevel@tonic-gate /*
5717c478bd9Sstevel@tonic-gate * If the "locals only" flag is on, then
5727c478bd9Sstevel@tonic-gate * we add the local symbols to the
5737c478bd9Sstevel@tonic-gate * exclusion lists.
5747c478bd9Sstevel@tonic-gate */
5757c478bd9Sstevel@tonic-gate addlist(Elist, name);
5767c478bd9Sstevel@tonic-gate addlist(elist, name);
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate DPRINTF("Index %lld:", l_nname);
5797c478bd9Sstevel@tonic-gate DPRINTF("\tValue: 0x%llx\t", l_npe->value);
5807c478bd9Sstevel@tonic-gate DPRINTF("Name: %s \n", l_npe->name);
5817c478bd9Sstevel@tonic-gate l_npe++;
5827c478bd9Sstevel@tonic-gate l_nname++;
5837c478bd9Sstevel@tonic-gate }
5847c478bd9Sstevel@tonic-gate
5857c478bd9Sstevel@tonic-gate if (strcmp(name, PRF_END) == 0)
5867c478bd9Sstevel@tonic-gate module->data_end = gsym.st_value;
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate
5897c478bd9Sstevel@tonic-gate if (l_npe == l_nl)
5907c478bd9Sstevel@tonic-gate fatal_error("no valid functions found");
5917c478bd9Sstevel@tonic-gate
5927c478bd9Sstevel@tonic-gate /*
5937c478bd9Sstevel@tonic-gate * Finally, we need to construct some dummy entries.
5947c478bd9Sstevel@tonic-gate */
5957c478bd9Sstevel@tonic-gate if (etext) {
5967c478bd9Sstevel@tonic-gate l_npe->name = PRF_EXTSYM;
5977c478bd9Sstevel@tonic-gate l_npe->value = etext->value + 1;
5987c478bd9Sstevel@tonic-gate l_npe->syminfo = GELF_ST_INFO(STB_GLOBAL, STT_FUNC);
5997c478bd9Sstevel@tonic-gate l_npe->module = module;
6007c478bd9Sstevel@tonic-gate l_npe++;
6017c478bd9Sstevel@tonic-gate l_nname++;
6027c478bd9Sstevel@tonic-gate }
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate l_npe->name = PRF_MEMTERM;
6057c478bd9Sstevel@tonic-gate l_npe->value = (pctype)-1;
6067c478bd9Sstevel@tonic-gate l_npe->syminfo = GELF_ST_INFO(STB_GLOBAL, STT_FUNC);
6077c478bd9Sstevel@tonic-gate l_npe->module = module;
6087c478bd9Sstevel@tonic-gate l_npe++;
6097c478bd9Sstevel@tonic-gate l_nname++;
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate /*
6127c478bd9Sstevel@tonic-gate * We're almost done; all we need to do is sort the symbols
6137c478bd9Sstevel@tonic-gate * and then remove the duplicates.
6147c478bd9Sstevel@tonic-gate */
61592ed1782Smike_s qsort(l_nl, (size_t)l_nname, sizeof (nltype), compare);
6167c478bd9Sstevel@tonic-gate remove_dup_syms(l_nl, &l_nname);
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate module->nl = l_nl;
6197c478bd9Sstevel@tonic-gate module->npe = l_npe;
6207c478bd9Sstevel@tonic-gate module->nname = l_nname;
6217c478bd9Sstevel@tonic-gate
6227c478bd9Sstevel@tonic-gate total_names += l_nname;
6237c478bd9Sstevel@tonic-gate }
624