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