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