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