xref: /onnv-gate/usr/src/cmd/sgs/prof/common/rdelf.c (revision 3621:2cbc0f92c696)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*3621Sab196087  * Common Development and Distribution License (the "License").
6*3621Sab196087  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*3621Sab196087  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23211Smike_s  * Use is subject to license terms.
240Sstevel@tonic-gate  */
25211Smike_s 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * ELF support routines for processing versioned mon.out files.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
32211Smike_s #include <stdlib.h>
33211Smike_s #include <string.h>
340Sstevel@tonic-gate #include "profv.h"
350Sstevel@tonic-gate 
360Sstevel@tonic-gate bool
is_shared_obj(char * name)370Sstevel@tonic-gate is_shared_obj(char *name)
380Sstevel@tonic-gate {
390Sstevel@tonic-gate 	int		fd;
400Sstevel@tonic-gate 	Elf		*elf;
410Sstevel@tonic-gate 	GElf_Ehdr	ehdr;
420Sstevel@tonic-gate 
430Sstevel@tonic-gate 	if ((fd = open(name, O_RDONLY)) == -1) {
44211Smike_s 		(void) fprintf(stderr, "%s: can't open `%s'\n", cmdname, name);
450Sstevel@tonic-gate 		exit(ERR_ELF);
460Sstevel@tonic-gate 	}
470Sstevel@tonic-gate 
480Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
49211Smike_s 		(void) fprintf(stderr, "%s: libelf out of date\n", cmdname);
500Sstevel@tonic-gate 		exit(ERR_ELF);
510Sstevel@tonic-gate 	}
520Sstevel@tonic-gate 
530Sstevel@tonic-gate 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
54211Smike_s 		(void) fprintf(stderr, "%s: elf_begin failed\n", cmdname);
550Sstevel@tonic-gate 		exit(ERR_ELF);
560Sstevel@tonic-gate 	}
570Sstevel@tonic-gate 
580Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
59211Smike_s 		(void) fprintf(stderr, "%s: can't read ELF header of %s\n",
600Sstevel@tonic-gate 								cmdname, name);
610Sstevel@tonic-gate 		exit(ERR_ELF);
620Sstevel@tonic-gate 	}
630Sstevel@tonic-gate 
64211Smike_s 	(void) elf_end(elf);
65211Smike_s 	(void) close(fd);
660Sstevel@tonic-gate 
670Sstevel@tonic-gate 	if (ehdr.e_type == ET_DYN)
680Sstevel@tonic-gate 		return (TRUE);
690Sstevel@tonic-gate 	else
700Sstevel@tonic-gate 		return (FALSE);
710Sstevel@tonic-gate }
720Sstevel@tonic-gate 
730Sstevel@tonic-gate static void
rm_dups(nltype * nl,size_t * nfuncs)740Sstevel@tonic-gate rm_dups(nltype *nl, size_t *nfuncs)
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 	size_t	i, prev = 0, ndx = 0;
770Sstevel@tonic-gate 	int	prev_type, prev_bind, cur_type;
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	for (i = 1; i < *nfuncs; i++) {
800Sstevel@tonic-gate 		/*
810Sstevel@tonic-gate 		 * If current value is different from prev, proceed.
820Sstevel@tonic-gate 		 */
830Sstevel@tonic-gate 		if (nl[prev].value < nl[i].value) {
840Sstevel@tonic-gate 			prev = i;
850Sstevel@tonic-gate 			continue;
860Sstevel@tonic-gate 		}
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 		/*
890Sstevel@tonic-gate 		 * If current and prev have the syminfo, rm the latter.
900Sstevel@tonic-gate 		 */
910Sstevel@tonic-gate 		if (nl[prev].info == nl[i].info) {
920Sstevel@tonic-gate 			nl[i].name = NULL;
930Sstevel@tonic-gate 			continue;
940Sstevel@tonic-gate 		}
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 		prev_type = ELF_ST_TYPE(nl[prev].info);
970Sstevel@tonic-gate 		prev_bind = ELF_ST_BIND(nl[prev].info);
980Sstevel@tonic-gate 		cur_type = ELF_ST_TYPE(nl[i].info);
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 		/*
1010Sstevel@tonic-gate 		 * Remove the one with STT_NOTYPE and keep the other.
1020Sstevel@tonic-gate 		 */
1030Sstevel@tonic-gate 		if (prev_type != cur_type) {
1040Sstevel@tonic-gate 			if (prev_type != STT_NOTYPE)
1050Sstevel@tonic-gate 				nl[i].name = NULL;
1060Sstevel@tonic-gate 			else {
1070Sstevel@tonic-gate 				nl[prev].name = NULL;
1080Sstevel@tonic-gate 				prev = i;
1090Sstevel@tonic-gate 			}
1100Sstevel@tonic-gate 			continue;
1110Sstevel@tonic-gate 		}
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 		/*
1140Sstevel@tonic-gate 		 * If they have the same type, take the stronger bound
1150Sstevel@tonic-gate 		 * function
1160Sstevel@tonic-gate 		 */
1170Sstevel@tonic-gate 		if (prev_bind != STB_WEAK)
1180Sstevel@tonic-gate 			nl[i].name = NULL;
1190Sstevel@tonic-gate 		else {
1200Sstevel@tonic-gate 			nl[prev].name = NULL;
1210Sstevel@tonic-gate 			prev = i;
1220Sstevel@tonic-gate 		}
1230Sstevel@tonic-gate 	}
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	/*
1270Sstevel@tonic-gate 	 * Actually remove the cleared symbols from namelist. We're not
1280Sstevel@tonic-gate 	 * truncating namelist by realloc, though.
1290Sstevel@tonic-gate 	 */
1300Sstevel@tonic-gate 	for (i = 0; (i < *nfuncs) && (nl[i].name != NULL); i++)
1310Sstevel@tonic-gate 		;
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	ndx = i;
1340Sstevel@tonic-gate 	for (i = ndx + 1; i < *nfuncs; i++) {
1350Sstevel@tonic-gate 		if (nl[i].name) {
1360Sstevel@tonic-gate 			nl[ndx] = nl[i];
1370Sstevel@tonic-gate 			ndx++;
1380Sstevel@tonic-gate 		}
1390Sstevel@tonic-gate 	}
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	*nfuncs = ndx;
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate int
cmp_by_address(const void * arg1,const void * arg2)145211Smike_s cmp_by_address(const void *arg1, const void *arg2)
1460Sstevel@tonic-gate {
147211Smike_s 	nltype *a = (nltype *)arg1;
148211Smike_s 	nltype *b = (nltype *)arg2;
149211Smike_s 
1500Sstevel@tonic-gate 	if (a->value < b->value)
1510Sstevel@tonic-gate 		return (-1);
1520Sstevel@tonic-gate 	else if (a->value > b->value)
1530Sstevel@tonic-gate 		return (1);
1540Sstevel@tonic-gate 	else
1550Sstevel@tonic-gate 		return (0);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate static int
is_function(Elf * elf,GElf_Sym * sym)1590Sstevel@tonic-gate is_function(Elf *elf, GElf_Sym *sym)
1600Sstevel@tonic-gate {
1610Sstevel@tonic-gate 	Elf_Scn		*scn;
1620Sstevel@tonic-gate 	GElf_Shdr	shdr;
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	/*
1650Sstevel@tonic-gate 	 * With dynamic linking, it is possible that certain undefined
1660Sstevel@tonic-gate 	 * symbols exist in the objects. The actual definition will be
1670Sstevel@tonic-gate 	 * found elsewhere, so we'll just skip it for this object.
1680Sstevel@tonic-gate 	 */
1690Sstevel@tonic-gate 	if (sym->st_shndx == SHN_UNDEF)
1700Sstevel@tonic-gate 		return (0);
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) {
1730Sstevel@tonic-gate 		if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL)
1740Sstevel@tonic-gate 			return (1);
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 		if (GELF_ST_BIND(sym->st_info) == STB_WEAK)
1770Sstevel@tonic-gate 			return (1);
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 		if (gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL)
1800Sstevel@tonic-gate 			return (1);
1810Sstevel@tonic-gate 	}
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	/*
1840Sstevel@tonic-gate 	 * It's not a function; determine if it's in an executable section.
1850Sstevel@tonic-gate 	 */
1860Sstevel@tonic-gate 	if (GELF_ST_TYPE(sym->st_info) != STT_NOTYPE)
1870Sstevel@tonic-gate 		return (0);
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	/*
1900Sstevel@tonic-gate 	 * If it isn't global, and it isn't weak, and it isn't
1910Sstevel@tonic-gate 	 * a 'local with the gflag set', then get out.
1920Sstevel@tonic-gate 	 */
1930Sstevel@tonic-gate 	if (GELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
1940Sstevel@tonic-gate 			GELF_ST_BIND(sym->st_info) != STB_WEAK &&
1950Sstevel@tonic-gate 			!(gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL))
1960Sstevel@tonic-gate 		return (0);
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	if (sym->st_shndx >= SHN_LORESERVE)
1990Sstevel@tonic-gate 		return (0);
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	scn = elf_getscn(elf, sym->st_shndx);
202211Smike_s 	(void) gelf_getshdr(scn, &shdr);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	if (!(shdr.sh_flags & SHF_EXECINSTR))
2050Sstevel@tonic-gate 		return (0);
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	return (1);
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate static void
fetch_symtab(Elf * elf,char * filename,mod_info_t * module)2110Sstevel@tonic-gate fetch_symtab(Elf *elf, char *filename, mod_info_t *module)
2120Sstevel@tonic-gate {
213*3621Sab196087 	Elf_Scn		*scn = NULL, *sym_pri = NULL, *sym_aux = NULL;
2140Sstevel@tonic-gate 	GElf_Word	strndx = 0;
2150Sstevel@tonic-gate 	size_t		i, nsyms, nfuncs;
216*3621Sab196087 	GElf_Xword	nsyms_pri, nsyms_aux = 0;
217*3621Sab196087 	Elf_Data	*symdata_pri, *symdata_aux;
2180Sstevel@tonic-gate 	nltype		*nl, *npe;
219*3621Sab196087 	int		symtab_found = 0;
2200Sstevel@tonic-gate 
221*3621Sab196087 
222*3621Sab196087 	/*
223*3621Sab196087 	 * Scan the section headers looking for a symbol table. Our
224*3621Sab196087 	 * preference is to use .symtab, because it contains the full
225*3621Sab196087 	 * set of symbols. If we find it, we stop looking immediately
226*3621Sab196087 	 * and use it. In the absence of a .symtab section, we are
227*3621Sab196087 	 * willing to use the dynamic symbol table (.dynsym), possibly
228*3621Sab196087 	 * augmented by the .SUNW_ldynsym, which contains local symbols.
229*3621Sab196087 	 */
230*3621Sab196087 	while ((symtab_found == 0) && ((scn = elf_nextscn(elf, scn)) != NULL)) {
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 		GElf_Shdr shdr;
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 		if (gelf_getshdr(scn, &shdr) == NULL)
2350Sstevel@tonic-gate 			continue;
2360Sstevel@tonic-gate 
237*3621Sab196087 		switch (shdr.sh_type) {
238*3621Sab196087 		case SHT_SYMTAB:
239*3621Sab196087 			nsyms_pri = shdr.sh_size / shdr.sh_entsize;
240*3621Sab196087 			strndx = shdr.sh_link;
241*3621Sab196087 			sym_pri = scn;
242*3621Sab196087 			/* Throw away .SUNW_ldynsym. It is for .dynsym only */
243*3621Sab196087 			nsyms_aux = 0;
244*3621Sab196087 			sym_aux = NULL;
245*3621Sab196087 			/* We have found the best symbol table. Stop looking */
246*3621Sab196087 			symtab_found = 1;
247*3621Sab196087 			break;
2480Sstevel@tonic-gate 
249*3621Sab196087 		case SHT_DYNSYM:
250*3621Sab196087 			/* We will use .dynsym if no .symtab is found */
251*3621Sab196087 			nsyms_pri = shdr.sh_size / shdr.sh_entsize;
2520Sstevel@tonic-gate 			strndx = shdr.sh_link;
253*3621Sab196087 			sym_pri = scn;
254*3621Sab196087 			break;
2550Sstevel@tonic-gate 
256*3621Sab196087 		case SHT_SUNW_LDYNSYM:
257*3621Sab196087 			/* Auxiliary table, used with .dynsym */
258*3621Sab196087 			nsyms_aux = shdr.sh_size / shdr.sh_entsize;
259*3621Sab196087 			sym_aux = scn;
2600Sstevel@tonic-gate 			break;
261*3621Sab196087 		}
2620Sstevel@tonic-gate 	}
2630Sstevel@tonic-gate 
264*3621Sab196087 	if (sym_pri == NULL || strndx == 0) {
265211Smike_s 		(void) fprintf(stderr, "%s: missing symbol table in %s\n",
2660Sstevel@tonic-gate 						    cmdname, filename);
2670Sstevel@tonic-gate 		exit(ERR_ELF);
2680Sstevel@tonic-gate 	}
2690Sstevel@tonic-gate 
270*3621Sab196087 	nsyms = (size_t)(nsyms_pri + nsyms_aux);
271*3621Sab196087 	if ((nsyms_pri + nsyms_aux) != (GElf_Xword)nsyms) {
272*3621Sab196087 		(void) fprintf(stderr,
273*3621Sab196087 		    "%s: can't handle more than 2^32 symbols", cmdname);
274*3621Sab196087 		exit(ERR_INPUT);
275*3621Sab196087 	}
276*3621Sab196087 
277*3621Sab196087 	if ((symdata_pri = elf_getdata(sym_pri, NULL)) == NULL) {
278211Smike_s 		(void) fprintf(stderr, "%s: can't read symbol data from %s\n",
279*3621Sab196087 		    cmdname, filename);
280*3621Sab196087 		exit(ERR_ELF);
281*3621Sab196087 	}
282*3621Sab196087 
283*3621Sab196087 	if ((sym_aux != NULL) &&
284*3621Sab196087 	    ((symdata_aux = elf_getdata(sym_aux, NULL)) == NULL)) {
285*3621Sab196087 		(void) fprintf(stderr,
286*3621Sab196087 		    "%s: can't read .SUNW_ldynsym symbol data from %s\n",
287*3621Sab196087 		    cmdname, filename);
2880Sstevel@tonic-gate 		exit(ERR_ELF);
2890Sstevel@tonic-gate 	}
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	if ((npe = nl = (nltype *) calloc(nsyms, sizeof (nltype))) == NULL) {
292211Smike_s 		(void) fprintf(stderr, "%s: can't alloc %x bytes for symbols\n",
2930Sstevel@tonic-gate 					cmdname, nsyms * sizeof (nltype));
2940Sstevel@tonic-gate 		exit(ERR_ELF);
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	/*
2980Sstevel@tonic-gate 	 * Now we need to cruise through the symbol table eliminating
2990Sstevel@tonic-gate 	 * all non-functions from consideration, and making strings
3000Sstevel@tonic-gate 	 * real.
3010Sstevel@tonic-gate 	 */
3020Sstevel@tonic-gate 	nfuncs = 0;
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	for (i = 1; i < nsyms; i++) {
3050Sstevel@tonic-gate 		GElf_Sym	gsym;
3060Sstevel@tonic-gate 		char		*name;
3070Sstevel@tonic-gate 
308*3621Sab196087 		/*
309*3621Sab196087 		 * Look up the symbol. In the case where we have a
310*3621Sab196087 		 * .SUNW_ldynsym/.dynsym pair, we treat them as a single
311*3621Sab196087 		 * logical table, with the data in .SUNW_ldynsym coming
312*3621Sab196087 		 * before the data in .dynsym.
313*3621Sab196087 		 */
314*3621Sab196087 		if (i >= nsyms_aux)
315*3621Sab196087 			(void) gelf_getsym(symdata_pri, i - nsyms_aux, &gsym);
316*3621Sab196087 		else
317*3621Sab196087 			(void) gelf_getsym(symdata_aux, i, &gsym);
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 		name = elf_strptr(elf, strndx, gsym.st_name);
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 		/*
3220Sstevel@tonic-gate 		 * We're interested in this symbol if it's a function
3230Sstevel@tonic-gate 		 */
3240Sstevel@tonic-gate 		if (is_function(elf, &gsym)) {
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 			npe->name = name;
3270Sstevel@tonic-gate 			npe->value = gsym.st_value;
3280Sstevel@tonic-gate 			npe->size = gsym.st_size;
3290Sstevel@tonic-gate 			npe->info = gsym.st_info;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 			npe++;
3320Sstevel@tonic-gate 			nfuncs++;
3330Sstevel@tonic-gate 		}
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 		if (strcmp(name, PRF_END) == 0)
3360Sstevel@tonic-gate 			module->data_end = gsym.st_value;
3370Sstevel@tonic-gate 	}
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	if (npe == nl) {
340211Smike_s 		(void) fprintf(stderr, "%s: no valid functions in %s\n",
3410Sstevel@tonic-gate 						    cmdname, filename);
3420Sstevel@tonic-gate 		exit(ERR_INPUT);
3430Sstevel@tonic-gate 	}
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	/*
3460Sstevel@tonic-gate 	 * And finally, sort the symbols by increasing address
3470Sstevel@tonic-gate 	 * and remove the duplicates.
3480Sstevel@tonic-gate 	 */
349211Smike_s 	qsort(nl, nfuncs, sizeof (nltype), cmp_by_address);
3500Sstevel@tonic-gate 	rm_dups(nl, &nfuncs);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	module->nl = nl;
3530Sstevel@tonic-gate 	module->nfuncs = nfuncs;
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate static GElf_Addr
get_txtorigin(Elf * elf,char * filename)3570Sstevel@tonic-gate get_txtorigin(Elf *elf, char *filename)
3580Sstevel@tonic-gate {
3590Sstevel@tonic-gate 	GElf_Ehdr	ehdr;
3600Sstevel@tonic-gate 	GElf_Phdr	phdr;
3610Sstevel@tonic-gate 	GElf_Half	ndx;
3620Sstevel@tonic-gate 	GElf_Addr	txt_origin = 0;
3630Sstevel@tonic-gate 	bool		first_load_seg = TRUE;
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
366211Smike_s 		(void) fprintf(stderr, "%s: can't read ELF header of %s\n",
3670Sstevel@tonic-gate 						    cmdname, filename);
3680Sstevel@tonic-gate 		exit(ERR_ELF);
3690Sstevel@tonic-gate 	}
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	for (ndx = 0; ndx < ehdr.e_phnum; ndx++) {
3720Sstevel@tonic-gate 		if (gelf_getphdr(elf, ndx, &phdr) == NULL)
3730Sstevel@tonic-gate 			continue;
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 		if ((phdr.p_type == PT_LOAD) && !(phdr.p_flags & PF_W)) {
3760Sstevel@tonic-gate 			if (first_load_seg || phdr.p_vaddr < txt_origin)
3770Sstevel@tonic-gate 				txt_origin = phdr.p_vaddr;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 			if (first_load_seg)
3800Sstevel@tonic-gate 				first_load_seg = FALSE;
3810Sstevel@tonic-gate 		}
3820Sstevel@tonic-gate 	}
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	return (txt_origin);
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate void
get_syms(char * filename,mod_info_t * mi)3880Sstevel@tonic-gate get_syms(char *filename, mod_info_t *mi)
3890Sstevel@tonic-gate {
3900Sstevel@tonic-gate 	int		fd;
3910Sstevel@tonic-gate 	Elf		*elf;
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	if ((fd = open(filename, O_RDONLY)) == -1) {
3940Sstevel@tonic-gate 		perror(filename);
3950Sstevel@tonic-gate 		exit(ERR_SYSCALL);
3960Sstevel@tonic-gate 	}
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
399211Smike_s 		(void) fprintf(stderr, "%s: libelf out of date\n", cmdname);
4000Sstevel@tonic-gate 		exit(ERR_ELF);
4010Sstevel@tonic-gate 	}
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
404211Smike_s 		(void) fprintf(stderr, "%s: elf_begin failed\n", cmdname);
4050Sstevel@tonic-gate 		exit(ERR_ELF);
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	if (gelf_getclass(elf) != ELFCLASS64) {
409211Smike_s 		(void) fprintf(stderr, "%s: unsupported mon.out format for "
4100Sstevel@tonic-gate 				    "this class of object\n", cmdname);
4110Sstevel@tonic-gate 		exit(ERR_ELF);
4120Sstevel@tonic-gate 	}
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	mi->txt_origin = get_txtorigin(elf, filename);
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	fetch_symtab(elf, filename, mi);
4170Sstevel@tonic-gate }
418