1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright (c) 1993-1998 by Sun Microsystems, Inc. 24*0Sstevel@tonic-gate * All rights reserved. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include "gprof.h" 30*0Sstevel@tonic-gate #include <stdlib.h> 31*0Sstevel@tonic-gate #include <sys/file.h> 32*0Sstevel@tonic-gate #include <fcntl.h> 33*0Sstevel@tonic-gate #include <unistd.h> 34*0Sstevel@tonic-gate #include <string.h> 35*0Sstevel@tonic-gate #include <sysexits.h> 36*0Sstevel@tonic-gate #include <libelf.h> 37*0Sstevel@tonic-gate #include "gelf.h" 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #ifdef DEBUG 40*0Sstevel@tonic-gate static void debug_dup_del(nltype *, nltype *); 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate #define DPRINTF(msg, file) if (debug & ELFDEBUG) \ 43*0Sstevel@tonic-gate printf(msg, file); 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate #define PRINTF(msg) if (debug & ELFDEBUG) \ 46*0Sstevel@tonic-gate printf(msg); 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate #define DEBUG_DUP_DEL(keeper, louser) if (debug & ELFDEBUG) \ 49*0Sstevel@tonic-gate debug_dup_del(keeper, louser); 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate #else 52*0Sstevel@tonic-gate #define DPRINTF(msg, file) 53*0Sstevel@tonic-gate #define PRINTF(msg) 54*0Sstevel@tonic-gate #define DEBUG_DUP_DEL(keeper, louser) 55*0Sstevel@tonic-gate #endif 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate #define VOID_P void * 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate size_t textbegin, textsize; 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate /* Prototype definitions first */ 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate static void process(char *filename, int fd); 66*0Sstevel@tonic-gate static void get_symtab(Elf *elf, char *filename, mod_info_t *module); 67*0Sstevel@tonic-gate static void get_textseg(Elf *elf, int fd, char *filename); 68*0Sstevel@tonic-gate static void save_aout_info(char *); 69*0Sstevel@tonic-gate static int compare(nltype *a, nltype *b); 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate static void 72*0Sstevel@tonic-gate fatal_error(char *error) 73*0Sstevel@tonic-gate { 74*0Sstevel@tonic-gate fprintf(stderr, "Fatal ELF error: %s (%s)\n", error, elf_errmsg(-1)); 75*0Sstevel@tonic-gate exit(EX_SOFTWARE); 76*0Sstevel@tonic-gate } 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate bool 79*0Sstevel@tonic-gate is_shared_obj(char *name) 80*0Sstevel@tonic-gate { 81*0Sstevel@tonic-gate int fd; 82*0Sstevel@tonic-gate Elf *elf; 83*0Sstevel@tonic-gate GElf_Ehdr ehdr; 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate if ((fd = open(name, O_RDONLY)) == -1) { 86*0Sstevel@tonic-gate fprintf(stderr, "%s: can't open `%s'\n", whoami, name); 87*0Sstevel@tonic-gate exit(EX_NOINPUT); 88*0Sstevel@tonic-gate } 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate if (elf_version(EV_CURRENT) == EV_NONE) 91*0Sstevel@tonic-gate fatal_error("libelf is out of date"); 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 94*0Sstevel@tonic-gate fatal_error("can't read as ELF file"); 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL) 97*0Sstevel@tonic-gate fatal_error("can't read ehdr"); 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate elf_end(elf); 100*0Sstevel@tonic-gate close(fd); 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate if (ehdr.e_type == ET_DYN) 103*0Sstevel@tonic-gate return (TRUE); 104*0Sstevel@tonic-gate else 105*0Sstevel@tonic-gate return (FALSE); 106*0Sstevel@tonic-gate } 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate static void 109*0Sstevel@tonic-gate save_aout_info(char *aoutname) 110*0Sstevel@tonic-gate { 111*0Sstevel@tonic-gate struct stat buf; 112*0Sstevel@tonic-gate extern fl_info_t aout_info; 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate if (stat(aoutname, &buf) == -1) { 115*0Sstevel@tonic-gate fprintf(stderr, "%s: can't get info on `%s'\n", 116*0Sstevel@tonic-gate whoami, aoutname); 117*0Sstevel@tonic-gate exit(EX_NOINPUT); 118*0Sstevel@tonic-gate } 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate aout_info.dev = buf.st_dev; 121*0Sstevel@tonic-gate aout_info.ino = buf.st_ino; 122*0Sstevel@tonic-gate aout_info.mtime = buf.st_mtime; 123*0Sstevel@tonic-gate aout_info.size = buf.st_size; 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate void 127*0Sstevel@tonic-gate getnfile(char *aoutname) 128*0Sstevel@tonic-gate { 129*0Sstevel@tonic-gate int fd; 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate DPRINTF(" Attempting to open %s \n", aoutname); 132*0Sstevel@tonic-gate if ((fd = open((aoutname), O_RDONLY)) == -1) { 133*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: can't open `%s'\n", 134*0Sstevel@tonic-gate whoami, aoutname); 135*0Sstevel@tonic-gate exit(EX_NOINPUT); 136*0Sstevel@tonic-gate } 137*0Sstevel@tonic-gate process(aoutname, fd); 138*0Sstevel@tonic-gate save_aout_info(aoutname); 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate (void) close(fd); 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate static GElf_Addr 144*0Sstevel@tonic-gate get_txtorigin(Elf *elf) 145*0Sstevel@tonic-gate { 146*0Sstevel@tonic-gate GElf_Ehdr ehdr; 147*0Sstevel@tonic-gate GElf_Phdr phdr; 148*0Sstevel@tonic-gate GElf_Half ndx; 149*0Sstevel@tonic-gate GElf_Addr txt_origin = 0; 150*0Sstevel@tonic-gate bool first_load_seg = TRUE; 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL) 153*0Sstevel@tonic-gate fatal_error("can't read ehdr"); 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate for (ndx = 0; ndx < ehdr.e_phnum; ndx++) { 156*0Sstevel@tonic-gate if (gelf_getphdr(elf, ndx, &phdr) == NULL) 157*0Sstevel@tonic-gate continue; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate if ((phdr.p_type == PT_LOAD) && !(phdr.p_flags & PF_W)) { 160*0Sstevel@tonic-gate if (first_load_seg || phdr.p_vaddr < txt_origin) 161*0Sstevel@tonic-gate txt_origin = phdr.p_vaddr; 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate if (first_load_seg) 164*0Sstevel@tonic-gate first_load_seg = FALSE; 165*0Sstevel@tonic-gate } 166*0Sstevel@tonic-gate } 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate return (txt_origin); 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate void 172*0Sstevel@tonic-gate process_namelist(mod_info_t *module) 173*0Sstevel@tonic-gate { 174*0Sstevel@tonic-gate int fd; 175*0Sstevel@tonic-gate Elf *elf; 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate if ((fd = open(module->name, O_RDONLY)) == -1) { 178*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: can't read %s\n", 179*0Sstevel@tonic-gate whoami, module->name); 180*0Sstevel@tonic-gate fprintf(stderr, "Exiting due to error(s)...\n"); 181*0Sstevel@tonic-gate exit(EX_NOINPUT); 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /* 185*0Sstevel@tonic-gate * libelf's version already verified in processing a.out, 186*0Sstevel@tonic-gate * so directly do elf_begin() 187*0Sstevel@tonic-gate */ 188*0Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 189*0Sstevel@tonic-gate fatal_error("can't read as ELF file"); 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate module->next = NULL; 192*0Sstevel@tonic-gate module->txt_origin = get_txtorigin(elf); 193*0Sstevel@tonic-gate get_symtab(elf, module->name, module); 194*0Sstevel@tonic-gate module->active = TRUE; 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /* 198*0Sstevel@tonic-gate * Get the ELF header and, if it exists, call get_symtab() 199*0Sstevel@tonic-gate * to begin processing of the file; otherwise, return from 200*0Sstevel@tonic-gate * processing the file with a warning. 201*0Sstevel@tonic-gate */ 202*0Sstevel@tonic-gate static void 203*0Sstevel@tonic-gate process(char *filename, int fd) 204*0Sstevel@tonic-gate { 205*0Sstevel@tonic-gate Elf *elf; 206*0Sstevel@tonic-gate extern bool cflag; 207*0Sstevel@tonic-gate extern bool Bflag; 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate if (elf_version(EV_CURRENT) == EV_NONE) 210*0Sstevel@tonic-gate fatal_error("libelf is out of date"); 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) 213*0Sstevel@tonic-gate fatal_error("can't read as ELF file"); 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate if (gelf_getclass(elf) == ELFCLASS64) 216*0Sstevel@tonic-gate Bflag = TRUE; 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate /* 219*0Sstevel@tonic-gate * Initialize active modules list. Note that we set the end 220*0Sstevel@tonic-gate * address while reading the symbol table, in get_symtab 221*0Sstevel@tonic-gate */ 222*0Sstevel@tonic-gate modules.id = 1; 223*0Sstevel@tonic-gate modules.next = NULL; 224*0Sstevel@tonic-gate modules.txt_origin = get_txtorigin(elf); 225*0Sstevel@tonic-gate modules.load_base = modules.txt_origin; 226*0Sstevel@tonic-gate if ((modules.name = (char *) malloc(strlen(filename) + 1)) == NULL) { 227*0Sstevel@tonic-gate fprintf(stderr, "%s: can't malloc %d bytes", 228*0Sstevel@tonic-gate whoami, strlen(filename) + 1); 229*0Sstevel@tonic-gate exit(EX_UNAVAILABLE); 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate strcpy(modules.name, filename); 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate get_symtab(elf, filename, &modules); 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate modules.load_end = modules.data_end; 236*0Sstevel@tonic-gate modules.active = TRUE; 237*0Sstevel@tonic-gate n_modules = 1; 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate if (cflag) 240*0Sstevel@tonic-gate get_textseg(elf, fd, filename); 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate static void 244*0Sstevel@tonic-gate get_textseg(Elf *elf, int fd, char *filename) 245*0Sstevel@tonic-gate { 246*0Sstevel@tonic-gate GElf_Ehdr ehdr; 247*0Sstevel@tonic-gate GElf_Phdr phdr; 248*0Sstevel@tonic-gate GElf_Half i; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL) 251*0Sstevel@tonic-gate fatal_error("can't read ehdr"); 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate for (i = 0; i < ehdr.e_phnum; i++) { 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate if (gelf_getphdr(elf, i, &phdr) == NULL) 256*0Sstevel@tonic-gate continue; 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate if (!(phdr.p_flags & PF_W) && (phdr.p_filesz > textsize)) { 259*0Sstevel@tonic-gate size_t chk; 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate /* 262*0Sstevel@tonic-gate * We could have multiple loadable text segments; 263*0Sstevel@tonic-gate * keep the largest we find. 264*0Sstevel@tonic-gate */ 265*0Sstevel@tonic-gate if (textspace) 266*0Sstevel@tonic-gate free(textspace); 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate /* 269*0Sstevel@tonic-gate * gprof is a 32-bit program; if this text segment 270*0Sstevel@tonic-gate * has a > 32-bit offset or length, it's too big. 271*0Sstevel@tonic-gate */ 272*0Sstevel@tonic-gate chk = (size_t)phdr.p_vaddr + (size_t)phdr.p_filesz; 273*0Sstevel@tonic-gate if (phdr.p_vaddr + phdr.p_filesz != (GElf_Xword)chk) 274*0Sstevel@tonic-gate fatal_error("text segment too large for -c"); 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate textbegin = (size_t)phdr.p_vaddr; 277*0Sstevel@tonic-gate textsize = (size_t)phdr.p_filesz; 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate textspace = malloc(textsize); 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate if (lseek(fd, (off_t)phdr.p_offset, SEEK_SET) != 282*0Sstevel@tonic-gate (off_t)phdr.p_offset) 283*0Sstevel@tonic-gate fatal_error("cannot seek to text section"); 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate if (read(fd, textspace, textsize) != textsize) 286*0Sstevel@tonic-gate fatal_error("cannot read text"); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate } 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate if (textsize == 0) 291*0Sstevel@tonic-gate fatal_error("can't find text segment"); 292*0Sstevel@tonic-gate } 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate #ifdef DEBUG 295*0Sstevel@tonic-gate static void 296*0Sstevel@tonic-gate debug_dup_del(nltype * keeper, nltype * louser) 297*0Sstevel@tonic-gate { 298*0Sstevel@tonic-gate printf("remove_dup_syms: discarding sym %s over sym %s\n", 299*0Sstevel@tonic-gate louser->name, keeper->name); 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate #endif DEBUG 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate static void 304*0Sstevel@tonic-gate remove_dup_syms(nltype *nl, sztype *sym_count) 305*0Sstevel@tonic-gate { 306*0Sstevel@tonic-gate int i; 307*0Sstevel@tonic-gate int index; 308*0Sstevel@tonic-gate int nextsym; 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate nltype * orig_list; 311*0Sstevel@tonic-gate if ((orig_list = malloc(sizeof (nltype) * *sym_count)) == NULL) { 312*0Sstevel@tonic-gate fprintf(stderr, "gprof: remove_dup_syms: malloc failed\n"); 313*0Sstevel@tonic-gate fprintf(stderr, "Exiting due to error(s)...\n"); 314*0Sstevel@tonic-gate exit(EX_UNAVAILABLE); 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate memcpy(orig_list, nl, sizeof (nltype) * *sym_count); 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate for (i = 0, index = 0, nextsym = 1; nextsym < *sym_count; nextsym++) { 319*0Sstevel@tonic-gate int i_type; 320*0Sstevel@tonic-gate int n_bind; 321*0Sstevel@tonic-gate int n_type; 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate /* 324*0Sstevel@tonic-gate * If orig_list[nextsym] points to a new symvalue, then we 325*0Sstevel@tonic-gate * will copy our keeper and move on to the next symbol. 326*0Sstevel@tonic-gate */ 327*0Sstevel@tonic-gate if ((orig_list + i)->value < (orig_list + nextsym)->value) { 328*0Sstevel@tonic-gate *(nl + index++) = *(orig_list +i); 329*0Sstevel@tonic-gate i = nextsym; 330*0Sstevel@tonic-gate continue; 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* 334*0Sstevel@tonic-gate * If these two symbols have the same info, then we 335*0Sstevel@tonic-gate * keep the first and keep checking for dups. 336*0Sstevel@tonic-gate */ 337*0Sstevel@tonic-gate if ((orig_list + i)->syminfo == 338*0Sstevel@tonic-gate (orig_list + nextsym)->syminfo) { 339*0Sstevel@tonic-gate DEBUG_DUP_DEL(orig_list + i, orig_list + nextsym); 340*0Sstevel@tonic-gate continue; 341*0Sstevel@tonic-gate } 342*0Sstevel@tonic-gate n_bind = ELF32_ST_BIND((orig_list + nextsym)->syminfo); 343*0Sstevel@tonic-gate i_type = ELF32_ST_TYPE((orig_list + i)->syminfo); 344*0Sstevel@tonic-gate n_type = ELF32_ST_TYPE((orig_list + nextsym)->syminfo); 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate /* 347*0Sstevel@tonic-gate * If they have the same type we take the stronger 348*0Sstevel@tonic-gate * bound function. 349*0Sstevel@tonic-gate */ 350*0Sstevel@tonic-gate if (i_type == n_type) { 351*0Sstevel@tonic-gate if (n_bind == STB_WEAK) { 352*0Sstevel@tonic-gate DEBUG_DUP_DEL((orig_list + i), 353*0Sstevel@tonic-gate (orig_list + nextsym)); 354*0Sstevel@tonic-gate continue; 355*0Sstevel@tonic-gate } 356*0Sstevel@tonic-gate DEBUG_DUP_DEL((orig_list + nextsym), 357*0Sstevel@tonic-gate (orig_list + i)); 358*0Sstevel@tonic-gate i = nextsym; 359*0Sstevel@tonic-gate continue; 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate /* 363*0Sstevel@tonic-gate * If the first symbol isn't of type NOTYPE then it must 364*0Sstevel@tonic-gate * be the keeper. 365*0Sstevel@tonic-gate */ 366*0Sstevel@tonic-gate if (i_type != STT_NOTYPE) { 367*0Sstevel@tonic-gate DEBUG_DUP_DEL((orig_list + i), 368*0Sstevel@tonic-gate (orig_list + nextsym)); 369*0Sstevel@tonic-gate continue; 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate /* 373*0Sstevel@tonic-gate * Throw away the first one and take the new 374*0Sstevel@tonic-gate * symbol 375*0Sstevel@tonic-gate */ 376*0Sstevel@tonic-gate DEBUG_DUP_DEL((orig_list + nextsym), (orig_list + i)); 377*0Sstevel@tonic-gate i = nextsym; 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate if ((orig_list + i)->value > (nl + index - 1)->value) 381*0Sstevel@tonic-gate *(nl + index++) = *(orig_list +i); 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate *sym_count = index; 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate /* 387*0Sstevel@tonic-gate * compare either by name or by value for sorting. 388*0Sstevel@tonic-gate * This is the comparison function called by qsort to 389*0Sstevel@tonic-gate * sort the symbols either by name or value when requested. 390*0Sstevel@tonic-gate */ 391*0Sstevel@tonic-gate static int 392*0Sstevel@tonic-gate compare(nltype *a, nltype *b) 393*0Sstevel@tonic-gate { 394*0Sstevel@tonic-gate if (a->value > b->value) 395*0Sstevel@tonic-gate return (1); 396*0Sstevel@tonic-gate else 397*0Sstevel@tonic-gate return ((a->value == b->value) - 1); 398*0Sstevel@tonic-gate } 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate static int 401*0Sstevel@tonic-gate is_function(Elf *elf, GElf_Sym *sym) 402*0Sstevel@tonic-gate { 403*0Sstevel@tonic-gate Elf_Scn *scn; 404*0Sstevel@tonic-gate GElf_Shdr shdr; 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate /* 407*0Sstevel@tonic-gate * With shared objects, it is possible we come across a function 408*0Sstevel@tonic-gate * that's global, but is undefined. The definition is probably 409*0Sstevel@tonic-gate * elsewhere, so we'll have to skip it as far as this object is 410*0Sstevel@tonic-gate * concerned. 411*0Sstevel@tonic-gate */ 412*0Sstevel@tonic-gate if (sym->st_shndx == SHN_UNDEF) 413*0Sstevel@tonic-gate return (0); 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) { 416*0Sstevel@tonic-gate if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL) 417*0Sstevel@tonic-gate return (1); 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate if (GELF_ST_BIND(sym->st_info) == STB_WEAK) 420*0Sstevel@tonic-gate return (1); 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate if (!aflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL) 423*0Sstevel@tonic-gate return (1); 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate /* 427*0Sstevel@tonic-gate * It's not a function; determine if it's in an executable section. 428*0Sstevel@tonic-gate */ 429*0Sstevel@tonic-gate if (GELF_ST_TYPE(sym->st_info) != STT_NOTYPE) 430*0Sstevel@tonic-gate return (0); 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate /* 433*0Sstevel@tonic-gate * If it isn't global, and it isn't weak, and it either isn't 434*0Sstevel@tonic-gate * local or the "all flag" isn't set, then get out. 435*0Sstevel@tonic-gate */ 436*0Sstevel@tonic-gate if (GELF_ST_BIND(sym->st_info) != STB_GLOBAL && 437*0Sstevel@tonic-gate GELF_ST_BIND(sym->st_info) != STB_WEAK && 438*0Sstevel@tonic-gate (GELF_ST_BIND(sym->st_info) != STB_LOCAL || aflag)) 439*0Sstevel@tonic-gate return (0); 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate if (sym->st_shndx >= SHN_LORESERVE) 442*0Sstevel@tonic-gate return (0); 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate scn = elf_getscn(elf, sym->st_shndx); 445*0Sstevel@tonic-gate gelf_getshdr(scn, &shdr); 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate if (!(shdr.sh_flags & SHF_EXECINSTR)) 448*0Sstevel@tonic-gate return (0); 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate return (1); 451*0Sstevel@tonic-gate } 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate static void 454*0Sstevel@tonic-gate get_symtab(Elf *elf, char *filename, mod_info_t *module) 455*0Sstevel@tonic-gate { 456*0Sstevel@tonic-gate Elf_Scn *scn = NULL, *sym = NULL; 457*0Sstevel@tonic-gate GElf_Word strndx = 0; 458*0Sstevel@tonic-gate sztype nsyms, i; 459*0Sstevel@tonic-gate Elf_Data *symdata; 460*0Sstevel@tonic-gate nltype *etext = NULL; 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate nltype *l_nl, *l_npe; 463*0Sstevel@tonic-gate sztype l_nname; 464*0Sstevel@tonic-gate extern sztype total_names; 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate while ((scn = elf_nextscn(elf, scn)) != NULL) { 467*0Sstevel@tonic-gate GElf_Shdr shdr; 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate if (gelf_getshdr(scn, &shdr) == NULL) 470*0Sstevel@tonic-gate continue; 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { 473*0Sstevel@tonic-gate GElf_Xword chk = shdr.sh_size / shdr.sh_entsize; 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate nsyms = (sztype)(shdr.sh_size / shdr.sh_entsize); 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate if (chk != (GElf_Xword)nsyms) 478*0Sstevel@tonic-gate fatal_error("32-bit gprof cannot handle" 479*0Sstevel@tonic-gate "more than 2^32 symbols"); 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate strndx = shdr.sh_link; 482*0Sstevel@tonic-gate sym = scn; 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate /* 486*0Sstevel@tonic-gate * If we've found a real symbol table, we're done. 487*0Sstevel@tonic-gate */ 488*0Sstevel@tonic-gate if (shdr.sh_type == SHT_SYMTAB) 489*0Sstevel@tonic-gate break; 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate if (sym == NULL || strndx == 0) 493*0Sstevel@tonic-gate fatal_error("can't find symbol table.\n"); 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate if ((symdata = elf_getdata(scn, NULL)) == NULL) 496*0Sstevel@tonic-gate fatal_error("can't read symbol data.\n"); 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate if ((l_nl = l_npe = (nltype *)calloc(nsyms + PRF_SYMCNT, 499*0Sstevel@tonic-gate sizeof (nltype))) == NULL) 500*0Sstevel@tonic-gate fatal_error("cannot allocate symbol data.\n"); 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate /* 503*0Sstevel@tonic-gate * Now we need to cruise through the symbol table eliminating 504*0Sstevel@tonic-gate * all non-functions from consideration, and making strings 505*0Sstevel@tonic-gate * real. 506*0Sstevel@tonic-gate */ 507*0Sstevel@tonic-gate l_nname = 0; 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate for (i = 1; i < nsyms; i++) { 510*0Sstevel@tonic-gate GElf_Sym gsym; 511*0Sstevel@tonic-gate char *name; 512*0Sstevel@tonic-gate 513*0Sstevel@tonic-gate gelf_getsym(symdata, i, &gsym); 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate name = elf_strptr(elf, strndx, gsym.st_name); 516*0Sstevel@tonic-gate 517*0Sstevel@tonic-gate /* 518*0Sstevel@tonic-gate * We're interested in this symbol if it's a function or 519*0Sstevel@tonic-gate * if it's the symbol "_etext" 520*0Sstevel@tonic-gate */ 521*0Sstevel@tonic-gate if (is_function(elf, &gsym) || strcmp(name, PRF_ETEXT) == 0) { 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate l_npe->name = name; 524*0Sstevel@tonic-gate l_npe->value = gsym.st_value; 525*0Sstevel@tonic-gate l_npe->sz = gsym.st_size; 526*0Sstevel@tonic-gate l_npe->syminfo = gsym.st_info; 527*0Sstevel@tonic-gate l_npe->module = module; 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate if (strcmp(name, PRF_ETEXT) == 0) 530*0Sstevel@tonic-gate etext = l_npe; 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate if (lflag == TRUE && 533*0Sstevel@tonic-gate GELF_ST_BIND(gsym.st_info) == STB_LOCAL) { 534*0Sstevel@tonic-gate /* 535*0Sstevel@tonic-gate * If the "locals only" flag is on, then 536*0Sstevel@tonic-gate * we add the local symbols to the 537*0Sstevel@tonic-gate * exclusion lists. 538*0Sstevel@tonic-gate */ 539*0Sstevel@tonic-gate addlist(Elist, name); 540*0Sstevel@tonic-gate addlist(elist, name); 541*0Sstevel@tonic-gate } 542*0Sstevel@tonic-gate DPRINTF("Index %lld:", l_nname); 543*0Sstevel@tonic-gate DPRINTF("\tValue: 0x%llx\t", l_npe->value); 544*0Sstevel@tonic-gate DPRINTF("Name: %s \n", l_npe->name); 545*0Sstevel@tonic-gate l_npe++; 546*0Sstevel@tonic-gate l_nname++; 547*0Sstevel@tonic-gate } 548*0Sstevel@tonic-gate 549*0Sstevel@tonic-gate if (strcmp(name, PRF_END) == 0) 550*0Sstevel@tonic-gate module->data_end = gsym.st_value; 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate if (l_npe == l_nl) 554*0Sstevel@tonic-gate fatal_error("no valid functions found"); 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate /* 557*0Sstevel@tonic-gate * Finally, we need to construct some dummy entries. 558*0Sstevel@tonic-gate */ 559*0Sstevel@tonic-gate if (etext) { 560*0Sstevel@tonic-gate l_npe->name = PRF_EXTSYM; 561*0Sstevel@tonic-gate l_npe->value = etext->value + 1; 562*0Sstevel@tonic-gate l_npe->syminfo = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); 563*0Sstevel@tonic-gate l_npe->module = module; 564*0Sstevel@tonic-gate l_npe++; 565*0Sstevel@tonic-gate l_nname++; 566*0Sstevel@tonic-gate } 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate l_npe->name = PRF_MEMTERM; 569*0Sstevel@tonic-gate l_npe->value = (pctype)-1; 570*0Sstevel@tonic-gate l_npe->syminfo = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); 571*0Sstevel@tonic-gate l_npe->module = module; 572*0Sstevel@tonic-gate l_npe++; 573*0Sstevel@tonic-gate l_nname++; 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate /* 576*0Sstevel@tonic-gate * We're almost done; all we need to do is sort the symbols 577*0Sstevel@tonic-gate * and then remove the duplicates. 578*0Sstevel@tonic-gate */ 579*0Sstevel@tonic-gate qsort(l_nl, (size_t)l_nname, sizeof (nltype), 580*0Sstevel@tonic-gate (int(*)(const void *, const void *)) compare); 581*0Sstevel@tonic-gate remove_dup_syms(l_nl, &l_nname); 582*0Sstevel@tonic-gate 583*0Sstevel@tonic-gate module->nl = l_nl; 584*0Sstevel@tonic-gate module->npe = l_npe; 585*0Sstevel@tonic-gate module->nname = l_nname; 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate total_names += l_nname; 588*0Sstevel@tonic-gate } 589