xref: /titanic_52/usr/src/cmd/sgs/prof/common/rdelf.c (revision 7a5d89c451efe2f22ced23ea9fcaa00be2a9b64f)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7a5d89c4Sab196087  * Common Development and Distribution License (the "License").
6*7a5d89c4Sab196087  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*7a5d89c4Sab196087  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2392ed1782Smike_s  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
2592ed1782Smike_s 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * ELF support routines for processing versioned mon.out files.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
3292ed1782Smike_s #include <stdlib.h>
3392ed1782Smike_s #include <string.h>
347c478bd9Sstevel@tonic-gate #include "profv.h"
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate bool
377c478bd9Sstevel@tonic-gate is_shared_obj(char *name)
387c478bd9Sstevel@tonic-gate {
397c478bd9Sstevel@tonic-gate 	int		fd;
407c478bd9Sstevel@tonic-gate 	Elf		*elf;
417c478bd9Sstevel@tonic-gate 	GElf_Ehdr	ehdr;
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate 	if ((fd = open(name, O_RDONLY)) == -1) {
4492ed1782Smike_s 		(void) fprintf(stderr, "%s: can't open `%s'\n", cmdname, name);
457c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
467c478bd9Sstevel@tonic-gate 	}
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
4992ed1782Smike_s 		(void) fprintf(stderr, "%s: libelf out of date\n", cmdname);
507c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
517c478bd9Sstevel@tonic-gate 	}
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
5492ed1782Smike_s 		(void) fprintf(stderr, "%s: elf_begin failed\n", cmdname);
557c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
567c478bd9Sstevel@tonic-gate 	}
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
5992ed1782Smike_s 		(void) fprintf(stderr, "%s: can't read ELF header of %s\n",
607c478bd9Sstevel@tonic-gate 								cmdname, name);
617c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
627c478bd9Sstevel@tonic-gate 	}
637c478bd9Sstevel@tonic-gate 
6492ed1782Smike_s 	(void) elf_end(elf);
6592ed1782Smike_s 	(void) close(fd);
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	if (ehdr.e_type == ET_DYN)
687c478bd9Sstevel@tonic-gate 		return (TRUE);
697c478bd9Sstevel@tonic-gate 	else
707c478bd9Sstevel@tonic-gate 		return (FALSE);
717c478bd9Sstevel@tonic-gate }
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate static void
747c478bd9Sstevel@tonic-gate rm_dups(nltype *nl, size_t *nfuncs)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 	size_t	i, prev = 0, ndx = 0;
777c478bd9Sstevel@tonic-gate 	int	prev_type, prev_bind, cur_type;
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	for (i = 1; i < *nfuncs; i++) {
807c478bd9Sstevel@tonic-gate 		/*
817c478bd9Sstevel@tonic-gate 		 * If current value is different from prev, proceed.
827c478bd9Sstevel@tonic-gate 		 */
837c478bd9Sstevel@tonic-gate 		if (nl[prev].value < nl[i].value) {
847c478bd9Sstevel@tonic-gate 			prev = i;
857c478bd9Sstevel@tonic-gate 			continue;
867c478bd9Sstevel@tonic-gate 		}
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 		/*
897c478bd9Sstevel@tonic-gate 		 * If current and prev have the syminfo, rm the latter.
907c478bd9Sstevel@tonic-gate 		 */
917c478bd9Sstevel@tonic-gate 		if (nl[prev].info == nl[i].info) {
927c478bd9Sstevel@tonic-gate 			nl[i].name = NULL;
937c478bd9Sstevel@tonic-gate 			continue;
947c478bd9Sstevel@tonic-gate 		}
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 		prev_type = ELF_ST_TYPE(nl[prev].info);
977c478bd9Sstevel@tonic-gate 		prev_bind = ELF_ST_BIND(nl[prev].info);
987c478bd9Sstevel@tonic-gate 		cur_type = ELF_ST_TYPE(nl[i].info);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 		/*
1017c478bd9Sstevel@tonic-gate 		 * Remove the one with STT_NOTYPE and keep the other.
1027c478bd9Sstevel@tonic-gate 		 */
1037c478bd9Sstevel@tonic-gate 		if (prev_type != cur_type) {
1047c478bd9Sstevel@tonic-gate 			if (prev_type != STT_NOTYPE)
1057c478bd9Sstevel@tonic-gate 				nl[i].name = NULL;
1067c478bd9Sstevel@tonic-gate 			else {
1077c478bd9Sstevel@tonic-gate 				nl[prev].name = NULL;
1087c478bd9Sstevel@tonic-gate 				prev = i;
1097c478bd9Sstevel@tonic-gate 			}
1107c478bd9Sstevel@tonic-gate 			continue;
1117c478bd9Sstevel@tonic-gate 		}
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 		/*
1147c478bd9Sstevel@tonic-gate 		 * If they have the same type, take the stronger bound
1157c478bd9Sstevel@tonic-gate 		 * function
1167c478bd9Sstevel@tonic-gate 		 */
1177c478bd9Sstevel@tonic-gate 		if (prev_bind != STB_WEAK)
1187c478bd9Sstevel@tonic-gate 			nl[i].name = NULL;
1197c478bd9Sstevel@tonic-gate 		else {
1207c478bd9Sstevel@tonic-gate 			nl[prev].name = NULL;
1217c478bd9Sstevel@tonic-gate 			prev = i;
1227c478bd9Sstevel@tonic-gate 		}
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	/*
1277c478bd9Sstevel@tonic-gate 	 * Actually remove the cleared symbols from namelist. We're not
1287c478bd9Sstevel@tonic-gate 	 * truncating namelist by realloc, though.
1297c478bd9Sstevel@tonic-gate 	 */
1307c478bd9Sstevel@tonic-gate 	for (i = 0; (i < *nfuncs) && (nl[i].name != NULL); i++)
1317c478bd9Sstevel@tonic-gate 		;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	ndx = i;
1347c478bd9Sstevel@tonic-gate 	for (i = ndx + 1; i < *nfuncs; i++) {
1357c478bd9Sstevel@tonic-gate 		if (nl[i].name) {
1367c478bd9Sstevel@tonic-gate 			nl[ndx] = nl[i];
1377c478bd9Sstevel@tonic-gate 			ndx++;
1387c478bd9Sstevel@tonic-gate 		}
1397c478bd9Sstevel@tonic-gate 	}
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	*nfuncs = ndx;
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate int
14592ed1782Smike_s cmp_by_address(const void *arg1, const void *arg2)
1467c478bd9Sstevel@tonic-gate {
14792ed1782Smike_s 	nltype *a = (nltype *)arg1;
14892ed1782Smike_s 	nltype *b = (nltype *)arg2;
14992ed1782Smike_s 
1507c478bd9Sstevel@tonic-gate 	if (a->value < b->value)
1517c478bd9Sstevel@tonic-gate 		return (-1);
1527c478bd9Sstevel@tonic-gate 	else if (a->value > b->value)
1537c478bd9Sstevel@tonic-gate 		return (1);
1547c478bd9Sstevel@tonic-gate 	else
1557c478bd9Sstevel@tonic-gate 		return (0);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate static int
1597c478bd9Sstevel@tonic-gate is_function(Elf *elf, GElf_Sym *sym)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate 	Elf_Scn		*scn;
1627c478bd9Sstevel@tonic-gate 	GElf_Shdr	shdr;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	/*
1657c478bd9Sstevel@tonic-gate 	 * With dynamic linking, it is possible that certain undefined
1667c478bd9Sstevel@tonic-gate 	 * symbols exist in the objects. The actual definition will be
1677c478bd9Sstevel@tonic-gate 	 * found elsewhere, so we'll just skip it for this object.
1687c478bd9Sstevel@tonic-gate 	 */
1697c478bd9Sstevel@tonic-gate 	if (sym->st_shndx == SHN_UNDEF)
1707c478bd9Sstevel@tonic-gate 		return (0);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) {
1737c478bd9Sstevel@tonic-gate 		if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL)
1747c478bd9Sstevel@tonic-gate 			return (1);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 		if (GELF_ST_BIND(sym->st_info) == STB_WEAK)
1777c478bd9Sstevel@tonic-gate 			return (1);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 		if (gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL)
1807c478bd9Sstevel@tonic-gate 			return (1);
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	/*
1847c478bd9Sstevel@tonic-gate 	 * It's not a function; determine if it's in an executable section.
1857c478bd9Sstevel@tonic-gate 	 */
1867c478bd9Sstevel@tonic-gate 	if (GELF_ST_TYPE(sym->st_info) != STT_NOTYPE)
1877c478bd9Sstevel@tonic-gate 		return (0);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	/*
1907c478bd9Sstevel@tonic-gate 	 * If it isn't global, and it isn't weak, and it isn't
1917c478bd9Sstevel@tonic-gate 	 * a 'local with the gflag set', then get out.
1927c478bd9Sstevel@tonic-gate 	 */
1937c478bd9Sstevel@tonic-gate 	if (GELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
1947c478bd9Sstevel@tonic-gate 			GELF_ST_BIND(sym->st_info) != STB_WEAK &&
1957c478bd9Sstevel@tonic-gate 			!(gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL))
1967c478bd9Sstevel@tonic-gate 		return (0);
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	if (sym->st_shndx >= SHN_LORESERVE)
1997c478bd9Sstevel@tonic-gate 		return (0);
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	scn = elf_getscn(elf, sym->st_shndx);
20292ed1782Smike_s 	(void) gelf_getshdr(scn, &shdr);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	if (!(shdr.sh_flags & SHF_EXECINSTR))
2057c478bd9Sstevel@tonic-gate 		return (0);
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	return (1);
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate static void
2117c478bd9Sstevel@tonic-gate fetch_symtab(Elf *elf, char *filename, mod_info_t *module)
2127c478bd9Sstevel@tonic-gate {
213*7a5d89c4Sab196087 	Elf_Scn		*scn = NULL, *sym_pri = NULL, *sym_aux = NULL;
2147c478bd9Sstevel@tonic-gate 	GElf_Word	strndx = 0;
2157c478bd9Sstevel@tonic-gate 	size_t		i, nsyms, nfuncs;
216*7a5d89c4Sab196087 	GElf_Xword	nsyms_pri, nsyms_aux = 0;
217*7a5d89c4Sab196087 	Elf_Data	*symdata_pri, *symdata_aux;
2187c478bd9Sstevel@tonic-gate 	nltype		*nl, *npe;
219*7a5d89c4Sab196087 	int		symtab_found = 0;
2207c478bd9Sstevel@tonic-gate 
221*7a5d89c4Sab196087 
222*7a5d89c4Sab196087 	/*
223*7a5d89c4Sab196087 	 * Scan the section headers looking for a symbol table. Our
224*7a5d89c4Sab196087 	 * preference is to use .symtab, because it contains the full
225*7a5d89c4Sab196087 	 * set of symbols. If we find it, we stop looking immediately
226*7a5d89c4Sab196087 	 * and use it. In the absence of a .symtab section, we are
227*7a5d89c4Sab196087 	 * willing to use the dynamic symbol table (.dynsym), possibly
228*7a5d89c4Sab196087 	 * augmented by the .SUNW_ldynsym, which contains local symbols.
229*7a5d89c4Sab196087 	 */
230*7a5d89c4Sab196087 	while ((symtab_found == 0) && ((scn = elf_nextscn(elf, scn)) != NULL)) {
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 		GElf_Shdr shdr;
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 		if (gelf_getshdr(scn, &shdr) == NULL)
2357c478bd9Sstevel@tonic-gate 			continue;
2367c478bd9Sstevel@tonic-gate 
237*7a5d89c4Sab196087 		switch (shdr.sh_type) {
238*7a5d89c4Sab196087 		case SHT_SYMTAB:
239*7a5d89c4Sab196087 			nsyms_pri = shdr.sh_size / shdr.sh_entsize;
2407c478bd9Sstevel@tonic-gate 			strndx = shdr.sh_link;
241*7a5d89c4Sab196087 			sym_pri = scn;
242*7a5d89c4Sab196087 			/* Throw away .SUNW_ldynsym. It is for .dynsym only */
243*7a5d89c4Sab196087 			nsyms_aux = 0;
244*7a5d89c4Sab196087 			sym_aux = NULL;
245*7a5d89c4Sab196087 			/* We have found the best symbol table. Stop looking */
246*7a5d89c4Sab196087 			symtab_found = 1;
247*7a5d89c4Sab196087 			break;
2487c478bd9Sstevel@tonic-gate 
249*7a5d89c4Sab196087 		case SHT_DYNSYM:
250*7a5d89c4Sab196087 			/* We will use .dynsym if no .symtab is found */
251*7a5d89c4Sab196087 			nsyms_pri = shdr.sh_size / shdr.sh_entsize;
252*7a5d89c4Sab196087 			strndx = shdr.sh_link;
253*7a5d89c4Sab196087 			sym_pri = scn;
254*7a5d89c4Sab196087 			break;
255*7a5d89c4Sab196087 
256*7a5d89c4Sab196087 		case SHT_SUNW_LDYNSYM:
257*7a5d89c4Sab196087 			/* Auxiliary table, used with .dynsym */
258*7a5d89c4Sab196087 			nsyms_aux = shdr.sh_size / shdr.sh_entsize;
259*7a5d89c4Sab196087 			sym_aux = scn;
2607c478bd9Sstevel@tonic-gate 			break;
2617c478bd9Sstevel@tonic-gate 		}
262*7a5d89c4Sab196087 	}
2637c478bd9Sstevel@tonic-gate 
264*7a5d89c4Sab196087 	if (sym_pri == NULL || strndx == 0) {
26592ed1782Smike_s 		(void) fprintf(stderr, "%s: missing symbol table in %s\n",
2667c478bd9Sstevel@tonic-gate 						    cmdname, filename);
2677c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
2687c478bd9Sstevel@tonic-gate 	}
2697c478bd9Sstevel@tonic-gate 
270*7a5d89c4Sab196087 	nsyms = (size_t)(nsyms_pri + nsyms_aux);
271*7a5d89c4Sab196087 	if ((nsyms_pri + nsyms_aux) != (GElf_Xword)nsyms) {
272*7a5d89c4Sab196087 		(void) fprintf(stderr,
273*7a5d89c4Sab196087 		    "%s: can't handle more than 2^32 symbols", cmdname);
274*7a5d89c4Sab196087 		exit(ERR_INPUT);
275*7a5d89c4Sab196087 	}
276*7a5d89c4Sab196087 
277*7a5d89c4Sab196087 	if ((symdata_pri = elf_getdata(sym_pri, NULL)) == NULL) {
27892ed1782Smike_s 		(void) fprintf(stderr, "%s: can't read symbol data from %s\n",
2797c478bd9Sstevel@tonic-gate 		    cmdname, filename);
2807c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 
283*7a5d89c4Sab196087 	if ((sym_aux != NULL) &&
284*7a5d89c4Sab196087 	    ((symdata_aux = elf_getdata(sym_aux, NULL)) == NULL)) {
285*7a5d89c4Sab196087 		(void) fprintf(stderr,
286*7a5d89c4Sab196087 		    "%s: can't read .SUNW_ldynsym symbol data from %s\n",
287*7a5d89c4Sab196087 		    cmdname, filename);
288*7a5d89c4Sab196087 		exit(ERR_ELF);
289*7a5d89c4Sab196087 	}
290*7a5d89c4Sab196087 
2917c478bd9Sstevel@tonic-gate 	if ((npe = nl = (nltype *) calloc(nsyms, sizeof (nltype))) == NULL) {
29292ed1782Smike_s 		(void) fprintf(stderr, "%s: can't alloc %x bytes for symbols\n",
2937c478bd9Sstevel@tonic-gate 					cmdname, nsyms * sizeof (nltype));
2947c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	/*
2987c478bd9Sstevel@tonic-gate 	 * Now we need to cruise through the symbol table eliminating
2997c478bd9Sstevel@tonic-gate 	 * all non-functions from consideration, and making strings
3007c478bd9Sstevel@tonic-gate 	 * real.
3017c478bd9Sstevel@tonic-gate 	 */
3027c478bd9Sstevel@tonic-gate 	nfuncs = 0;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	for (i = 1; i < nsyms; i++) {
3057c478bd9Sstevel@tonic-gate 		GElf_Sym	gsym;
3067c478bd9Sstevel@tonic-gate 		char		*name;
3077c478bd9Sstevel@tonic-gate 
308*7a5d89c4Sab196087 		/*
309*7a5d89c4Sab196087 		 * Look up the symbol. In the case where we have a
310*7a5d89c4Sab196087 		 * .SUNW_ldynsym/.dynsym pair, we treat them as a single
311*7a5d89c4Sab196087 		 * logical table, with the data in .SUNW_ldynsym coming
312*7a5d89c4Sab196087 		 * before the data in .dynsym.
313*7a5d89c4Sab196087 		 */
314*7a5d89c4Sab196087 		if (i >= nsyms_aux)
315*7a5d89c4Sab196087 			(void) gelf_getsym(symdata_pri, i - nsyms_aux, &gsym);
316*7a5d89c4Sab196087 		else
317*7a5d89c4Sab196087 			(void) gelf_getsym(symdata_aux, i, &gsym);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 		name = elf_strptr(elf, strndx, gsym.st_name);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 		/*
3227c478bd9Sstevel@tonic-gate 		 * We're interested in this symbol if it's a function
3237c478bd9Sstevel@tonic-gate 		 */
3247c478bd9Sstevel@tonic-gate 		if (is_function(elf, &gsym)) {
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 			npe->name = name;
3277c478bd9Sstevel@tonic-gate 			npe->value = gsym.st_value;
3287c478bd9Sstevel@tonic-gate 			npe->size = gsym.st_size;
3297c478bd9Sstevel@tonic-gate 			npe->info = gsym.st_info;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 			npe++;
3327c478bd9Sstevel@tonic-gate 			nfuncs++;
3337c478bd9Sstevel@tonic-gate 		}
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 		if (strcmp(name, PRF_END) == 0)
3367c478bd9Sstevel@tonic-gate 			module->data_end = gsym.st_value;
3377c478bd9Sstevel@tonic-gate 	}
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	if (npe == nl) {
34092ed1782Smike_s 		(void) fprintf(stderr, "%s: no valid functions in %s\n",
3417c478bd9Sstevel@tonic-gate 						    cmdname, filename);
3427c478bd9Sstevel@tonic-gate 		exit(ERR_INPUT);
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	/*
3467c478bd9Sstevel@tonic-gate 	 * And finally, sort the symbols by increasing address
3477c478bd9Sstevel@tonic-gate 	 * and remove the duplicates.
3487c478bd9Sstevel@tonic-gate 	 */
34992ed1782Smike_s 	qsort(nl, nfuncs, sizeof (nltype), cmp_by_address);
3507c478bd9Sstevel@tonic-gate 	rm_dups(nl, &nfuncs);
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	module->nl = nl;
3537c478bd9Sstevel@tonic-gate 	module->nfuncs = nfuncs;
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate static GElf_Addr
3577c478bd9Sstevel@tonic-gate get_txtorigin(Elf *elf, char *filename)
3587c478bd9Sstevel@tonic-gate {
3597c478bd9Sstevel@tonic-gate 	GElf_Ehdr	ehdr;
3607c478bd9Sstevel@tonic-gate 	GElf_Phdr	phdr;
3617c478bd9Sstevel@tonic-gate 	GElf_Half	ndx;
3627c478bd9Sstevel@tonic-gate 	GElf_Addr	txt_origin = 0;
3637c478bd9Sstevel@tonic-gate 	bool		first_load_seg = TRUE;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
36692ed1782Smike_s 		(void) fprintf(stderr, "%s: can't read ELF header of %s\n",
3677c478bd9Sstevel@tonic-gate 						    cmdname, filename);
3687c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	for (ndx = 0; ndx < ehdr.e_phnum; ndx++) {
3727c478bd9Sstevel@tonic-gate 		if (gelf_getphdr(elf, ndx, &phdr) == NULL)
3737c478bd9Sstevel@tonic-gate 			continue;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 		if ((phdr.p_type == PT_LOAD) && !(phdr.p_flags & PF_W)) {
3767c478bd9Sstevel@tonic-gate 			if (first_load_seg || phdr.p_vaddr < txt_origin)
3777c478bd9Sstevel@tonic-gate 				txt_origin = phdr.p_vaddr;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 			if (first_load_seg)
3807c478bd9Sstevel@tonic-gate 				first_load_seg = FALSE;
3817c478bd9Sstevel@tonic-gate 		}
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	return (txt_origin);
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate void
3887c478bd9Sstevel@tonic-gate get_syms(char *filename, mod_info_t *mi)
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate 	int		fd;
3917c478bd9Sstevel@tonic-gate 	Elf		*elf;
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	if ((fd = open(filename, O_RDONLY)) == -1) {
3947c478bd9Sstevel@tonic-gate 		perror(filename);
3957c478bd9Sstevel@tonic-gate 		exit(ERR_SYSCALL);
3967c478bd9Sstevel@tonic-gate 	}
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
39992ed1782Smike_s 		(void) fprintf(stderr, "%s: libelf out of date\n", cmdname);
4007c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
40492ed1782Smike_s 		(void) fprintf(stderr, "%s: elf_begin failed\n", cmdname);
4057c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	if (gelf_getclass(elf) != ELFCLASS64) {
40992ed1782Smike_s 		(void) fprintf(stderr, "%s: unsupported mon.out format for "
4107c478bd9Sstevel@tonic-gate 				    "this class of object\n", cmdname);
4117c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
4127c478bd9Sstevel@tonic-gate 	}
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	mi->txt_origin = get_txtorigin(elf, filename);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	fetch_symtab(elf, filename, mi);
4177c478bd9Sstevel@tonic-gate }
418