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
47static unsigned long
48my_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
69static void
70output_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
98static void
99store_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
132static void
133check_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
173static int
174stringcompare(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
198static void
199profile_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
243static void
244output_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
316static int
317obj_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
399static int
400obj_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
551static int
552obj_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
604static int
605find_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
682static int
683find_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
788static int
789obj_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
825static void
826obj_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
855static int
856is_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
894static void
895scan_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
980static void
981scan_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
1067static void
1068bind_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
1133static Elf_Scn *
1134get_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
1166static void
1167print_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) + 2);
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
1257static void
1258get_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
1323static void
1324process(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
1358static int
1359process_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
1400static dt_list *
1401add_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
1434static void
1435find_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
1478static int
1479obj_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
1535static int
1536analyze_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
1575static void
1576analyze_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
1610static int
1611analyze_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
1683int
1684main(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