xref: /illumos-gate/usr/src/cmd/sgs/prof/common/rdelf.c (revision 7879e8a6)
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
57a5d89c4Sab  * Common Development and Distribution License (the "License").
67a5d89c4Sab  * 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 /*
227a5d89c4Sab  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2392ed1782Smike_s  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
2592ed1782Smike_s 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * ELF support routines for processing versioned mon.out files.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
3092ed1782Smike_s #include <stdlib.h>
3192ed1782Smike_s #include <string.h>
327c478bd9Sstevel@tonic-gate #include "profv.h"
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate bool
is_shared_obj(char * name)357c478bd9Sstevel@tonic-gate is_shared_obj(char *name)
367c478bd9Sstevel@tonic-gate {
377c478bd9Sstevel@tonic-gate 	int		fd;
387c478bd9Sstevel@tonic-gate 	Elf		*elf;
397c478bd9Sstevel@tonic-gate 	GElf_Ehdr	ehdr;
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate 	if ((fd = open(name, O_RDONLY)) == -1) {
4292ed1782Smike_s 		(void) fprintf(stderr, "%s: can't open `%s'\n", cmdname, name);
437c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
447c478bd9Sstevel@tonic-gate 	}
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
4792ed1782Smike_s 		(void) fprintf(stderr, "%s: libelf out of date\n", cmdname);
487c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
497c478bd9Sstevel@tonic-gate 	}
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
5292ed1782Smike_s 		(void) fprintf(stderr, "%s: elf_begin failed\n", cmdname);
537c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
547c478bd9Sstevel@tonic-gate 	}
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
5792ed1782Smike_s 		(void) fprintf(stderr, "%s: can't read ELF header of %s\n",
587c478bd9Sstevel@tonic-gate 								cmdname, name);
597c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
607c478bd9Sstevel@tonic-gate 	}
617c478bd9Sstevel@tonic-gate 
6292ed1782Smike_s 	(void) elf_end(elf);
6392ed1782Smike_s 	(void) close(fd);
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	if (ehdr.e_type == ET_DYN)
667c478bd9Sstevel@tonic-gate 		return (TRUE);
677c478bd9Sstevel@tonic-gate 	else
687c478bd9Sstevel@tonic-gate 		return (FALSE);
697c478bd9Sstevel@tonic-gate }
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate static void
rm_dups(nltype * nl,size_t * nfuncs)727c478bd9Sstevel@tonic-gate rm_dups(nltype *nl, size_t *nfuncs)
737c478bd9Sstevel@tonic-gate {
747c478bd9Sstevel@tonic-gate 	size_t	i, prev = 0, ndx = 0;
757c478bd9Sstevel@tonic-gate 	int	prev_type, prev_bind, cur_type;
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 	for (i = 1; i < *nfuncs; i++) {
787c478bd9Sstevel@tonic-gate 		/*
797c478bd9Sstevel@tonic-gate 		 * If current value is different from prev, proceed.
807c478bd9Sstevel@tonic-gate 		 */
817c478bd9Sstevel@tonic-gate 		if (nl[prev].value < nl[i].value) {
827c478bd9Sstevel@tonic-gate 			prev = i;
837c478bd9Sstevel@tonic-gate 			continue;
847c478bd9Sstevel@tonic-gate 		}
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 		/*
877c478bd9Sstevel@tonic-gate 		 * If current and prev have the syminfo, rm the latter.
887c478bd9Sstevel@tonic-gate 		 */
897c478bd9Sstevel@tonic-gate 		if (nl[prev].info == nl[i].info) {
907c478bd9Sstevel@tonic-gate 			nl[i].name = NULL;
917c478bd9Sstevel@tonic-gate 			continue;
927c478bd9Sstevel@tonic-gate 		}
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 		prev_type = ELF_ST_TYPE(nl[prev].info);
957c478bd9Sstevel@tonic-gate 		prev_bind = ELF_ST_BIND(nl[prev].info);
967c478bd9Sstevel@tonic-gate 		cur_type = ELF_ST_TYPE(nl[i].info);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 		/*
997c478bd9Sstevel@tonic-gate 		 * Remove the one with STT_NOTYPE and keep the other.
1007c478bd9Sstevel@tonic-gate 		 */
1017c478bd9Sstevel@tonic-gate 		if (prev_type != cur_type) {
1027c478bd9Sstevel@tonic-gate 			if (prev_type != STT_NOTYPE)
1037c478bd9Sstevel@tonic-gate 				nl[i].name = NULL;
1047c478bd9Sstevel@tonic-gate 			else {
1057c478bd9Sstevel@tonic-gate 				nl[prev].name = NULL;
1067c478bd9Sstevel@tonic-gate 				prev = i;
1077c478bd9Sstevel@tonic-gate 			}
1087c478bd9Sstevel@tonic-gate 			continue;
1097c478bd9Sstevel@tonic-gate 		}
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 		/*
1127c478bd9Sstevel@tonic-gate 		 * If they have the same type, take the stronger bound
1137c478bd9Sstevel@tonic-gate 		 * function
1147c478bd9Sstevel@tonic-gate 		 */
1157c478bd9Sstevel@tonic-gate 		if (prev_bind != STB_WEAK)
1167c478bd9Sstevel@tonic-gate 			nl[i].name = NULL;
1177c478bd9Sstevel@tonic-gate 		else {
1187c478bd9Sstevel@tonic-gate 			nl[prev].name = NULL;
1197c478bd9Sstevel@tonic-gate 			prev = i;
1207c478bd9Sstevel@tonic-gate 		}
1217c478bd9Sstevel@tonic-gate 	}
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	/*
1257c478bd9Sstevel@tonic-gate 	 * Actually remove the cleared symbols from namelist. We're not
1267c478bd9Sstevel@tonic-gate 	 * truncating namelist by realloc, though.
1277c478bd9Sstevel@tonic-gate 	 */
1287c478bd9Sstevel@tonic-gate 	for (i = 0; (i < *nfuncs) && (nl[i].name != NULL); i++)
1297c478bd9Sstevel@tonic-gate 		;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	ndx = i;
1327c478bd9Sstevel@tonic-gate 	for (i = ndx + 1; i < *nfuncs; i++) {
1337c478bd9Sstevel@tonic-gate 		if (nl[i].name) {
1347c478bd9Sstevel@tonic-gate 			nl[ndx] = nl[i];
1357c478bd9Sstevel@tonic-gate 			ndx++;
1367c478bd9Sstevel@tonic-gate 		}
1377c478bd9Sstevel@tonic-gate 	}
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	*nfuncs = ndx;
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate int
cmp_by_address(const void * arg1,const void * arg2)14392ed1782Smike_s cmp_by_address(const void *arg1, const void *arg2)
1447c478bd9Sstevel@tonic-gate {
14592ed1782Smike_s 	nltype *a = (nltype *)arg1;
14692ed1782Smike_s 	nltype *b = (nltype *)arg2;
14792ed1782Smike_s 
1487c478bd9Sstevel@tonic-gate 	if (a->value < b->value)
1497c478bd9Sstevel@tonic-gate 		return (-1);
1507c478bd9Sstevel@tonic-gate 	else if (a->value > b->value)
1517c478bd9Sstevel@tonic-gate 		return (1);
1527c478bd9Sstevel@tonic-gate 	else
1537c478bd9Sstevel@tonic-gate 		return (0);
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate static int
is_function(Elf * elf,GElf_Sym * sym)1577c478bd9Sstevel@tonic-gate is_function(Elf *elf, GElf_Sym *sym)
1587c478bd9Sstevel@tonic-gate {
1597c478bd9Sstevel@tonic-gate 	Elf_Scn		*scn;
1607c478bd9Sstevel@tonic-gate 	GElf_Shdr	shdr;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	/*
1637c478bd9Sstevel@tonic-gate 	 * With dynamic linking, it is possible that certain undefined
1647c478bd9Sstevel@tonic-gate 	 * symbols exist in the objects. The actual definition will be
1657c478bd9Sstevel@tonic-gate 	 * found elsewhere, so we'll just skip it for this object.
1667c478bd9Sstevel@tonic-gate 	 */
1677c478bd9Sstevel@tonic-gate 	if (sym->st_shndx == SHN_UNDEF)
1687c478bd9Sstevel@tonic-gate 		return (0);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) {
1717c478bd9Sstevel@tonic-gate 		if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL)
1727c478bd9Sstevel@tonic-gate 			return (1);
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 		if (GELF_ST_BIND(sym->st_info) == STB_WEAK)
1757c478bd9Sstevel@tonic-gate 			return (1);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 		if (gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL)
1787c478bd9Sstevel@tonic-gate 			return (1);
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	/*
1827c478bd9Sstevel@tonic-gate 	 * It's not a function; determine if it's in an executable section.
1837c478bd9Sstevel@tonic-gate 	 */
1847c478bd9Sstevel@tonic-gate 	if (GELF_ST_TYPE(sym->st_info) != STT_NOTYPE)
1857c478bd9Sstevel@tonic-gate 		return (0);
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	/*
1887c478bd9Sstevel@tonic-gate 	 * If it isn't global, and it isn't weak, and it isn't
1897c478bd9Sstevel@tonic-gate 	 * a 'local with the gflag set', then get out.
1907c478bd9Sstevel@tonic-gate 	 */
1917c478bd9Sstevel@tonic-gate 	if (GELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
1927c478bd9Sstevel@tonic-gate 			GELF_ST_BIND(sym->st_info) != STB_WEAK &&
1937c478bd9Sstevel@tonic-gate 			!(gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL))
1947c478bd9Sstevel@tonic-gate 		return (0);
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	if (sym->st_shndx >= SHN_LORESERVE)
1977c478bd9Sstevel@tonic-gate 		return (0);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	scn = elf_getscn(elf, sym->st_shndx);
20092ed1782Smike_s 	(void) gelf_getshdr(scn, &shdr);
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	if (!(shdr.sh_flags & SHF_EXECINSTR))
2037c478bd9Sstevel@tonic-gate 		return (0);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	return (1);
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate static void
fetch_symtab(Elf * elf,char * filename,mod_info_t * module)2097c478bd9Sstevel@tonic-gate fetch_symtab(Elf *elf, char *filename, mod_info_t *module)
2107c478bd9Sstevel@tonic-gate {
2117a5d89c4Sab 	Elf_Scn		*scn = NULL, *sym_pri = NULL, *sym_aux = NULL;
2127c478bd9Sstevel@tonic-gate 	GElf_Word	strndx = 0;
2137c478bd9Sstevel@tonic-gate 	size_t		i, nsyms, nfuncs;
214*7879e8a6SToomas Soome 	GElf_Xword	nsyms_pri = 0, nsyms_aux = 0;
215*7879e8a6SToomas Soome 	Elf_Data	*symdata_pri, *symdata_aux = NULL;
2167c478bd9Sstevel@tonic-gate 	nltype		*nl, *npe;
2177a5d89c4Sab 	int		symtab_found = 0;
2187c478bd9Sstevel@tonic-gate 
2197a5d89c4Sab 
2207a5d89c4Sab 	/*
2217a5d89c4Sab 	 * Scan the section headers looking for a symbol table. Our
2227a5d89c4Sab 	 * preference is to use .symtab, because it contains the full
2237a5d89c4Sab 	 * set of symbols. If we find it, we stop looking immediately
2247a5d89c4Sab 	 * and use it. In the absence of a .symtab section, we are
2257a5d89c4Sab 	 * willing to use the dynamic symbol table (.dynsym), possibly
2267a5d89c4Sab 	 * augmented by the .SUNW_ldynsym, which contains local symbols.
2277a5d89c4Sab 	 */
2287a5d89c4Sab 	while ((symtab_found == 0) && ((scn = elf_nextscn(elf, scn)) != NULL)) {
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 		GElf_Shdr shdr;
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 		if (gelf_getshdr(scn, &shdr) == NULL)
2337c478bd9Sstevel@tonic-gate 			continue;
2347c478bd9Sstevel@tonic-gate 
2357a5d89c4Sab 		switch (shdr.sh_type) {
2367a5d89c4Sab 		case SHT_SYMTAB:
2377a5d89c4Sab 			nsyms_pri = shdr.sh_size / shdr.sh_entsize;
2387a5d89c4Sab 			strndx = shdr.sh_link;
2397a5d89c4Sab 			sym_pri = scn;
2407a5d89c4Sab 			/* Throw away .SUNW_ldynsym. It is for .dynsym only */
2417a5d89c4Sab 			nsyms_aux = 0;
2427a5d89c4Sab 			sym_aux = NULL;
2437a5d89c4Sab 			/* We have found the best symbol table. Stop looking */
2447a5d89c4Sab 			symtab_found = 1;
2457a5d89c4Sab 			break;
2467c478bd9Sstevel@tonic-gate 
2477a5d89c4Sab 		case SHT_DYNSYM:
2487a5d89c4Sab 			/* We will use .dynsym if no .symtab is found */
2497a5d89c4Sab 			nsyms_pri = shdr.sh_size / shdr.sh_entsize;
2507c478bd9Sstevel@tonic-gate 			strndx = shdr.sh_link;
2517a5d89c4Sab 			sym_pri = scn;
2527a5d89c4Sab 			break;
2537c478bd9Sstevel@tonic-gate 
2547a5d89c4Sab 		case SHT_SUNW_LDYNSYM:
2557a5d89c4Sab 			/* Auxiliary table, used with .dynsym */
2567a5d89c4Sab 			nsyms_aux = shdr.sh_size / shdr.sh_entsize;
2577a5d89c4Sab 			sym_aux = scn;
2587c478bd9Sstevel@tonic-gate 			break;
2597a5d89c4Sab 		}
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 
2627a5d89c4Sab 	if (sym_pri == NULL || strndx == 0) {
26392ed1782Smike_s 		(void) fprintf(stderr, "%s: missing symbol table in %s\n",
2647c478bd9Sstevel@tonic-gate 						    cmdname, filename);
2657c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 
2687a5d89c4Sab 	nsyms = (size_t)(nsyms_pri + nsyms_aux);
2697a5d89c4Sab 	if ((nsyms_pri + nsyms_aux) != (GElf_Xword)nsyms) {
2707a5d89c4Sab 		(void) fprintf(stderr,
2717a5d89c4Sab 		    "%s: can't handle more than 2^32 symbols", cmdname);
2727a5d89c4Sab 		exit(ERR_INPUT);
2737a5d89c4Sab 	}
2747a5d89c4Sab 
2757a5d89c4Sab 	if ((symdata_pri = elf_getdata(sym_pri, NULL)) == NULL) {
27692ed1782Smike_s 		(void) fprintf(stderr, "%s: can't read symbol data from %s\n",
2777a5d89c4Sab 		    cmdname, filename);
2787a5d89c4Sab 		exit(ERR_ELF);
2797a5d89c4Sab 	}
2807a5d89c4Sab 
2817a5d89c4Sab 	if ((sym_aux != NULL) &&
2827a5d89c4Sab 	    ((symdata_aux = elf_getdata(sym_aux, NULL)) == NULL)) {
2837a5d89c4Sab 		(void) fprintf(stderr,
2847a5d89c4Sab 		    "%s: can't read .SUNW_ldynsym symbol data from %s\n",
2857a5d89c4Sab 		    cmdname, filename);
2867c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	if ((npe = nl = (nltype *) calloc(nsyms, sizeof (nltype))) == NULL) {
29092ed1782Smike_s 		(void) fprintf(stderr, "%s: can't alloc %x bytes for symbols\n",
2917c478bd9Sstevel@tonic-gate 					cmdname, nsyms * sizeof (nltype));
2927c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	/*
2967c478bd9Sstevel@tonic-gate 	 * Now we need to cruise through the symbol table eliminating
2977c478bd9Sstevel@tonic-gate 	 * all non-functions from consideration, and making strings
2987c478bd9Sstevel@tonic-gate 	 * real.
2997c478bd9Sstevel@tonic-gate 	 */
3007c478bd9Sstevel@tonic-gate 	nfuncs = 0;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	for (i = 1; i < nsyms; i++) {
3037c478bd9Sstevel@tonic-gate 		GElf_Sym	gsym;
3047c478bd9Sstevel@tonic-gate 		char		*name;
3057c478bd9Sstevel@tonic-gate 
3067a5d89c4Sab 		/*
3077a5d89c4Sab 		 * Look up the symbol. In the case where we have a
3087a5d89c4Sab 		 * .SUNW_ldynsym/.dynsym pair, we treat them as a single
3097a5d89c4Sab 		 * logical table, with the data in .SUNW_ldynsym coming
3107a5d89c4Sab 		 * before the data in .dynsym.
3117a5d89c4Sab 		 */
3127a5d89c4Sab 		if (i >= nsyms_aux)
3137a5d89c4Sab 			(void) gelf_getsym(symdata_pri, i - nsyms_aux, &gsym);
3147a5d89c4Sab 		else
3157a5d89c4Sab 			(void) gelf_getsym(symdata_aux, i, &gsym);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 		name = elf_strptr(elf, strndx, gsym.st_name);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 		/*
3207c478bd9Sstevel@tonic-gate 		 * We're interested in this symbol if it's a function
3217c478bd9Sstevel@tonic-gate 		 */
3227c478bd9Sstevel@tonic-gate 		if (is_function(elf, &gsym)) {
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 			npe->name = name;
3257c478bd9Sstevel@tonic-gate 			npe->value = gsym.st_value;
3267c478bd9Sstevel@tonic-gate 			npe->size = gsym.st_size;
3277c478bd9Sstevel@tonic-gate 			npe->info = gsym.st_info;
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 			npe++;
3307c478bd9Sstevel@tonic-gate 			nfuncs++;
3317c478bd9Sstevel@tonic-gate 		}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 		if (strcmp(name, PRF_END) == 0)
3347c478bd9Sstevel@tonic-gate 			module->data_end = gsym.st_value;
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	if (npe == nl) {
33892ed1782Smike_s 		(void) fprintf(stderr, "%s: no valid functions in %s\n",
3397c478bd9Sstevel@tonic-gate 						    cmdname, filename);
3407c478bd9Sstevel@tonic-gate 		exit(ERR_INPUT);
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	/*
3447c478bd9Sstevel@tonic-gate 	 * And finally, sort the symbols by increasing address
3457c478bd9Sstevel@tonic-gate 	 * and remove the duplicates.
3467c478bd9Sstevel@tonic-gate 	 */
34792ed1782Smike_s 	qsort(nl, nfuncs, sizeof (nltype), cmp_by_address);
3487c478bd9Sstevel@tonic-gate 	rm_dups(nl, &nfuncs);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	module->nl = nl;
3517c478bd9Sstevel@tonic-gate 	module->nfuncs = nfuncs;
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate static GElf_Addr
get_txtorigin(Elf * elf,char * filename)3557c478bd9Sstevel@tonic-gate get_txtorigin(Elf *elf, char *filename)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	GElf_Ehdr	ehdr;
3587c478bd9Sstevel@tonic-gate 	GElf_Phdr	phdr;
3597c478bd9Sstevel@tonic-gate 	GElf_Half	ndx;
3607c478bd9Sstevel@tonic-gate 	GElf_Addr	txt_origin = 0;
3617c478bd9Sstevel@tonic-gate 	bool		first_load_seg = TRUE;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
36492ed1782Smike_s 		(void) fprintf(stderr, "%s: can't read ELF header of %s\n",
3657c478bd9Sstevel@tonic-gate 						    cmdname, filename);
3667c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	for (ndx = 0; ndx < ehdr.e_phnum; ndx++) {
3707c478bd9Sstevel@tonic-gate 		if (gelf_getphdr(elf, ndx, &phdr) == NULL)
3717c478bd9Sstevel@tonic-gate 			continue;
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 		if ((phdr.p_type == PT_LOAD) && !(phdr.p_flags & PF_W)) {
3747c478bd9Sstevel@tonic-gate 			if (first_load_seg || phdr.p_vaddr < txt_origin)
3757c478bd9Sstevel@tonic-gate 				txt_origin = phdr.p_vaddr;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 			if (first_load_seg)
3787c478bd9Sstevel@tonic-gate 				first_load_seg = FALSE;
3797c478bd9Sstevel@tonic-gate 		}
3807c478bd9Sstevel@tonic-gate 	}
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	return (txt_origin);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate void
get_syms(char * filename,mod_info_t * mi)3867c478bd9Sstevel@tonic-gate get_syms(char *filename, mod_info_t *mi)
3877c478bd9Sstevel@tonic-gate {
3887c478bd9Sstevel@tonic-gate 	int		fd;
3897c478bd9Sstevel@tonic-gate 	Elf		*elf;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	if ((fd = open(filename, O_RDONLY)) == -1) {
3927c478bd9Sstevel@tonic-gate 		perror(filename);
3937c478bd9Sstevel@tonic-gate 		exit(ERR_SYSCALL);
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
39792ed1782Smike_s 		(void) fprintf(stderr, "%s: libelf out of date\n", cmdname);
3987c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
40292ed1782Smike_s 		(void) fprintf(stderr, "%s: elf_begin failed\n", cmdname);
4037c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	if (gelf_getclass(elf) != ELFCLASS64) {
40792ed1782Smike_s 		(void) fprintf(stderr, "%s: unsupported mon.out format for "
4087c478bd9Sstevel@tonic-gate 				    "this class of object\n", cmdname);
4097c478bd9Sstevel@tonic-gate 		exit(ERR_ELF);
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	mi->txt_origin = get_txtorigin(elf, filename);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	fetch_symtab(elf, filename, mi);
4157c478bd9Sstevel@tonic-gate }
416