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
my_elf_hash(const char * name)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
output_dtneeded(dt_list * list)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
store_binding(binding_bucket * bind)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
check_store_binding(binding_bucket * bind)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
stringcompare(binding_bucket * a,binding_bucket * b)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
profile_binding(binding_bucket * bind)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
output_binding(char * prog_name,char * target)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
obj_init(obj_list * c)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
obj_elf_hdr(obj_list * c)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
obj_prog_hdr(obj_list * c)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
find_dynamic_sect(obj_list * c)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
find_symtabs(obj_list * c)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
obj_app_symtab(obj_list * c)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
obj_finis(obj_list * c)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
is_text_section(int shndx,Elf * elf_file,Elf64_Ehdr * ehdr)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
scan_archive_symbols(obj_list * c,Elf64_Sym * syms,int symn,char * buf,Elf * elf_file,Elf64_Ehdr * ehdr)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
scan_symbols(obj_list * c,Elf64_Sym * syms,int symn,char * buf)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
bind_symbols(obj_list * c,Elf64_Sym * syms,int symn,char * buf)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 *
get_scnfd(Elf * e_file,int shstrtab,int SCN_TYPE)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
print_symtab(obj_list * com,Elf * elf_file,Elf64_Ehdr * ehdr,Elf64_Shdr * shdr,Elf_Scn * p_sd,char * filename)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
get_symtab(obj_list * c,Elf * elf_file,Elf64_Ehdr * ehdr,char * filename)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
process(obj_list * c,Elf * elf_file,char * filename)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
process_archive(obj_list * c)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 *
add_dtneeded(dt_list * p,dt_list * node)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
find_dtneeded(obj_list * c)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
obj_elfcheck(obj_list * c)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
analyze_dependency(char * dep_file)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
analyze_main(obj_list * c)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
analyze_args(obj_list * c,int argc,char * argv[])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
main(int argc,char * argv[])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