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