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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 33 /* ------------------------------------------------------------------------ */ 34 /* include headers */ 35 /* ------------------------------------------------------------------------ */ 36 37 #include "static_prof.h" 38 39 /* ========== elf_hash ==================================================== */ 40 /* 41 * DESCRIPTION: 42 * The hash function copied from libelf.so.1 43 */ 44 /* ======================================================================== */ 45 46 static unsigned long 47 my_elf_hash(const char *name) 48 { 49 unsigned long g, h = 0; 50 const unsigned char *nm = (unsigned char *) name; 51 52 while (*nm != '\0') { 53 h = (h << 4) + *nm++; 54 if ((g = h & MASK) != 0) 55 h ^= g >> 24; 56 h &= ~MASK; 57 } 58 return (h); 59 } 60 61 /* ========== output_dtneeded ============================================= */ 62 /* 63 * DESCRIPTION: 64 * Outputs all the dt_needed entries if any. 65 */ 66 /* ======================================================================== */ 67 68 static void 69 output_dtneeded(dt_list * list) 70 { 71 72 dt_list *p = list; 73 74 (void) fprintf(OUTPUT_FD, "#dtneeded:"); 75 if (!p) { 76 (void) fprintf(OUTPUT_FD, "\n"); 77 return; 78 } else { 79 while (p != NULL) { 80 (void) fprintf(OUTPUT_FD, 81 " %s", 82 p->libname); 83 p = p->next; 84 } 85 (void) fprintf(OUTPUT_FD, "\n"); 86 } 87 } 88 89 /* ========== store_binding =============================================== */ 90 /* 91 * DESCRIPTION: 92 * Read in the symbol binding information from the symbol table and 93 * store them into the hash table of buckets. 94 */ 95 /* ======================================================================== */ 96 97 static void 98 store_binding(binding_bucket * bind) 99 { 100 unsigned long bktno; 101 unsigned long orig_bktno; 102 int table_full = FALSE; 103 int i; 104 105 bktno = my_elf_hash(bind->sym) % DEFBKTS; 106 orig_bktno = bktno; 107 108 if (!bkts[bktno].sym) { 109 bkts[bktno].sym = bind->sym; 110 bkts[bktno].obj = bind->obj; 111 bkts[bktno].ref_lib = bind->ref_lib; 112 bkts[bktno].def_lib = bind->def_lib; 113 bkts[bktno].section = bind->section; 114 bkts[bktno].stbind = bind->stbind; 115 bkts[bktno].sttype = bind->sttype; 116 } else { 117 bktno = (bktno + 1) % DEFBKTS; 118 for (i = bktno; i < DEFBKTS; i = (i + 1) % DEFBKTS) { 119 if (i == orig_bktno) { 120 table_full = TRUE; 121 exit(1); 122 } 123 if (!bkts[i].sym) 124 break; 125 } 126 if ((!bkts[i].sym) && (table_full != TRUE)) { 127 bkts[i].sym = bind->sym; 128 bkts[i].obj = bind->obj; 129 bkts[i].ref_lib = bind->ref_lib; 130 bkts[i].def_lib = bind->def_lib; 131 bkts[i].section = bind->section; 132 bkts[i].stbind = bind->stbind; 133 bkts[i].sttype = bind->sttype; 134 } 135 } 136 } 137 138 /* ========== check_store_binding ========================================= */ 139 /* 140 * DESCRIPTION: 141 * Check what's already on the hash table with the new symbol binding 142 * information from the dependencies and record it into the bucket. 143 */ 144 /* ======================================================================== */ 145 146 static void 147 check_store_binding(binding_bucket * bind) 148 { 149 unsigned long bktno; 150 unsigned long orig_bktno; 151 unsigned long i; 152 153 bktno = my_elf_hash(bind->sym) % DEFBKTS; 154 orig_bktno = bktno; 155 156 if (!bkts[bktno].sym) 157 return; 158 if (bkts[bktno].sym && (strcmp(bkts[bktno].sym, bind->sym)) == 0) { 159 if (strcmp(bkts[bktno].ref_lib, "<Unknown>") == 0) 160 if (strcmp(bkts[bktno].obj, bind->obj)) 161 bkts[bktno].ref_lib = bind->obj; 162 } else { 163 bktno = (bktno + 1) % DEFBKTS; 164 for (i = bktno; i < DEFBKTS; i = (i + 1) % DEFBKTS) { 165 if (i == orig_bktno) 166 break; 167 if (!bkts[i].sym) 168 continue; 169 if (bkts[i].sym && 170 (strcmp(bkts[i].sym, bind->sym)) == 0) { 171 if (strcmp(bkts[i].ref_lib, "<Unknown>") == 0) 172 if (strcmp(bkts[i].obj, bind->obj)) 173 bkts[i].ref_lib = bind->obj; 174 break; 175 } 176 } 177 } 178 } 179 180 /* ========== stringcompare =============================================== */ 181 /* 182 * DESCRIPTION: 183 * Compares two strings for qsort(). 184 */ 185 /* ======================================================================== */ 186 187 static int 188 stringcompare(binding_bucket * a, 189 binding_bucket * b) 190 { 191 char *x = "\0"; 192 char *y = "\0"; 193 int retcode; 194 195 if (a->sym) 196 x = a->sym; 197 198 if (b->sym) 199 y = b->sym; 200 201 retcode = strcoll(x, y); 202 return (retcode); 203 } 204 205 /* ========== profile_binding ============================================= */ 206 /* 207 * DESCRIPTION: 208 * Output the bindings directly to stdout or a file. 209 */ 210 /* ======================================================================== */ 211 212 static void 213 profile_binding(binding_bucket * bind) 214 { 215 char *ref_lib_ptr; 216 217 if (bind->sym && strcmp(bind->ref_lib, "<Unknown>")) { 218 if (ref_lib_ptr = strrchr(bind->ref_lib, (int)'/')) { 219 ref_lib_ptr++; 220 if (bind->stbind) 221 (void) fprintf(OUTPUT_FD, 222 "%s|%s|%s|%s|%s|%s|%s\n", 223 ref_lib_ptr, 224 bind->section, 225 bind->stbind, 226 bind->sttype, 227 bind->sym, 228 bind->def_lib, 229 bind->obj); 230 } else if (bind->stbind) 231 (void) fprintf(OUTPUT_FD, 232 "%s|%s|%s|%s|%s|%s|%s\n", 233 bind->ref_lib, 234 bind->section, 235 bind->stbind, 236 bind->sttype, 237 bind->sym, 238 bind->def_lib, 239 bind->obj); 240 } else if (bind->sym && bind->stbind) 241 (void) fprintf(OUTPUT_FD, 242 "%s|%s|%s|%s|%s\n", 243 bind->obj, 244 bind->section, 245 bind->stbind, 246 bind->sttype, 247 bind->sym); 248 } 249 250 /* ========== output_binding ============================================== */ 251 /* 252 * DESCRIPTION: 253 * Output the hash table to either stdout or a file. 254 */ 255 /* ======================================================================== */ 256 257 static void 258 output_binding(char *prog_name, 259 char *target) 260 { 261 int i; 262 char *ref_lib_ptr; 263 264 qsort(bkts, 265 DEFBKTS, 266 sizeof (binding_bucket), 267 (int (*) (const void *, const void *)) stringcompare); 268 269 if (oflag) { 270 if ((OUTPUT_FD = fopen(outputfile, "w")) == NULL) { 271 if (sflag) 272 (void) fprintf(stderr, 273 "\nfopen failed to open <%s>...\n\n", 274 outputfile); 275 exit(1); 276 } 277 } 278 /* generates profile report */ 279 (void) fprintf(OUTPUT_FD, 280 "#generated by %s\n", 281 prog_name); 282 (void) fprintf(OUTPUT_FD, 283 "#profiling symbols in .text section of %s\n", 284 target); 285 output_dtneeded(dt_needed); 286 287 for (i = 0; i < DEFBKTS; i++) { 288 if (bkts[i].sym && strcmp(bkts[i].ref_lib, "<Unknown>")) { 289 if (ref_lib_ptr = strrchr(bkts[i].ref_lib, (int)'/')) { 290 ref_lib_ptr++; 291 if (bkts[i].stbind) 292 (void) fprintf(OUTPUT_FD, 293 "%s|%s|%s|%s|%s|%s|%s\n", 294 ref_lib_ptr, 295 bkts[i].section, 296 bkts[i].stbind, 297 bkts[i].sttype, 298 bkts[i].sym, 299 bkts[i].def_lib, 300 bkts[i].obj); 301 } else if (bkts[i].stbind) 302 (void) fprintf(OUTPUT_FD, 303 "%s|%s|%s|%s|%s|%s|%s\n", 304 bkts[i].ref_lib, 305 bkts[i].section, 306 bkts[i].stbind, 307 bkts[i].sttype, 308 bkts[i].sym, 309 bkts[i].def_lib, 310 bkts[i].obj); 311 } else if (bkts[i].sym && bkts[i].stbind) 312 (void) fprintf(OUTPUT_FD, 313 "%s|%s|%s|%s|%s\n", 314 bkts[i].obj, 315 bkts[i].section, 316 bkts[i].stbind, 317 bkts[i].sttype, 318 bkts[i].sym); 319 } 320 } 321 322 /* ========== obj_init ==================================================== */ 323 /* 324 * DESCRIPTION: 325 * Open (object) file, get ELF descriptor, and verify that the file is 326 * an ELF file. 327 */ 328 /* ======================================================================== */ 329 330 static int 331 obj_init(obj_list * c) 332 { 333 int mode = O_RDONLY; 334 335 /* open the file */ 336 if ((c->obj->fd = open(c->obj->ename, mode)) < 0) { 337 if (sflag) { 338 if (errno == ENOENT) 339 (void) fprintf(stderr, 340 "Cannot open <<%s>> : \ 341 No such file or directory.\n", 342 c->obj->ename); 343 else if (errno == EMFILE) 344 (void) fprintf(stderr, 345 "File <<%s>> : Already opened.\n", 346 c->obj->ename); 347 } 348 c->obj->fd = NULL; 349 return (FAIL); 350 } 351 /* 352 * queries the ELF library's internal version. 353 * Passing ver equal to EV_NONE causes elf_version() to return 354 * the library's internal version, without altering the working 355 * version. If ver is a version known to the library, 356 * elf_version() returns the previous or initial working 357 * version number. Otherwise, the working version remains 358 * unchanged and elf_version() returns EV_NONE. 359 */ 360 361 /* check if libelf.so is at the right level */ 362 if (elf_version(EV_CURRENT) == EV_NONE) { 363 if (sflag) 364 (void) fprintf(stderr, 365 "Library out of date in ELF access routines.\n"); 366 return (FAIL); 367 } 368 /* 369 * Before the first call to elf_begin(), it must call 370 * elf_version() to coordinate versions. 371 */ 372 373 /* 374 * get elf descriptor just to examine the contents of an existing 375 * file 376 */ 377 if ((c->obj->elf = elf_begin(c->obj->fd, ELF_C_READ, (Elf *) 0)) 378 == (Elf *) 0) { 379 if (sflag) 380 (void) fprintf(stderr, 381 "File is not in executable and \ 382 linking format(ELF).\n"); 383 return (FAIL); 384 } 385 /* Rule out COFF, a.out and shell script files */ 386 if (elf_kind(c->obj->elf) == ELF_K_COFF) { 387 if (sflag) { 388 (void) fprintf(stderr, 389 "File is not in executable \ 390 and linking format(ELF) or archive.\n"); 391 } 392 return (FAIL); 393 } 394 if (elf_kind(c->obj->elf) != ELF_K_AR && 395 elf_kind(c->obj->elf) != ELF_K_ELF) { 396 if (sflag) { 397 (void) fprintf(stderr, 398 "File is not in executable and linking \ 399 format(ELF) or archive.\n"); 400 } 401 return (FAIL); 402 } 403 return (SUCCEED); 404 } 405 406 /* ========== obj_elf_hdr ================================================= */ 407 /* 408 * DESCRIPTION: 409 * Obtain the elf header, verify elf header information 410 */ 411 /* ======================================================================== */ 412 413 static int 414 obj_elf_hdr(obj_list * c) 415 { 416 #if defined(_LP64) 417 Elf64_Ehdr *ptr; 418 #else 419 Elf32_Ehdr *ptr; 420 #endif 421 422 /* 423 * get the elf header if one is available for the ELF descriptor 424 * c->elf 425 */ 426 #if defined(_LP64) 427 if ((ptr = elf64_getehdr(c->obj->elf)) == (Elf64_Ehdr *) 0) { 428 if (sflag) 429 (void) fprintf(stderr, 430 "File is not in 64-bit format.\n"); 431 return (FAIL); 432 } 433 #else 434 if ((ptr = elf32_getehdr(c->obj->elf)) == (Elf32_Ehdr *) 0) { 435 if (sflag) 436 (void) fprintf(stderr, 437 "File is not in 32-bit format.\n"); 438 return (FAIL); 439 } 440 #endif 441 442 /* if there is elf header, save the pointer */ 443 #if defined(_LP64) 444 c->obj->ehdr = (Elf64_Ehdr *) ptr; 445 #else 446 c->obj->ehdr = (Elf32_Ehdr *) ptr; 447 #endif 448 449 /* e_ident[] is identification index which holds values */ 450 /* 451 * we could also use elf_getident() to retrieve file identification 452 * data. 453 */ 454 455 /* 456 * e_ident[EI_CLASS] identifies the file's class: 457 * ELFCLASSNONE - invalid class 458 * ELFCLASS32 - 32-bit objects 459 * ELFCLASS64 - 64-bit objects 460 */ 461 462 #if defined(_LP64) 463 if (ptr->e_ident[EI_CLASS] != ELFCLASS64) { 464 if (sflag) 465 (void) fprintf(stderr, 466 "File is not in 64-bit format.\n"); 467 return (FAIL); 468 } 469 #else 470 if (ptr->e_ident[EI_CLASS] != ELFCLASS32) { 471 if (sflag) 472 (void) fprintf(stderr, 473 "File is not in 32-bit format.\n"); 474 return (FAIL); 475 } 476 #endif 477 /* 478 * e_ident[EI_DATA] specifies the data encoding of the 479 * processor-specific data in the object file: 480 * ELFDATANONE - invalid data encoding 481 * ELFDATA2LSB - specifies 2's complement values, with the least 482 * significant byte occupying the lowest address 483 * ELFDATA2MSB - specifies 2's complement values, with the most 484 * significant byte occupying the lowest address 485 */ 486 487 /* 488 * e_ident[EI_VERSION] specifies the ELF header version number. 489 * Currently, this value must be EV_CURRENT. 490 */ 491 492 if (!(ptr->e_ident[EI_VERSION] == EV_CURRENT) && 493 (ptr->e_version == EV_CURRENT)) { 494 if (sflag) 495 (void) fprintf(stderr, 496 "File is recorded in an \ 497 incompatible ELF version.\n"); 498 return (FAIL); 499 } 500 /* only interested in relocatable, shared object, or executable file */ 501 switch (ptr->e_type) { 502 case ET_REL: 503 case ET_EXEC: 504 case ET_DYN: 505 break; 506 default: 507 if (sflag) { 508 (void) fprintf(stderr, 509 "File is not relocatable, "); 510 (void) fprintf(stderr, 511 "executable, or shared object.\n"); 512 } 513 return (FAIL); 514 } 515 516 /* 517 * e_machine's value specifies the required architecture for an 518 * individual file 519 */ 520 521 #if defined(__sparcv9) 522 if (ptr->e_machine != EM_SPARCV9) { 523 if (sflag) 524 (void) fprintf(stderr, 525 "File is not for 64-bit \ 526 SPARC machine architecture.\n"); 527 return (FAIL); 528 } 529 #elif defined(__amd64) 530 if (ptr->e_machine != EM_AMD64) { 531 if (sflag) 532 (void) fprintf(stderr, 533 "File is not for 64-bit \ 534 amd64 machine architecture.\n"); 535 return (FAIL); 536 } 537 #elif defined(__i386) 538 if (ptr->e_machine != EM_386) { 539 if (sflag) 540 (void) fprintf(stderr, 541 "File is not for 32-bit \ 542 i386 machine architecture.\n"); 543 return (FAIL); 544 } 545 #else 546 if (ptr->e_machine != EM_SPARC) { 547 if (sflag) 548 (void) fprintf(stderr, 549 "File is not for 32-bit \ 550 SPARC machine architecture.\n"); 551 return (FAIL); 552 } 553 #endif 554 return (SUCCEED); 555 } 556 557 /* ========== obj_prog_hdr ============================================= */ 558 /* 559 * DESCRIPTION: 560 * For executable files and shared objects only, check if it has 561 * a program header table. 562 */ 563 /* ===================================================================== */ 564 565 static int 566 obj_prog_hdr(obj_list * c) 567 { 568 /* 569 * Assume: the elf header has already been read, and the file 570 * has already been determined to be 571 * executable, shared object, or relocatable 572 */ 573 574 /* 575 * Program headers are meaningful only for executable and shared 576 * object files. It is an array of structures, each describing a 577 * segment or other information needs to prepare the program for 578 * execution. 579 */ 580 581 /* skip if file is not executable or shared object */ 582 /* e_type == ET_REL meaning Relocatable file */ 583 if (c->obj->ehdr->e_type == ET_REL) 584 return (SUCCEED); 585 586 /* 587 * ehdr->e_phoff holds the program header table's file offset in 588 * bytes. 589 */ 590 /* If the file has no program header table, this member holds zero. */ 591 /* 592 * ehdr->e_phnum holds the number of entries in the program header 593 * table. 594 */ 595 /* 596 * If a file has no program header table, e_phnum holds the value 597 * zero. 598 */ 599 600 /* make sure there's a program header table */ 601 if ((c->obj->ehdr->e_phoff == 0) || 602 (c->obj->ehdr->e_phnum == 0)) { 603 if (sflag) 604 (void) fprintf(stderr, 605 "File has no program header table.\n"); 606 return (FAIL); 607 } 608 return (SUCCEED); 609 } 610 611 /* ========== find_dynamic_sect ========================================== */ 612 /* 613 * DESCRIPTION: 614 * Find the dynamic section. 615 */ 616 /* ======================================================================= */ 617 618 static int 619 find_dynamic_sect(obj_list * c) 620 { 621 #if defined(_LP64) 622 Elf64_Shdr *scurrent; /* temp 64 bit section pointer */ 623 #else 624 Elf32_Shdr *scurrent; /* temp 32 bit section pointer */ 625 #endif 626 Elf_Scn *scn; /* temp section header pointer */ 627 Elf_Data *ddata; /* temp data header pointer */ 628 size_t index; /* temp section header table index */ 629 630 c->obj->dynnames = NULL; /* init of dynamic string table ptr */ 631 c->obj->dynsect = NULL; /* init of dynamic section ptr */ 632 c->obj->ddata = NULL; /* init of dynamic strtab data ptr */ 633 634 /* only process executables and shared objects */ 635 if (c->obj->ehdr->e_type != ET_EXEC && c->obj->ehdr->e_type != ET_DYN) 636 return (SUCCEED); 637 638 if ((c->obj->ehdr->e_shoff == 0) || (c->obj->ehdr->e_shnum == 0)) { 639 /* there are no sections */ 640 return (SUCCEED); 641 } 642 /* search the section header table for dynamic section */ 643 644 /* start with null section; section index = 0 */ 645 scn = 0; 646 647 while ((scn = elf_nextscn(c->obj->elf, scn)) != 0) { 648 /* retrieve the section header */ 649 #if defined(_LP64) 650 scurrent = elf64_getshdr(scn); 651 #else 652 scurrent = elf32_getshdr(scn); 653 #endif 654 655 /* check for dynamic section; (i.e., .dynamic) */ 656 if (scurrent->sh_type == SHT_DYNAMIC) { 657 ddata = 0; 658 if ((ddata = elf_getdata(scn, ddata)) == 0 || 659 (ddata->d_size == 0)) 660 return (SUCCEED); 661 662 /* now, we got data of dynamic section */ 663 c->obj->dynsect = ddata->d_buf; 664 665 /* index to section header for dynamic string table */ 666 index = scurrent->sh_link; 667 /* get scn descriptor of dynamic string table */ 668 scn = elf_getscn(c->obj->elf, index); 669 /* get dynamic string table section header */ 670 #if defined(_LP64) 671 scurrent = elf64_getshdr(scn); 672 #else 673 scurrent = elf32_getshdr(scn); 674 #endif 675 /* get the dynamic string table data descriptor */ 676 c->obj->ddata = elf_getdata(scn, (c->obj->ddata)); 677 /* save the pointer to dynamic string table data */ 678 c->obj->dynnames = c->obj->ddata->d_buf; 679 /* 680 * now, we got dynamic strtab and dynamic section 681 * information 682 */ 683 break; 684 } 685 } 686 return (SUCCEED); 687 } 688 689 /* ========== find_symtabs ================================================ */ 690 /* 691 * DESCRIPTION: 692 * Find and check symbol tables for an application file 693 */ 694 /* ======================================================================== */ 695 696 static int 697 find_symtabs(obj_list * c) 698 { 699 #if defined(_LP64) 700 Elf64_Shdr *shdr; 701 #else 702 Elf32_Shdr *shdr; 703 #endif 704 Elf_Scn *scn, *scn2; 705 Elf_Data *data; 706 707 c->obj->sym_tab = NULL; 708 c->obj->sym_num = 0; 709 c->obj->sym_names = NULL; 710 c->obj->dsym_tab = NULL; 711 c->obj->dsym_num = 0; 712 c->obj->dsym_names = NULL; 713 c->obj->sym_data = NULL; 714 c->obj->dsym_data = NULL; 715 scn = 0; 716 717 /* 718 * loop through the section header table looking for symbol tables. 719 * There must be one or two: .symtab and .dynsym 720 * upon finding a symbol table, save its pointer in obj_com. 721 */ 722 723 /* get section descriptor */ 724 while ((scn = elf_nextscn(c->obj->elf, scn)) != 0) { 725 #if defined(_LP64) 726 Elf64_Sym *syms; 727 #else 728 Elf32_Sym *syms; 729 #endif 730 int symn; 731 char *strs; 732 733 /* point to section header */ 734 #if defined(_LP64) 735 shdr = elf64_getshdr(scn); 736 #else 737 shdr = elf32_getshdr(scn); 738 #endif 739 740 if (shdr == 0) 741 return (FAIL); 742 743 /* skip if this section is not a symbol table */ 744 if ((shdr->sh_type != SHT_DYNSYM) && 745 (shdr->sh_type != SHT_SYMTAB)) 746 continue; 747 748 /* get data descriptor for the symbol table itself */ 749 data = elf_getdata(scn, NULL); 750 if (data == NULL) 751 continue; 752 753 /* save pointer to symbol table */ 754 #if defined(_LP64) 755 syms = (Elf64_Sym *) data->d_buf; 756 #else 757 syms = (Elf32_Sym *) data->d_buf; 758 #endif 759 760 /* 761 * now start looking for the string table associated with 762 * this symbol table section 763 */ 764 765 /* get section descriptor first */ 766 scn2 = elf_getscn(c->obj->elf, shdr->sh_link); 767 if (scn2 == NULL) 768 continue; 769 770 /* get data descriptor for the string table section */ 771 data = elf_getdata(scn2, NULL); 772 if (data == NULL) 773 continue; 774 775 /* save pointer to name string table */ 776 strs = data->d_buf; 777 symn = shdr->sh_size / shdr->sh_entsize; 778 779 /* save information in obj_com */ 780 if (shdr->sh_type == SHT_SYMTAB) { 781 c->obj->sym_tab = syms; 782 c->obj->sym_num = symn; 783 c->obj->sym_names = strs; 784 c->obj->sym_data = data; 785 } else { /* must be the dynamic linking symbol table */ 786 c->obj->dsym_tab = syms; 787 c->obj->dsym_num = symn; 788 c->obj->dsym_names = strs; 789 c->obj->dsym_data = data; 790 } /* end if */ 791 } /* end while */ 792 return (SUCCEED); 793 } 794 795 /* ========== obj_app_symtab ============================================== */ 796 /* 797 * DESCRIPTION: 798 * Check existence of application's symbol tables. 799 */ 800 /* ======================================================================== */ 801 802 static int 803 obj_app_symtab(obj_list * c) 804 { 805 /* issue error if a relocatable file has no symbol table */ 806 if (c->obj->sym_tab == NULL) { 807 if (c->obj->ehdr->e_type == ET_REL) { 808 if (sflag) 809 (void) fprintf(stderr, 810 "ELF error: no symbol \ 811 table in object file.\n"); 812 return (FAIL); 813 } else { 814 if (c->obj->dsym_tab == NULL) { 815 if (sflag) { 816 (void) fprintf(stderr, 817 "Warning: Binary is \ 818 completely statically \ 819 linked and stripped.\n"); 820 } 821 return (FAIL); 822 } 823 if (sflag) 824 (void) fprintf(stderr, 825 "Binary is stripped.\n"); 826 } 827 } 828 return (SUCCEED); 829 } 830 831 /* ========== obj_finis =================================================== */ 832 /* 833 * DESCRIPTION: 834 * It checks the c->fd and c->elf pointers. If they are not NULL, 835 * close the file descriptor and ELF descriptor. 836 */ 837 /* ======================================================================== */ 838 839 static void 840 obj_finis(obj_list * c) 841 { 842 obj_list *p; 843 844 if (c) { 845 while (c) { 846 if (c->obj->elf != (Elf *) 0) 847 (void) elf_end(c->obj->elf); 848 if (c->obj->fd != 0) 849 (void) close(c->obj->fd); 850 p = c; 851 c = c->next; 852 free(p->obj); 853 free(p); 854 } 855 } 856 } 857 858 /* ========= is_text_section ============================================== */ 859 /* 860 * DESCRIPTION: 861 * Scan through every section and returns TRUE(1) if the given section 862 * is ".text", otherwise, returns FALSE(0). 863 * INPUTS: shndx - section header index 864 * elf_file - ELF descriptor of the object file under test 865 * ehdr - ELF header of the object file under test 866 */ 867 /* ======================================================================== */ 868 869 static int 870 is_text_section(int shndx, 871 Elf * elf_file, 872 #if defined(_LP64) 873 Elf64_Ehdr * ehdr) 874 #else 875 Elf32_Ehdr * ehdr) 876 #endif 877 { 878 char *sym_name; 879 Elf_Scn *scn = elf_getscn(elf_file, shndx); 880 881 if (scn != NULL) { 882 #if defined(_LP64) 883 Elf64_Shdr *shdr; 884 shdr = elf64_getshdr(scn); 885 #else 886 Elf32_Shdr *shdr; 887 shdr = elf32_getshdr(scn); 888 #endif 889 sym_name = elf_strptr(elf_file, 890 ehdr->e_shstrndx, 891 shdr->sh_name); 892 if (strcmp(sym_name, ".text") == 0) 893 return (1); 894 } 895 return (0); 896 } 897 898 /* ========== scan_archive_symbols ======================================= */ 899 /* 900 * DESCRIPTION: 901 * Scan through the archive symbol tables and write them out. 902 * INPUTS: syms - pointer to application symbol table 903 * symn - number of entries in application symbol table 904 * buf - first byte of application string table 905 */ 906 /* ======================================================================= */ 907 908 static void 909 scan_archive_symbols(obj_list * c, 910 #if defined(_LP64) 911 Elf64_Sym * syms, 912 #else 913 Elf32_Sym * syms, 914 #endif 915 int symn, 916 char *buf, 917 Elf * elf_file, 918 #if defined(_LP64) 919 Elf64_Ehdr * ehdr) 920 #else 921 Elf32_Ehdr * ehdr) 922 #endif 923 { 924 #if defined(_LP64) 925 Elf64_Sym *symtab_entry; 926 #else 927 Elf32_Sym *symtab_entry; 928 #endif 929 int i; 930 char *sym_name; 931 int sttype; 932 int stbind; 933 934 symtab_entry = syms; 935 for (i = 0; i < symn; i++, symtab_entry++) { 936 binding_bucket *binding; 937 /* look only at .text section symbols */ 938 if (!is_text_section(symtab_entry->st_shndx, elf_file, ehdr)) 939 continue; 940 941 /* look only at weak and global symbols */ 942 #if defined(_LP64) 943 stbind = ELF64_ST_BIND(symtab_entry->st_info); 944 #else 945 stbind = ELF32_ST_BIND(symtab_entry->st_info); 946 #endif 947 if (stbind != STB_GLOBAL) { 948 if (stbind != STB_WEAK) 949 continue; 950 } 951 /* look only at functions and objects */ 952 #if defined(_LP64) 953 sttype = ELF64_ST_TYPE(symtab_entry->st_info); 954 #else 955 sttype = ELF32_ST_TYPE(symtab_entry->st_info); 956 #endif 957 if (sttype != STT_FUNC) { 958 if (sttype != STT_OBJECT) 959 continue; 960 } 961 sym_name = buf + symtab_entry->st_name; 962 binding = (struct binding_bucket *) 963 malloc(sizeof (binding_bucket)); 964 binding->sym = sym_name; 965 binding->obj = c->obj->ename; 966 binding->section = "TEXT"; 967 binding->ref_lib = "<Unknown>"; 968 binding->def_lib = "*DIRECT*"; 969 if (stbind == STB_GLOBAL) 970 binding->stbind = "GLOB"; 971 else if (stbind == STB_WEAK) 972 binding->stbind = "WEAK"; 973 if (sttype == STT_FUNC) 974 binding->sttype = "FUNC"; 975 else if (sttype == STT_OBJECT) 976 binding->sttype = "OBJT"; 977 if (pflag) 978 profile_binding(binding); 979 else 980 store_binding(binding); 981 } /* end for */ 982 } 983 984 /* ========== scan_symbols ================================================ */ 985 /* 986 * DESCRIPTION: 987 * Scan through the symbol table and write them out. 988 * INPUTS: syms - pointer to application symbol table 989 * symn - number of entries in application symbol table 990 * buf - first byte of application string table 991 */ 992 /* ======================================================================== */ 993 994 static void 995 scan_symbols(obj_list * c, 996 #if defined(_LP64) 997 Elf64_Sym * syms, 998 #else 999 Elf32_Sym * syms, 1000 #endif 1001 int symn, 1002 char *buf) 1003 { 1004 #if defined(_LP64) 1005 Elf64_Sym *symtab_entry; 1006 #else 1007 Elf32_Sym *symtab_entry; 1008 #endif 1009 int i; 1010 char *sym_name; 1011 int sttype; 1012 int stbind; 1013 1014 symtab_entry = syms; 1015 if (pflag) { 1016 (void) fprintf(OUTPUT_FD, 1017 "#profiling symbols in .text section of %s\n", 1018 c->obj->ename); 1019 output_dtneeded(dt_needed); 1020 } 1021 for (i = 0; i < symn; i++, symtab_entry++) { 1022 binding_bucket *binding; 1023 /* look only at .text section symbols */ 1024 if (!is_text_section(symtab_entry->st_shndx, 1025 c->obj->elf, 1026 c->obj->ehdr)) 1027 continue; 1028 1029 /* look only at weak and global symbols */ 1030 #if defined(_LP64) 1031 stbind = ELF64_ST_BIND(symtab_entry->st_info); 1032 #else 1033 stbind = ELF32_ST_BIND(symtab_entry->st_info); 1034 #endif 1035 if (stbind != STB_GLOBAL) { 1036 if (stbind != STB_WEAK) 1037 continue; 1038 } 1039 /* look only at functions and objects */ 1040 #if defined(_LP64) 1041 sttype = ELF64_ST_TYPE(symtab_entry->st_info); 1042 #else 1043 sttype = ELF32_ST_TYPE(symtab_entry->st_info); 1044 #endif 1045 if (sttype != STT_FUNC) { 1046 if (sttype != STT_OBJECT) 1047 continue; 1048 } 1049 sym_name = buf + symtab_entry->st_name; 1050 binding = (struct binding_bucket *) 1051 malloc(sizeof (binding_bucket)); 1052 binding->sym = sym_name; 1053 binding->obj = c->obj->ename; 1054 binding->section = "TEXT"; 1055 binding->ref_lib = "<Unknown>"; 1056 binding->def_lib = "*DIRECT*"; 1057 if (stbind == STB_GLOBAL) 1058 binding->stbind = "GLOB"; 1059 else if (stbind == STB_WEAK) 1060 binding->stbind = "WEAK"; 1061 if (sttype == STT_FUNC) 1062 binding->sttype = "FUNC"; 1063 else if (sttype == STT_OBJECT) 1064 binding->sttype = "OBJT"; 1065 if (pflag) 1066 profile_binding(binding); 1067 else 1068 store_binding(binding); 1069 } /* end for */ 1070 } 1071 1072 /* ========= bind_symbols ================================================= */ 1073 /* 1074 * DESCRIPTION: 1075 * Scan through the dynamic symbol table and write them out. 1076 * INPUTS: syms - pointer to application symbol table 1077 * symn - number of entries in application symbol table 1078 * buf - first byte of application string table 1079 */ 1080 /* ======================================================================== */ 1081 1082 static void 1083 bind_symbols(obj_list * c, 1084 #if defined(_LP64) 1085 Elf64_Sym * syms, 1086 #else 1087 Elf32_Sym * syms, 1088 #endif 1089 int symn, 1090 char *buf) 1091 { 1092 #if defined(_LP64) 1093 Elf64_Sym *symtab_entry; 1094 #else 1095 Elf32_Sym *symtab_entry; 1096 #endif 1097 int i; 1098 char *sym_name; 1099 binding_bucket *binding; 1100 int sttype; 1101 int stbind; 1102 1103 symtab_entry = syms; 1104 for (i = 0; i < symn; i++, symtab_entry++) { 1105 /* look only at global symbols */ 1106 #if defined(_LP64) 1107 stbind = ELF64_ST_BIND(symtab_entry->st_info); 1108 #else 1109 stbind = ELF32_ST_BIND(symtab_entry->st_info); 1110 #endif 1111 if (symtab_entry->st_shndx == SHN_UNDEF) 1112 continue; 1113 if (symtab_entry->st_shndx == SHN_ABS) 1114 continue; 1115 if (stbind != STB_GLOBAL) { 1116 if (stbind != STB_WEAK) 1117 continue; 1118 } 1119 /* look only at functions and objects */ 1120 #if defined(_LP64) 1121 sttype = ELF64_ST_TYPE(symtab_entry->st_info); 1122 #else 1123 sttype = ELF32_ST_TYPE(symtab_entry->st_info); 1124 #endif 1125 if (sttype != STT_FUNC) { 1126 if (sttype != STT_OBJECT) 1127 continue; 1128 } 1129 sym_name = buf + symtab_entry->st_name; 1130 binding = (binding_bucket *) malloc(sizeof (binding_bucket)); 1131 binding->obj = c->obj->ename; 1132 binding->sym = sym_name; 1133 if (!pflag) 1134 check_store_binding(binding); 1135 } /* end for */ 1136 } 1137 1138 /* ========== get_scnfd =================================================== */ 1139 /* 1140 * DESCRIPTION: 1141 * Gets section descriptor for the associated string table 1142 * and verifies that the type of the section pointed to is 1143 * indeed of type STRTAB. Returns a valid section descriptor 1144 * or NULL on error. 1145 */ 1146 /* ======================================================================== */ 1147 1148 static Elf_Scn * 1149 get_scnfd(Elf * e_file, 1150 int shstrtab, 1151 int SCN_TYPE) 1152 { 1153 Elf_Scn *scn_fd; 1154 #if defined(_LP64) 1155 Elf64_Shdr *shdr; 1156 #else 1157 Elf32_Shdr *shdr; 1158 #endif 1159 1160 if ((scn_fd = elf_getscn(e_file, shstrtab)) == NULL) 1161 return (NULL); 1162 1163 #if defined(_LP64) 1164 shdr = elf64_getshdr(scn_fd); 1165 #else 1166 shdr = elf32_getshdr(scn_fd); 1167 #endif 1168 1169 if (shdr->sh_type != SCN_TYPE) 1170 return (NULL); 1171 return (scn_fd); 1172 } 1173 1174 /* ========== print_symtab ================================================ */ 1175 /* 1176 * DESCRIPTION: 1177 * Outputs symbol bindings from symbol table to hash table. 1178 */ 1179 /* ======================================================================== */ 1180 1181 static void 1182 print_symtab(obj_list * com, 1183 Elf * elf_file, 1184 #if defined(_LP64) 1185 Elf64_Ehdr * ehdr, 1186 Elf64_Shdr * shdr, 1187 #else 1188 Elf32_Ehdr * ehdr, 1189 Elf32_Shdr * shdr, 1190 #endif 1191 Elf_Scn * p_sd, 1192 char *filename) 1193 { 1194 #if defined(_LP64) 1195 Elf64_Sym *syms; 1196 #else 1197 Elf32_Sym *syms; 1198 #endif 1199 Elf_Data *data; 1200 Elf_Scn *scn; 1201 int count = 0; 1202 char *strs, *fullname; 1203 obj_list *c; 1204 1205 c = (obj_list *) malloc(sizeof (obj_list)); 1206 c->obj = (obj_com *) malloc(sizeof (obj_com)); 1207 fullname = (char *)malloc(strlen(com->obj->ename) 1208 + strlen(filename) + 2); 1209 (void *) strcpy(fullname, com->obj->ename); 1210 (void *) strcat(fullname, "("); 1211 (void *) strcat(fullname, filename); 1212 (void *) strcat(fullname, ")"); 1213 c->obj->ename = fullname; 1214 1215 if ((data = elf_getdata(p_sd, NULL)) == NULL) { 1216 if (sflag) 1217 (void) fprintf(stderr, 1218 "%s - No symbol table data\n", 1219 c->obj->ename); 1220 return; 1221 } 1222 #if defined(_LP64) 1223 syms = (Elf64_Sym *) data->d_buf; 1224 #else 1225 syms = (Elf32_Sym *) data->d_buf; 1226 #endif 1227 1228 scn = elf_getscn(elf_file, shdr->sh_link); 1229 if (scn == NULL) 1230 return; 1231 data = elf_getdata(scn, NULL); 1232 if (data == NULL) 1233 return; 1234 strs = data->d_buf; 1235 count = shdr->sh_size / shdr->sh_entsize; 1236 if (syms == NULL) { 1237 if (sflag) 1238 (void) fprintf(stderr, 1239 "%s: Problem reading symbol data\n", 1240 c->obj->ename); 1241 return; 1242 } 1243 c->obj->sym_tab = syms; 1244 c->obj->sym_num = count; 1245 c->obj->sym_names = strs; 1246 1247 if (aflag) 1248 (void) scan_archive_symbols(c, 1249 c->obj->sym_tab, 1250 c->obj->sym_num, 1251 c->obj->sym_names, 1252 elf_file, 1253 ehdr); 1254 else 1255 (void) bind_symbols(c, 1256 c->obj->sym_tab, 1257 c->obj->sym_num, 1258 c->obj->sym_names); 1259 free(c->obj); 1260 free(c); 1261 } 1262 1263 /* ========== get_symtab ================================================== */ 1264 /* 1265 * DESCRIPTION: 1266 * Gets the symbol table. This function does not output the contents 1267 * of the symbol table but sets up the parameters and then calls 1268 * print_symtab() to output the symbol bindings. 1269 */ 1270 /* ======================================================================== */ 1271 1272 static void 1273 get_symtab(obj_list * c, 1274 Elf * elf_file, 1275 #if defined(_LP64) 1276 Elf64_Ehdr * ehdr, 1277 #else 1278 Elf32_Ehdr * ehdr, 1279 #endif 1280 char *filename) 1281 { 1282 Elf_Scn *scn, *scnfd; 1283 Elf_Data *data; 1284 #if defined(_LP64) 1285 Elf64_Word symtabtype; 1286 #else 1287 Elf32_Word symtabtype; 1288 #endif 1289 1290 /* get section header string table */ 1291 scnfd = get_scnfd(elf_file, ehdr->e_shstrndx, SHT_STRTAB); 1292 if (scnfd == NULL) { 1293 if (sflag) 1294 (void) fprintf(stderr, 1295 "%s: Could not get string table\n", 1296 filename); 1297 return; 1298 } 1299 data = elf_getdata(scnfd, NULL); 1300 if (data->d_size == 0) { 1301 if (sflag) 1302 (void) fprintf(stderr, 1303 "%s: No data in string table\n", 1304 filename); 1305 return; 1306 } 1307 symtabtype = SHT_SYMTAB; 1308 scn = 0; 1309 while ((scn = elf_nextscn(elf_file, scn)) != 0) { 1310 #if defined(_LP64) 1311 Elf64_Shdr *shdr; 1312 if ((shdr = elf64_getshdr(scn)) == NULL) 1313 #else 1314 Elf32_Shdr *shdr; 1315 if ((shdr = elf32_getshdr(scn)) == NULL) 1316 #endif 1317 { 1318 if (sflag) 1319 (void) fprintf(stderr, 1320 "%s: %s:\n", 1321 filename, 1322 elf_errmsg(-1)); 1323 return; 1324 } 1325 if (shdr->sh_type == symtabtype) 1326 print_symtab(c, elf_file, ehdr, shdr, scn, filename); 1327 } /* end while */ 1328 } 1329 1330 /* ========== process ===================================================== */ 1331 /* 1332 * DESCRIPTION: 1333 * Gets the ELF header and, if it exists, call get_symtab() to begin 1334 * processing of the file; otherwise, returns with a warning. 1335 */ 1336 /* ======================================================================== */ 1337 1338 static void 1339 process(obj_list * c, 1340 Elf * elf_file, 1341 char *filename) 1342 { 1343 #if defined(_LP64) 1344 Elf64_Ehdr *ehdr; 1345 #else 1346 Elf32_Ehdr *ehdr; 1347 #endif 1348 1349 #if defined(_LP64) 1350 if ((ehdr = elf64_getehdr(elf_file)) == NULL) 1351 #else 1352 if ((ehdr = elf32_getehdr(elf_file)) == NULL) 1353 #endif 1354 { 1355 if (sflag) 1356 (void) fprintf(stderr, 1357 "%s: %s\n", 1358 filename, elf_errmsg(-1)); 1359 return; 1360 } 1361 get_symtab(c, elf_file, ehdr, filename); 1362 } 1363 1364 /* ========== process_archive ============================================= */ 1365 /* 1366 * DESCRIPTION: 1367 * Processes member files of an archive. This function provides 1368 * a loop through an archive equivalent the processing of each_file 1369 * for individual object file. 1370 */ 1371 /* ======================================================================== */ 1372 1373 static int 1374 process_archive(obj_list * c) 1375 { 1376 Elf_Arhdr *p_ar; 1377 Elf *arf; 1378 Elf_Cmd cmd = ELF_C_READ; 1379 1380 while ((arf = elf_begin(c->obj->fd, cmd, c->obj->elf)) != 0) { 1381 p_ar = elf_getarhdr(arf); 1382 if (p_ar == NULL) { 1383 if (sflag) 1384 (void) fprintf(stderr, 1385 "%s: %s\n", 1386 c->obj->filename, elf_errmsg(-1)); 1387 return (FAIL); 1388 } 1389 if ((int)strncmp(p_ar->ar_name, "/", 1) == 0) { 1390 cmd = elf_next(arf); 1391 (void) elf_end(arf); 1392 continue; 1393 } 1394 if (elf_kind(arf) == ELF_K_ELF) { 1395 process(c, arf, p_ar->ar_name); 1396 } else { 1397 cmd = elf_next(arf); 1398 (void) elf_end(arf); 1399 continue; 1400 } 1401 cmd = elf_next(arf); 1402 (void) elf_end(arf); 1403 } /* end while */ 1404 return (SUCCEED); 1405 } 1406 1407 /* ========== add_dtneeded ================================================ */ 1408 /* 1409 * DESCRIPTION: 1410 * Inserts a new node into the linked list. It is basically for 1411 * generating a simple linked list of DT_NEEDED entries. 1412 */ 1413 /* ======================================================================== */ 1414 1415 static dt_list * 1416 add_dtneeded(dt_list * p, 1417 dt_list * node) 1418 { 1419 dt_list *head = p, *tail; 1420 1421 if (!head) 1422 head = node; 1423 else { 1424 tail = head; 1425 if (strcmp(tail->libname, node->libname) == 0) { 1426 free(node); 1427 return (head); 1428 } 1429 while (tail->next != NULL) { 1430 tail = tail->next; 1431 if (strcmp(tail->libname, node->libname) == 0) { 1432 free(node); 1433 return (head); 1434 } 1435 } 1436 tail->next = node; 1437 } 1438 return (head); 1439 } 1440 1441 /* ========== find_dtneeded =============================================== */ 1442 /* 1443 * DESCRIPTION: 1444 * Find the DT_NEEDED, DT_FILTER, and DT_AUXILIARY entries, and save 1445 * them to link list. 1446 */ 1447 /* ======================================================================== */ 1448 1449 static void 1450 find_dtneeded(obj_list * c) 1451 { 1452 #if defined(_LP64) 1453 Elf64_Dyn *dcurrent; /* temp 64 bit dynamic table entry ptr */ 1454 #else 1455 Elf32_Dyn *dcurrent; /* temp 32 bit dynamic table entry ptr */ 1456 #endif 1457 dt_list *tmp_lib; 1458 1459 dcurrent = c->obj->dynsect; 1460 if (!dcurrent) 1461 return; 1462 1463 /* 1464 * If there are any DT_NEEDED 1465 * entries, add them to the dt_needed list. 1466 */ 1467 1468 while (dcurrent->d_tag != DT_NULL) { 1469 if (dcurrent->d_tag == DT_NEEDED) { 1470 tmp_lib = (dt_list *) malloc(sizeof (dt_list)); 1471 tmp_lib->libname = c->obj->dynnames + 1472 dcurrent->d_un.d_val; 1473 tmp_lib->d_tag = dcurrent->d_tag; 1474 tmp_lib->next = NULL; 1475 dt_needed = add_dtneeded(dt_needed, tmp_lib); 1476 } 1477 dcurrent++; 1478 } 1479 } 1480 1481 /* ========= obj_elfcheck ================================================= */ 1482 /* 1483 * DESCRIPTION: 1484 * It checks the elf header and saves its pointer if succeeds. 1485 * It checks the program header and saves its pointer if succeed. 1486 * It checks the section header table and saves its pointer to 1487 * section header table and section header string table if it 1488 * succeeds. It finds dynsym symbol table and saves its pointer. 1489 * It finds symtab and saves its pointers. 1490 */ 1491 /* ======================================================================== */ 1492 1493 static int 1494 obj_elfcheck(obj_list * c) 1495 { 1496 /* open the file and ELF descriptor */ 1497 if (obj_init(c) == FAIL) { 1498 obj_finis(c); 1499 return (FAIL); 1500 } 1501 /* if it is an archive library */ 1502 if (elf_kind(c->obj->elf) == ELF_K_AR) { 1503 if (process_archive(c) == SUCCEED) 1504 return (SUCCEED); 1505 else 1506 return (FAIL); 1507 } 1508 /* get the ELF header information */ 1509 if (obj_elf_hdr(c) == FAIL) { 1510 obj_finis(c); 1511 return (FAIL); 1512 } 1513 /* get the program header for dynamic, etc. */ 1514 if (obj_prog_hdr(c) == FAIL) { 1515 obj_finis(c); 1516 return (FAIL); 1517 } 1518 /* find and save pointers to application symbol tables */ 1519 if (find_symtabs(c) == FAIL) { 1520 obj_finis(c); 1521 return (FAIL); 1522 } 1523 /* check the existence of application's symbol tables */ 1524 if (obj_app_symtab(c) == FAIL) { 1525 obj_finis(c); 1526 return (FAIL); 1527 } 1528 /* find and save pointers to the dynamic section */ 1529 if (find_dynamic_sect(c) == FAIL) { 1530 obj_finis(c); 1531 return (FAIL); 1532 } 1533 /* 1534 * find the DT_NEEDED entries and save the name to dt_needed link 1535 * list 1536 */ 1537 (void) find_dtneeded(c); 1538 1539 return (SUCCEED); 1540 } 1541 1542 /* ========= analyze_dependency ========================================== */ 1543 /* 1544 * DESCRIPTION: 1545 * Read in an dependency object file and analyze it. 1546 * INPUTS: dep_file - dependency object file name 1547 */ 1548 /* ======================================================================= */ 1549 1550 static int 1551 analyze_dependency(char *dep_file) 1552 { 1553 obj_list *dep_obj; 1554 1555 if (!dep_file) 1556 return (SUCCEED); 1557 1558 dep_obj = (obj_list *) malloc(sizeof (obj_list)); 1559 (void) memset(dep_obj, 0, sizeof (obj_list)); 1560 dep_obj->obj = (obj_com *) malloc(sizeof (obj_com)); 1561 (void) memset(dep_obj->obj, 0, sizeof (obj_com)); 1562 dep_obj->next = NULL; 1563 dep_obj->obj->filename = dep_file; 1564 dep_obj->obj->ename = dep_obj->obj->filename; 1565 1566 if (obj_elfcheck(dep_obj) == FAIL) 1567 return (FAIL); 1568 1569 if (dep_obj->obj->dsym_names != NULL) 1570 bind_symbols(dep_obj, 1571 dep_obj->obj->dsym_tab, 1572 dep_obj->obj->dsym_num, 1573 dep_obj->obj->dsym_names); 1574 1575 if (dep_obj->obj->sym_names != NULL) 1576 bind_symbols(dep_obj, 1577 dep_obj->obj->sym_tab, 1578 dep_obj->obj->sym_num, 1579 dep_obj->obj->sym_names); 1580 return (SUCCEED); 1581 } 1582 1583 /* ========= analyze_main =============================================== */ 1584 /* 1585 * DESCRIPTION: 1586 * Read in an object file and analyze it. 1587 */ 1588 /* ====================================================================== */ 1589 1590 static void 1591 analyze_main(obj_list * c) 1592 { 1593 int i; 1594 1595 if (obj_elfcheck(c) == FAIL) 1596 exit(1); 1597 1598 aflag = FALSE; 1599 1600 if (c->obj->sym_names != NULL) 1601 scan_symbols(c, 1602 c->obj->sym_tab, 1603 c->obj->sym_num, 1604 c->obj->sym_names); 1605 else if (c->obj->dsym_names != NULL) 1606 scan_symbols(c, 1607 c->obj->dsym_tab, 1608 c->obj->dsym_num, 1609 c->obj->dsym_names); 1610 1611 if (c->obj->numfiles == 0) 1612 return; 1613 1614 for (i = 0; i < c->obj->numfiles; i++) 1615 (void) analyze_dependency(c->obj->filenames[i]); 1616 } 1617 1618 /* ========= analyze_args ================================================= */ 1619 /* 1620 * DESCRIPTION: 1621 * Analyze the command-line options. 1622 */ 1623 /* ======================================================================== */ 1624 1625 static int 1626 analyze_args(obj_list * c, 1627 int argc, 1628 char *argv[]) 1629 { 1630 extern char *optarg; 1631 extern int optind; 1632 int option; 1633 int i; 1634 char *nameptr; 1635 char slash = '/'; 1636 int errflg = 0; 1637 1638 if ((nameptr = strrchr(argv[0], slash)) != NULL) 1639 nameptr++; 1640 else 1641 nameptr = argv[0]; 1642 1643 while ((option = getopt(argc, argv, "pso:a")) != EOF) { 1644 switch (option) { 1645 case 'p': /* just do profiling; write to stdout */ 1646 pflag = 1; 1647 break; 1648 case 's': /* silent mode to turn off stderr messages */ 1649 sflag = 0; 1650 break; 1651 case 'o': /* redirects the output */ 1652 outputfile = optarg; 1653 oflag = 1; 1654 break; 1655 case 'a': /* processes archive as input */ 1656 aflag = 1; 1657 break; 1658 case '?': 1659 default: 1660 errflg++; 1661 } /* end switch */ 1662 } /* end while */ 1663 1664 /* exit if there are no files to process */ 1665 if (optind >= argc) 1666 errflg++; 1667 if (errflg) { 1668 (void) fprintf(stderr, 1669 "usage: %s [-p] [-s] [-o outputfile] ", nameptr); 1670 (void) fprintf(stderr, 1671 "<archive>|<binary_executable>\n"); 1672 (void) fprintf(stderr, 1673 "\t\t [<archive>|<dynamic library>...]\n"); 1674 return (FALSE); 1675 } /* end if */ 1676 c->obj->filename = argv[optind++]; 1677 c->obj->ename = c->obj->filename; 1678 1679 /* compute number of files and save their pointers */ 1680 c->obj->numfiles = argc - optind; 1681 1682 if (c->obj->numfiles > 0) { 1683 i = 0; 1684 c->obj->filenames = (char **) 1685 malloc(sizeof (char *) * 1686 (c->obj->numfiles + 1)); 1687 for (; optind < argc; i++, optind++) 1688 c->obj->filenames[i] = argv[optind]; 1689 } 1690 return (TRUE); 1691 } 1692 1693 /* ======================================================================= */ 1694 /* 1695 * Here starts the main () 1696 */ 1697 /* ======================================================================= */ 1698 1699 void 1700 main(int argc, 1701 char **argv) 1702 { 1703 obj_list *main_obj; 1704 dt_list *q; 1705 1706 main_obj = (obj_list *) malloc(sizeof (obj_list)); 1707 (void) memset(main_obj, 0, sizeof (obj_list)); 1708 main_obj->obj = (obj_com *) malloc(sizeof (obj_com)); 1709 (void) memset(main_obj->obj, 0, sizeof (obj_com)); 1710 main_obj->next = NULL; 1711 1712 if (!analyze_args(main_obj, argc, argv)) 1713 exit(1); 1714 1715 if (oflag && pflag) { 1716 if ((OUTPUT_FD = fopen(outputfile, "w")) == NULL) { 1717 if (sflag) 1718 (void) fprintf(stderr, 1719 "\nfopen failed to open <%s>...\n\n", 1720 outputfile); 1721 exit(1); 1722 } 1723 } 1724 /* generates profile report if pflag is set */ 1725 if (pflag) 1726 (void) fprintf(OUTPUT_FD, 1727 "#generated by %s\n", 1728 argv[0]); 1729 1730 /* analyze the input file */ 1731 analyze_main(main_obj); 1732 1733 /* generates profile report */ 1734 if (!pflag) 1735 output_binding(argv[0], main_obj->obj->ename); 1736 1737 /* close the library .so file descriptor and ELF descriptor */ 1738 obj_finis(main_obj); 1739 1740 /* de-allocates the dt_needed link list */ 1741 if (dt_needed) { 1742 while (dt_needed) { 1743 q = dt_needed; 1744 dt_needed = dt_needed->next; 1745 free(q); 1746 } 1747 } 1748 /* close the output redirect file descriptor */ 1749 if (oflag) 1750 (void) fclose(OUTPUT_FD); 1751 1752 exit(0); 1753 } 1754