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