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 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 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 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 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 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 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 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 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 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 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 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 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 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