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