xref: /onnv-gate/usr/src/cmd/sgs/prof/common/rdelf.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright (c) 1998 by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All rights reserved.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*0Sstevel@tonic-gate 
28*0Sstevel@tonic-gate /*
29*0Sstevel@tonic-gate  * ELF support routines for processing versioned mon.out files.
30*0Sstevel@tonic-gate  */
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #include "profv.h"
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate bool
35*0Sstevel@tonic-gate is_shared_obj(char *name)
36*0Sstevel@tonic-gate {
37*0Sstevel@tonic-gate 	int		fd;
38*0Sstevel@tonic-gate 	Elf		*elf;
39*0Sstevel@tonic-gate 	GElf_Ehdr	ehdr;
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate 	if ((fd = open(name, O_RDONLY)) == -1) {
42*0Sstevel@tonic-gate 		fprintf(stderr, "%s: can't open `%s'\n", cmdname, name);
43*0Sstevel@tonic-gate 		exit(ERR_ELF);
44*0Sstevel@tonic-gate 	}
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
47*0Sstevel@tonic-gate 		fprintf(stderr, "%s: libelf out of date\n", cmdname);
48*0Sstevel@tonic-gate 		exit(ERR_ELF);
49*0Sstevel@tonic-gate 	}
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
52*0Sstevel@tonic-gate 		fprintf(stderr, "%s: elf_begin failed\n", cmdname);
53*0Sstevel@tonic-gate 		exit(ERR_ELF);
54*0Sstevel@tonic-gate 	}
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
57*0Sstevel@tonic-gate 		fprintf(stderr, "%s: can't read ELF header of %s\n",
58*0Sstevel@tonic-gate 								cmdname, name);
59*0Sstevel@tonic-gate 		exit(ERR_ELF);
60*0Sstevel@tonic-gate 	}
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate 	elf_end(elf);
63*0Sstevel@tonic-gate 	close(fd);
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate 	if (ehdr.e_type == ET_DYN)
66*0Sstevel@tonic-gate 		return (TRUE);
67*0Sstevel@tonic-gate 	else
68*0Sstevel@tonic-gate 		return (FALSE);
69*0Sstevel@tonic-gate }
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate static void
72*0Sstevel@tonic-gate rm_dups(nltype *nl, size_t *nfuncs)
73*0Sstevel@tonic-gate {
74*0Sstevel@tonic-gate 	size_t	i, prev = 0, ndx = 0;
75*0Sstevel@tonic-gate 	int	prev_type, prev_bind, cur_type;
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 	for (i = 1; i < *nfuncs; i++) {
78*0Sstevel@tonic-gate 		/*
79*0Sstevel@tonic-gate 		 * If current value is different from prev, proceed.
80*0Sstevel@tonic-gate 		 */
81*0Sstevel@tonic-gate 		if (nl[prev].value < nl[i].value) {
82*0Sstevel@tonic-gate 			prev = i;
83*0Sstevel@tonic-gate 			continue;
84*0Sstevel@tonic-gate 		}
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 		/*
87*0Sstevel@tonic-gate 		 * If current and prev have the syminfo, rm the latter.
88*0Sstevel@tonic-gate 		 */
89*0Sstevel@tonic-gate 		if (nl[prev].info == nl[i].info) {
90*0Sstevel@tonic-gate 			nl[i].name = NULL;
91*0Sstevel@tonic-gate 			continue;
92*0Sstevel@tonic-gate 		}
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 		prev_type = ELF_ST_TYPE(nl[prev].info);
95*0Sstevel@tonic-gate 		prev_bind = ELF_ST_BIND(nl[prev].info);
96*0Sstevel@tonic-gate 		cur_type = ELF_ST_TYPE(nl[i].info);
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 		/*
99*0Sstevel@tonic-gate 		 * Remove the one with STT_NOTYPE and keep the other.
100*0Sstevel@tonic-gate 		 */
101*0Sstevel@tonic-gate 		if (prev_type != cur_type) {
102*0Sstevel@tonic-gate 			if (prev_type != STT_NOTYPE)
103*0Sstevel@tonic-gate 				nl[i].name = NULL;
104*0Sstevel@tonic-gate 			else {
105*0Sstevel@tonic-gate 				nl[prev].name = NULL;
106*0Sstevel@tonic-gate 				prev = i;
107*0Sstevel@tonic-gate 			}
108*0Sstevel@tonic-gate 			continue;
109*0Sstevel@tonic-gate 		}
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 		/*
112*0Sstevel@tonic-gate 		 * If they have the same type, take the stronger bound
113*0Sstevel@tonic-gate 		 * function
114*0Sstevel@tonic-gate 		 */
115*0Sstevel@tonic-gate 		if (prev_bind != STB_WEAK)
116*0Sstevel@tonic-gate 			nl[i].name = NULL;
117*0Sstevel@tonic-gate 		else {
118*0Sstevel@tonic-gate 			nl[prev].name = NULL;
119*0Sstevel@tonic-gate 			prev = i;
120*0Sstevel@tonic-gate 		}
121*0Sstevel@tonic-gate 	}
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	/*
125*0Sstevel@tonic-gate 	 * Actually remove the cleared symbols from namelist. We're not
126*0Sstevel@tonic-gate 	 * truncating namelist by realloc, though.
127*0Sstevel@tonic-gate 	 */
128*0Sstevel@tonic-gate 	for (i = 0; (i < *nfuncs) && (nl[i].name != NULL); i++)
129*0Sstevel@tonic-gate 		;
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 	ndx = i;
132*0Sstevel@tonic-gate 	for (i = ndx + 1; i < *nfuncs; i++) {
133*0Sstevel@tonic-gate 		if (nl[i].name) {
134*0Sstevel@tonic-gate 			nl[ndx] = nl[i];
135*0Sstevel@tonic-gate 			ndx++;
136*0Sstevel@tonic-gate 		}
137*0Sstevel@tonic-gate 	}
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 	*nfuncs = ndx;
140*0Sstevel@tonic-gate }
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate int
143*0Sstevel@tonic-gate cmp_by_address(nltype *a, nltype *b)
144*0Sstevel@tonic-gate {
145*0Sstevel@tonic-gate 	if (a->value < b->value)
146*0Sstevel@tonic-gate 		return (-1);
147*0Sstevel@tonic-gate 	else if (a->value > b->value)
148*0Sstevel@tonic-gate 		return (1);
149*0Sstevel@tonic-gate 	else
150*0Sstevel@tonic-gate 		return (0);
151*0Sstevel@tonic-gate }
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate static int
154*0Sstevel@tonic-gate is_function(Elf *elf, GElf_Sym *sym)
155*0Sstevel@tonic-gate {
156*0Sstevel@tonic-gate 	Elf_Scn		*scn;
157*0Sstevel@tonic-gate 	GElf_Shdr	shdr;
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	/*
160*0Sstevel@tonic-gate 	 * With dynamic linking, it is possible that certain undefined
161*0Sstevel@tonic-gate 	 * symbols exist in the objects. The actual definition will be
162*0Sstevel@tonic-gate 	 * found elsewhere, so we'll just skip it for this object.
163*0Sstevel@tonic-gate 	 */
164*0Sstevel@tonic-gate 	if (sym->st_shndx == SHN_UNDEF)
165*0Sstevel@tonic-gate 		return (0);
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 	if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) {
168*0Sstevel@tonic-gate 		if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL)
169*0Sstevel@tonic-gate 			return (1);
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 		if (GELF_ST_BIND(sym->st_info) == STB_WEAK)
172*0Sstevel@tonic-gate 			return (1);
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 		if (gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL)
175*0Sstevel@tonic-gate 			return (1);
176*0Sstevel@tonic-gate 	}
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	/*
179*0Sstevel@tonic-gate 	 * It's not a function; determine if it's in an executable section.
180*0Sstevel@tonic-gate 	 */
181*0Sstevel@tonic-gate 	if (GELF_ST_TYPE(sym->st_info) != STT_NOTYPE)
182*0Sstevel@tonic-gate 		return (0);
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	/*
185*0Sstevel@tonic-gate 	 * If it isn't global, and it isn't weak, and it isn't
186*0Sstevel@tonic-gate 	 * a 'local with the gflag set', then get out.
187*0Sstevel@tonic-gate 	 */
188*0Sstevel@tonic-gate 	if (GELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
189*0Sstevel@tonic-gate 			GELF_ST_BIND(sym->st_info) != STB_WEAK &&
190*0Sstevel@tonic-gate 			!(gflag && GELF_ST_BIND(sym->st_info) == STB_LOCAL))
191*0Sstevel@tonic-gate 		return (0);
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	if (sym->st_shndx >= SHN_LORESERVE)
194*0Sstevel@tonic-gate 		return (0);
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	scn = elf_getscn(elf, sym->st_shndx);
197*0Sstevel@tonic-gate 	gelf_getshdr(scn, &shdr);
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 	if (!(shdr.sh_flags & SHF_EXECINSTR))
200*0Sstevel@tonic-gate 		return (0);
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	return (1);
203*0Sstevel@tonic-gate }
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate static void
206*0Sstevel@tonic-gate fetch_symtab(Elf *elf, char *filename, mod_info_t *module)
207*0Sstevel@tonic-gate {
208*0Sstevel@tonic-gate 	Elf_Scn		*scn = NULL, *sym = NULL;
209*0Sstevel@tonic-gate 	GElf_Word	strndx = 0;
210*0Sstevel@tonic-gate 	size_t		i, nsyms, nfuncs;
211*0Sstevel@tonic-gate 	Elf_Data	*symdata;
212*0Sstevel@tonic-gate 	nltype		*nl, *npe;
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	while ((scn = elf_nextscn(elf, scn)) != NULL) {
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 		GElf_Shdr shdr;
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 		if (gelf_getshdr(scn, &shdr) == NULL)
219*0Sstevel@tonic-gate 			continue;
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 		if (shdr.sh_type == SHT_SYMTAB ||
222*0Sstevel@tonic-gate 					shdr.sh_type == SHT_DYNSYM) {
223*0Sstevel@tonic-gate 			GElf_Xword chk = shdr.sh_size / shdr.sh_entsize;
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 			nsyms = (size_t) (shdr.sh_size / shdr.sh_entsize);
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 			if (chk != (GElf_Xword) nsyms) {
228*0Sstevel@tonic-gate 				fprintf(stderr, "%s: can't handle"
229*0Sstevel@tonic-gate 					"more than 2^32 symbols", cmdname);
230*0Sstevel@tonic-gate 				exit(ERR_INPUT);
231*0Sstevel@tonic-gate 			}
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 			strndx = shdr.sh_link;
234*0Sstevel@tonic-gate 			sym = scn;
235*0Sstevel@tonic-gate 		}
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 		/*
238*0Sstevel@tonic-gate 		 * If we've found a real symbol table, we're done.
239*0Sstevel@tonic-gate 		 */
240*0Sstevel@tonic-gate 		if (shdr.sh_type == SHT_SYMTAB)
241*0Sstevel@tonic-gate 			break;
242*0Sstevel@tonic-gate 	}
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 	if (sym == NULL || strndx == 0) {
245*0Sstevel@tonic-gate 		fprintf(stderr, "%s: missing symbol table in %s\n",
246*0Sstevel@tonic-gate 						    cmdname, filename);
247*0Sstevel@tonic-gate 		exit(ERR_ELF);
248*0Sstevel@tonic-gate 	}
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	if ((symdata = elf_getdata(scn, NULL)) == NULL) {
251*0Sstevel@tonic-gate 		fprintf(stderr, "%s: can't read symbol data from %s\n",
252*0Sstevel@tonic-gate 						    cmdname, filename);
253*0Sstevel@tonic-gate 		exit(ERR_ELF);
254*0Sstevel@tonic-gate 	}
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	if ((npe = nl = (nltype *) calloc(nsyms, sizeof (nltype))) == NULL) {
257*0Sstevel@tonic-gate 		fprintf(stderr, "%s: can't alloc %llx bytes for symbols\n",
258*0Sstevel@tonic-gate 					cmdname, nsyms * sizeof (nltype));
259*0Sstevel@tonic-gate 		exit(ERR_ELF);
260*0Sstevel@tonic-gate 	}
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	/*
263*0Sstevel@tonic-gate 	 * Now we need to cruise through the symbol table eliminating
264*0Sstevel@tonic-gate 	 * all non-functions from consideration, and making strings
265*0Sstevel@tonic-gate 	 * real.
266*0Sstevel@tonic-gate 	 */
267*0Sstevel@tonic-gate 	nfuncs = 0;
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	for (i = 1; i < nsyms; i++) {
270*0Sstevel@tonic-gate 		GElf_Sym	gsym;
271*0Sstevel@tonic-gate 		char		*name;
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 		gelf_getsym(symdata, i, &gsym);
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate 		name = elf_strptr(elf, strndx, gsym.st_name);
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 		/*
278*0Sstevel@tonic-gate 		 * We're interested in this symbol if it's a function
279*0Sstevel@tonic-gate 		 */
280*0Sstevel@tonic-gate 		if (is_function(elf, &gsym)) {
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 			npe->name = name;
283*0Sstevel@tonic-gate 			npe->value = gsym.st_value;
284*0Sstevel@tonic-gate 			npe->size = gsym.st_size;
285*0Sstevel@tonic-gate 			npe->info = gsym.st_info;
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 			npe++;
288*0Sstevel@tonic-gate 			nfuncs++;
289*0Sstevel@tonic-gate 		}
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 		if (strcmp(name, PRF_END) == 0)
292*0Sstevel@tonic-gate 			module->data_end = gsym.st_value;
293*0Sstevel@tonic-gate 	}
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 	if (npe == nl) {
296*0Sstevel@tonic-gate 		fprintf(stderr, "%s: no valid functions in %s\n",
297*0Sstevel@tonic-gate 						    cmdname, filename);
298*0Sstevel@tonic-gate 		exit(ERR_INPUT);
299*0Sstevel@tonic-gate 	}
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	/*
302*0Sstevel@tonic-gate 	 * And finally, sort the symbols by increasing address
303*0Sstevel@tonic-gate 	 * and remove the duplicates.
304*0Sstevel@tonic-gate 	 */
305*0Sstevel@tonic-gate 	qsort(nl, nfuncs, sizeof (nltype),
306*0Sstevel@tonic-gate 			(int(*)(const void *, const void *)) cmp_by_address);
307*0Sstevel@tonic-gate 	rm_dups(nl, &nfuncs);
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	module->nl = nl;
310*0Sstevel@tonic-gate 	module->nfuncs = nfuncs;
311*0Sstevel@tonic-gate }
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate static GElf_Addr
314*0Sstevel@tonic-gate get_txtorigin(Elf *elf, char *filename)
315*0Sstevel@tonic-gate {
316*0Sstevel@tonic-gate 	GElf_Ehdr	ehdr;
317*0Sstevel@tonic-gate 	GElf_Phdr	phdr;
318*0Sstevel@tonic-gate 	GElf_Half	ndx;
319*0Sstevel@tonic-gate 	GElf_Addr	txt_origin = 0;
320*0Sstevel@tonic-gate 	bool		first_load_seg = TRUE;
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
323*0Sstevel@tonic-gate 		fprintf(stderr, "%s: can't read ELF header of %s\n",
324*0Sstevel@tonic-gate 						    cmdname, filename);
325*0Sstevel@tonic-gate 		exit(ERR_ELF);
326*0Sstevel@tonic-gate 	}
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate 	for (ndx = 0; ndx < ehdr.e_phnum; ndx++) {
329*0Sstevel@tonic-gate 		if (gelf_getphdr(elf, ndx, &phdr) == NULL)
330*0Sstevel@tonic-gate 			continue;
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 		if ((phdr.p_type == PT_LOAD) && !(phdr.p_flags & PF_W)) {
333*0Sstevel@tonic-gate 			if (first_load_seg || phdr.p_vaddr < txt_origin)
334*0Sstevel@tonic-gate 				txt_origin = phdr.p_vaddr;
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 			if (first_load_seg)
337*0Sstevel@tonic-gate 				first_load_seg = FALSE;
338*0Sstevel@tonic-gate 		}
339*0Sstevel@tonic-gate 	}
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	return (txt_origin);
342*0Sstevel@tonic-gate }
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate void
345*0Sstevel@tonic-gate get_syms(char *filename, mod_info_t *mi)
346*0Sstevel@tonic-gate {
347*0Sstevel@tonic-gate 	int		fd;
348*0Sstevel@tonic-gate 	Elf		*elf;
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	if ((fd = open(filename, O_RDONLY)) == -1) {
351*0Sstevel@tonic-gate 		perror(filename);
352*0Sstevel@tonic-gate 		exit(ERR_SYSCALL);
353*0Sstevel@tonic-gate 	}
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
356*0Sstevel@tonic-gate 		fprintf(stderr, "%s: libelf out of date\n", cmdname);
357*0Sstevel@tonic-gate 		exit(ERR_ELF);
358*0Sstevel@tonic-gate 	}
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
361*0Sstevel@tonic-gate 		fprintf(stderr, "%s: elf_begin failed\n", cmdname);
362*0Sstevel@tonic-gate 		exit(ERR_ELF);
363*0Sstevel@tonic-gate 	}
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 	if (gelf_getclass(elf) != ELFCLASS64) {
366*0Sstevel@tonic-gate 		fprintf(stderr, "%s: unsupported mon.out format for "
367*0Sstevel@tonic-gate 				    "this class of object\n", cmdname);
368*0Sstevel@tonic-gate 		exit(ERR_ELF);
369*0Sstevel@tonic-gate 	}
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	mi->txt_origin = get_txtorigin(elf, filename);
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	fetch_symtab(elf, filename, mi);
374*0Sstevel@tonic-gate }
375