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