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 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdio.h>
30*0Sstevel@tonic-gate #include <stdlib.h>
31*0Sstevel@tonic-gate #include <stddef.h>
32*0Sstevel@tonic-gate #include <unistd.h>
33*0Sstevel@tonic-gate #include <ctype.h>
34*0Sstevel@tonic-gate #include <fcntl.h>
35*0Sstevel@tonic-gate #include <string.h>
36*0Sstevel@tonic-gate #include <strings.h>
37*0Sstevel@tonic-gate #include <memory.h>
38*0Sstevel@tonic-gate #include <errno.h>
39*0Sstevel@tonic-gate #include <dirent.h>
40*0Sstevel@tonic-gate #include <signal.h>
41*0Sstevel@tonic-gate #include <limits.h>
42*0Sstevel@tonic-gate #include <libgen.h>
43*0Sstevel@tonic-gate #include <zone.h>
44*0Sstevel@tonic-gate #include <sys/types.h>
45*0Sstevel@tonic-gate #include <sys/stat.h>
46*0Sstevel@tonic-gate #include <sys/systeminfo.h>
47*0Sstevel@tonic-gate #include <sys/sysmacros.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate #include "libproc.h"
50*0Sstevel@tonic-gate #include "Pcontrol.h"
51*0Sstevel@tonic-gate #include "Putil.h"
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate static file_info_t *build_map_symtab(struct ps_prochandle *, map_info_t *);
54*0Sstevel@tonic-gate static map_info_t *exec_map(struct ps_prochandle *);
55*0Sstevel@tonic-gate static map_info_t *object_to_map(struct ps_prochandle *, Lmid_t, const char *);
56*0Sstevel@tonic-gate static map_info_t *object_name_to_map(struct ps_prochandle *,
57*0Sstevel@tonic-gate 	Lmid_t, const char *);
58*0Sstevel@tonic-gate static GElf_Sym *sym_by_name(sym_tbl_t *, const char *, GElf_Sym *, uint_t *);
59*0Sstevel@tonic-gate static int read_ehdr32(struct ps_prochandle *, Elf32_Ehdr *, uintptr_t);
60*0Sstevel@tonic-gate #ifdef _LP64
61*0Sstevel@tonic-gate static int read_ehdr64(struct ps_prochandle *, Elf64_Ehdr *, uintptr_t);
62*0Sstevel@tonic-gate #endif
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate #define	DATA_TYPES	\
65*0Sstevel@tonic-gate 	((1 << STT_OBJECT) | (1 << STT_FUNC) | \
66*0Sstevel@tonic-gate 	(1 << STT_COMMON) | (1 << STT_TLS))
67*0Sstevel@tonic-gate #define	IS_DATA_TYPE(tp)	(((1 << (tp)) & DATA_TYPES) != 0)
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate #define	MA_RWX	(MA_READ | MA_WRITE | MA_EXEC)
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate typedef enum {
72*0Sstevel@tonic-gate 	PRO_NATURAL,
73*0Sstevel@tonic-gate 	PRO_BYADDR,
74*0Sstevel@tonic-gate 	PRO_BYNAME
75*0Sstevel@tonic-gate } pr_order_t;
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate static int
78*0Sstevel@tonic-gate addr_cmp(const void *aa, const void *bb)
79*0Sstevel@tonic-gate {
80*0Sstevel@tonic-gate 	uintptr_t a = *((uintptr_t *)aa);
81*0Sstevel@tonic-gate 	uintptr_t b = *((uintptr_t *)bb);
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 	if (a > b)
84*0Sstevel@tonic-gate 		return (1);
85*0Sstevel@tonic-gate 	if (a < b)
86*0Sstevel@tonic-gate 		return (-1);
87*0Sstevel@tonic-gate 	return (0);
88*0Sstevel@tonic-gate }
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate /*
91*0Sstevel@tonic-gate  * Allocation function for a new file_info_t
92*0Sstevel@tonic-gate  */
93*0Sstevel@tonic-gate static file_info_t *
94*0Sstevel@tonic-gate file_info_new(struct ps_prochandle *P, map_info_t *mptr)
95*0Sstevel@tonic-gate {
96*0Sstevel@tonic-gate 	file_info_t *fptr;
97*0Sstevel@tonic-gate 	map_info_t *mp;
98*0Sstevel@tonic-gate 	uintptr_t a, addr, *addrs, last = 0;
99*0Sstevel@tonic-gate 	uint_t i, j, naddrs = 0, unordered = 0;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	if ((fptr = calloc(1, sizeof (file_info_t))) == NULL)
102*0Sstevel@tonic-gate 		return (NULL);
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	list_link(fptr, &P->file_head);
105*0Sstevel@tonic-gate 	(void) strcpy(fptr->file_pname, mptr->map_pmap.pr_mapname);
106*0Sstevel@tonic-gate 	mptr->map_file = fptr;
107*0Sstevel@tonic-gate 	fptr->file_ref = 1;
108*0Sstevel@tonic-gate 	fptr->file_fd = -1;
109*0Sstevel@tonic-gate 	P->num_files++;
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	/*
112*0Sstevel@tonic-gate 	 * To figure out which map_info_t instances correspond to the mappings
113*0Sstevel@tonic-gate 	 * for this load object, we look at the in-memory ELF image in the
114*0Sstevel@tonic-gate 	 * base mapping (usually the program text). We examine the program
115*0Sstevel@tonic-gate 	 * headers to find the addresses at the beginning and end of each
116*0Sstevel@tonic-gate 	 * section and store them in a list which we then sort. Finally, we
117*0Sstevel@tonic-gate 	 * walk down the list of addresses and the list of map_info_t
118*0Sstevel@tonic-gate 	 * instances in lock step to correctly find the mappings that
119*0Sstevel@tonic-gate 	 * correspond to this load object.
120*0Sstevel@tonic-gate 	 */
121*0Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
122*0Sstevel@tonic-gate 		Elf32_Ehdr ehdr;
123*0Sstevel@tonic-gate 		Elf32_Phdr phdr;
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 		if (read_ehdr32(P, &ehdr, mptr->map_pmap.pr_vaddr) != 0)
126*0Sstevel@tonic-gate 			return (fptr);
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 		addrs = malloc(sizeof (uintptr_t) * ehdr.e_phnum * 2);
129*0Sstevel@tonic-gate 		a = mptr->map_pmap.pr_vaddr + ehdr.e_phoff;
130*0Sstevel@tonic-gate 		for (i = 0; i < ehdr.e_phnum; i++, a += ehdr.e_phentsize) {
131*0Sstevel@tonic-gate 			if (Pread(P, &phdr, sizeof (phdr), a) != sizeof (phdr))
132*0Sstevel@tonic-gate 				goto out;
133*0Sstevel@tonic-gate 			if (phdr.p_type != PT_LOAD || phdr.p_memsz == 0)
134*0Sstevel@tonic-gate 				continue;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 			addr = phdr.p_vaddr;
137*0Sstevel@tonic-gate 			if (ehdr.e_type == ET_DYN)
138*0Sstevel@tonic-gate 				addr += mptr->map_pmap.pr_vaddr;
139*0Sstevel@tonic-gate 			if (last > addr)
140*0Sstevel@tonic-gate 				unordered = 1;
141*0Sstevel@tonic-gate 			addrs[naddrs++] = addr;
142*0Sstevel@tonic-gate 			addrs[naddrs++] = last = addr + phdr.p_memsz - 1;
143*0Sstevel@tonic-gate 		}
144*0Sstevel@tonic-gate #ifdef _LP64
145*0Sstevel@tonic-gate 	} else {
146*0Sstevel@tonic-gate 		Elf64_Ehdr ehdr;
147*0Sstevel@tonic-gate 		Elf64_Phdr phdr;
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 		if (read_ehdr64(P, &ehdr, mptr->map_pmap.pr_vaddr) != 0)
150*0Sstevel@tonic-gate 			return (fptr);
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 		addrs = malloc(sizeof (uintptr_t) * ehdr.e_phnum * 2);
153*0Sstevel@tonic-gate 		a = mptr->map_pmap.pr_vaddr + ehdr.e_phoff;
154*0Sstevel@tonic-gate 		for (i = 0; i < ehdr.e_phnum; i++, a += ehdr.e_phentsize) {
155*0Sstevel@tonic-gate 			if (Pread(P, &phdr, sizeof (phdr), a) != sizeof (phdr))
156*0Sstevel@tonic-gate 				goto out;
157*0Sstevel@tonic-gate 			if (phdr.p_type != PT_LOAD || phdr.p_memsz == 0)
158*0Sstevel@tonic-gate 				continue;
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 			addr = phdr.p_vaddr;
161*0Sstevel@tonic-gate 			if (ehdr.e_type == ET_DYN)
162*0Sstevel@tonic-gate 				addr += mptr->map_pmap.pr_vaddr;
163*0Sstevel@tonic-gate 			if (last > addr)
164*0Sstevel@tonic-gate 				unordered = 1;
165*0Sstevel@tonic-gate 			addrs[naddrs++] = addr;
166*0Sstevel@tonic-gate 			addrs[naddrs++] = last = addr + phdr.p_memsz - 1;
167*0Sstevel@tonic-gate 		}
168*0Sstevel@tonic-gate #endif
169*0Sstevel@tonic-gate 	}
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	if (unordered)
172*0Sstevel@tonic-gate 		qsort(addrs, naddrs, sizeof (uintptr_t), addr_cmp);
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	i = j = 0;
176*0Sstevel@tonic-gate 	mp = P->mappings;
177*0Sstevel@tonic-gate 	while (j < P->map_count && i < naddrs) {
178*0Sstevel@tonic-gate 		addr = addrs[i];
179*0Sstevel@tonic-gate 		if (addr >= mp->map_pmap.pr_vaddr &&
180*0Sstevel@tonic-gate 		    addr < mp->map_pmap.pr_vaddr + mp->map_pmap.pr_size &&
181*0Sstevel@tonic-gate 		    mp->map_file == NULL) {
182*0Sstevel@tonic-gate 			mp->map_file = fptr;
183*0Sstevel@tonic-gate 			fptr->file_ref++;
184*0Sstevel@tonic-gate 		}
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 		if (addr < mp->map_pmap.pr_vaddr + mp->map_pmap.pr_size) {
187*0Sstevel@tonic-gate 			i++;
188*0Sstevel@tonic-gate 		} else {
189*0Sstevel@tonic-gate 			mp++;
190*0Sstevel@tonic-gate 			j++;
191*0Sstevel@tonic-gate 		}
192*0Sstevel@tonic-gate 	}
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate out:
195*0Sstevel@tonic-gate 	free(addrs);
196*0Sstevel@tonic-gate 	return (fptr);
197*0Sstevel@tonic-gate }
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate /*
200*0Sstevel@tonic-gate  * Deallocation function for a file_info_t
201*0Sstevel@tonic-gate  */
202*0Sstevel@tonic-gate static void
203*0Sstevel@tonic-gate file_info_free(struct ps_prochandle *P, file_info_t *fptr)
204*0Sstevel@tonic-gate {
205*0Sstevel@tonic-gate 	if (--fptr->file_ref == 0) {
206*0Sstevel@tonic-gate 		list_unlink(fptr);
207*0Sstevel@tonic-gate 		if (fptr->file_symtab.sym_elf) {
208*0Sstevel@tonic-gate 			(void) elf_end(fptr->file_symtab.sym_elf);
209*0Sstevel@tonic-gate 			free(fptr->file_symtab.sym_elfmem);
210*0Sstevel@tonic-gate 		}
211*0Sstevel@tonic-gate 		if (fptr->file_symtab.sym_byname)
212*0Sstevel@tonic-gate 			free(fptr->file_symtab.sym_byname);
213*0Sstevel@tonic-gate 		if (fptr->file_symtab.sym_byaddr)
214*0Sstevel@tonic-gate 			free(fptr->file_symtab.sym_byaddr);
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 		if (fptr->file_dynsym.sym_elf) {
217*0Sstevel@tonic-gate 			(void) elf_end(fptr->file_dynsym.sym_elf);
218*0Sstevel@tonic-gate 			free(fptr->file_dynsym.sym_elfmem);
219*0Sstevel@tonic-gate 		}
220*0Sstevel@tonic-gate 		if (fptr->file_dynsym.sym_byname)
221*0Sstevel@tonic-gate 			free(fptr->file_dynsym.sym_byname);
222*0Sstevel@tonic-gate 		if (fptr->file_dynsym.sym_byaddr)
223*0Sstevel@tonic-gate 			free(fptr->file_dynsym.sym_byaddr);
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 		if (fptr->file_lo)
226*0Sstevel@tonic-gate 			free(fptr->file_lo);
227*0Sstevel@tonic-gate 		if (fptr->file_lname)
228*0Sstevel@tonic-gate 			free(fptr->file_lname);
229*0Sstevel@tonic-gate 		if (fptr->file_elf)
230*0Sstevel@tonic-gate 			(void) elf_end(fptr->file_elf);
231*0Sstevel@tonic-gate 		if (fptr->file_elfmem != NULL)
232*0Sstevel@tonic-gate 			free(fptr->file_elfmem);
233*0Sstevel@tonic-gate 		if (fptr->file_fd >= 0)
234*0Sstevel@tonic-gate 			(void) close(fptr->file_fd);
235*0Sstevel@tonic-gate 		if (fptr->file_ctfp) {
236*0Sstevel@tonic-gate 			ctf_close(fptr->file_ctfp);
237*0Sstevel@tonic-gate 			free(fptr->file_ctf_buf);
238*0Sstevel@tonic-gate 		}
239*0Sstevel@tonic-gate 		free(fptr);
240*0Sstevel@tonic-gate 		P->num_files--;
241*0Sstevel@tonic-gate 	}
242*0Sstevel@tonic-gate }
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate /*
245*0Sstevel@tonic-gate  * Deallocation function for a map_info_t
246*0Sstevel@tonic-gate  */
247*0Sstevel@tonic-gate static void
248*0Sstevel@tonic-gate map_info_free(struct ps_prochandle *P, map_info_t *mptr)
249*0Sstevel@tonic-gate {
250*0Sstevel@tonic-gate 	file_info_t *fptr;
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 	if ((fptr = mptr->map_file) != NULL) {
253*0Sstevel@tonic-gate 		if (fptr->file_map == mptr)
254*0Sstevel@tonic-gate 			fptr->file_map = NULL;
255*0Sstevel@tonic-gate 		file_info_free(P, fptr);
256*0Sstevel@tonic-gate 	}
257*0Sstevel@tonic-gate 	if (P->execname && mptr == P->map_exec) {
258*0Sstevel@tonic-gate 		free(P->execname);
259*0Sstevel@tonic-gate 		P->execname = NULL;
260*0Sstevel@tonic-gate 	}
261*0Sstevel@tonic-gate 	if (P->auxv && (mptr == P->map_exec || mptr == P->map_ldso)) {
262*0Sstevel@tonic-gate 		free(P->auxv);
263*0Sstevel@tonic-gate 		P->auxv = NULL;
264*0Sstevel@tonic-gate 		P->nauxv = 0;
265*0Sstevel@tonic-gate 	}
266*0Sstevel@tonic-gate 	if (mptr == P->map_exec)
267*0Sstevel@tonic-gate 		P->map_exec = NULL;
268*0Sstevel@tonic-gate 	if (mptr == P->map_ldso)
269*0Sstevel@tonic-gate 		P->map_ldso = NULL;
270*0Sstevel@tonic-gate }
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate /*
273*0Sstevel@tonic-gate  * Call-back function for librtld_db to iterate through all of its shared
274*0Sstevel@tonic-gate  * libraries.  We use this to get the load object names for the mappings.
275*0Sstevel@tonic-gate  */
276*0Sstevel@tonic-gate static int
277*0Sstevel@tonic-gate map_iter(const rd_loadobj_t *lop, void *cd)
278*0Sstevel@tonic-gate {
279*0Sstevel@tonic-gate 	char buf[PATH_MAX];
280*0Sstevel@tonic-gate 	struct ps_prochandle *P = cd;
281*0Sstevel@tonic-gate 	map_info_t *mptr;
282*0Sstevel@tonic-gate 	file_info_t *fptr;
283*0Sstevel@tonic-gate 
284*0Sstevel@tonic-gate 	dprintf("encountered rd object at %p\n", (void *)lop->rl_base);
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 	if ((mptr = Paddr2mptr(P, lop->rl_base)) == NULL)
287*0Sstevel@tonic-gate 		return (1); /* Base address does not match any mapping */
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 	if ((fptr = mptr->map_file) == NULL &&
290*0Sstevel@tonic-gate 	    (fptr = file_info_new(P, mptr)) == NULL)
291*0Sstevel@tonic-gate 		return (1); /* Failed to allocate a new file_info_t */
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 	if ((fptr->file_lo == NULL) &&
294*0Sstevel@tonic-gate 	    (fptr->file_lo = malloc(sizeof (rd_loadobj_t))) == NULL) {
295*0Sstevel@tonic-gate 		file_info_free(P, fptr);
296*0Sstevel@tonic-gate 		return (1); /* Failed to allocate rd_loadobj_t */
297*0Sstevel@tonic-gate 	}
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 	fptr->file_map = mptr;
300*0Sstevel@tonic-gate 	*fptr->file_lo = *lop;
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	fptr->file_lo->rl_plt_base = fptr->file_plt_base;
303*0Sstevel@tonic-gate 	fptr->file_lo->rl_plt_size = fptr->file_plt_size;
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	if (fptr->file_lname) {
306*0Sstevel@tonic-gate 		free(fptr->file_lname);
307*0Sstevel@tonic-gate 		fptr->file_lname = NULL;
308*0Sstevel@tonic-gate 	}
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	if (Pread_string(P, buf, sizeof (buf), lop->rl_nameaddr) > 0) {
311*0Sstevel@tonic-gate 		if ((fptr->file_lname = strdup(buf)) != NULL)
312*0Sstevel@tonic-gate 			fptr->file_lbase = basename(fptr->file_lname);
313*0Sstevel@tonic-gate 	}
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 	dprintf("loaded rd object %s lmid %lx\n",
316*0Sstevel@tonic-gate 	    fptr->file_lname ? fptr->file_lname : "<NULL>", lop->rl_lmident);
317*0Sstevel@tonic-gate 	return (1);
318*0Sstevel@tonic-gate }
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate static void
321*0Sstevel@tonic-gate map_set(struct ps_prochandle *P, map_info_t *mptr, const char *lname)
322*0Sstevel@tonic-gate {
323*0Sstevel@tonic-gate 	file_info_t *fptr;
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	if ((fptr = mptr->map_file) == NULL &&
326*0Sstevel@tonic-gate 	    (fptr = file_info_new(P, mptr)) == NULL)
327*0Sstevel@tonic-gate 		return; /* Failed to allocate a new file_info_t */
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	fptr->file_map = mptr;
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 	if ((fptr->file_lo == NULL) &&
332*0Sstevel@tonic-gate 	    (fptr->file_lo = malloc(sizeof (rd_loadobj_t))) == NULL) {
333*0Sstevel@tonic-gate 		file_info_free(P, fptr);
334*0Sstevel@tonic-gate 		return; /* Failed to allocate rd_loadobj_t */
335*0Sstevel@tonic-gate 	}
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	(void) memset(fptr->file_lo, 0, sizeof (rd_loadobj_t));
338*0Sstevel@tonic-gate 	fptr->file_lo->rl_base = mptr->map_pmap.pr_vaddr;
339*0Sstevel@tonic-gate 	fptr->file_lo->rl_bend =
340*0Sstevel@tonic-gate 		mptr->map_pmap.pr_vaddr + mptr->map_pmap.pr_size;
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	fptr->file_lo->rl_plt_base = fptr->file_plt_base;
343*0Sstevel@tonic-gate 	fptr->file_lo->rl_plt_size = fptr->file_plt_size;
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 	if (fptr->file_lname) {
346*0Sstevel@tonic-gate 		free(fptr->file_lname);
347*0Sstevel@tonic-gate 		fptr->file_lname = NULL;
348*0Sstevel@tonic-gate 	}
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	if ((fptr->file_lname = strdup(lname)) != NULL)
351*0Sstevel@tonic-gate 		fptr->file_lbase = basename(fptr->file_lname);
352*0Sstevel@tonic-gate }
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate static void
355*0Sstevel@tonic-gate load_static_maps(struct ps_prochandle *P)
356*0Sstevel@tonic-gate {
357*0Sstevel@tonic-gate 	map_info_t *mptr;
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	/*
360*0Sstevel@tonic-gate 	 * Construct the map for the a.out.
361*0Sstevel@tonic-gate 	 */
362*0Sstevel@tonic-gate 	if ((mptr = object_name_to_map(P, PR_LMID_EVERY, PR_OBJ_EXEC)) != NULL)
363*0Sstevel@tonic-gate 		map_set(P, mptr, "a.out");
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 	/*
366*0Sstevel@tonic-gate 	 * If the dynamic linker exists for this process,
367*0Sstevel@tonic-gate 	 * construct the map for it.
368*0Sstevel@tonic-gate 	 */
369*0Sstevel@tonic-gate 	if (Pgetauxval(P, AT_BASE) != -1L &&
370*0Sstevel@tonic-gate 	    (mptr = object_name_to_map(P, PR_LMID_EVERY, PR_OBJ_LDSO)) != NULL)
371*0Sstevel@tonic-gate 		map_set(P, mptr, "ld.so.1");
372*0Sstevel@tonic-gate }
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate /*
375*0Sstevel@tonic-gate  * Go through all the address space mappings, validating or updating
376*0Sstevel@tonic-gate  * the information already gathered, or gathering new information.
377*0Sstevel@tonic-gate  *
378*0Sstevel@tonic-gate  * This function is only called when we suspect that the mappings have changed
379*0Sstevel@tonic-gate  * because this is the first time we're calling it or because of rtld activity.
380*0Sstevel@tonic-gate  */
381*0Sstevel@tonic-gate void
382*0Sstevel@tonic-gate Pupdate_maps(struct ps_prochandle *P)
383*0Sstevel@tonic-gate {
384*0Sstevel@tonic-gate 	char mapfile[64];
385*0Sstevel@tonic-gate 	int mapfd;
386*0Sstevel@tonic-gate 	struct stat statb;
387*0Sstevel@tonic-gate 	prmap_t *Pmap = NULL;
388*0Sstevel@tonic-gate 	prmap_t *pmap;
389*0Sstevel@tonic-gate 	ssize_t nmap;
390*0Sstevel@tonic-gate 	int i;
391*0Sstevel@tonic-gate 	uint_t oldmapcount;
392*0Sstevel@tonic-gate 	map_info_t *newmap, *newp;
393*0Sstevel@tonic-gate 	map_info_t *mptr;
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	if (P->info_valid)
396*0Sstevel@tonic-gate 		return;
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 	Preadauxvec(P);
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	(void) sprintf(mapfile, "/proc/%d/map", (int)P->pid);
401*0Sstevel@tonic-gate 	if ((mapfd = open(mapfile, O_RDONLY)) < 0 ||
402*0Sstevel@tonic-gate 	    fstat(mapfd, &statb) != 0 ||
403*0Sstevel@tonic-gate 	    statb.st_size < sizeof (prmap_t) ||
404*0Sstevel@tonic-gate 	    (Pmap = malloc(statb.st_size)) == NULL ||
405*0Sstevel@tonic-gate 	    (nmap = pread(mapfd, Pmap, statb.st_size, 0L)) <= 0 ||
406*0Sstevel@tonic-gate 	    (nmap /= sizeof (prmap_t)) == 0) {
407*0Sstevel@tonic-gate 		if (Pmap != NULL)
408*0Sstevel@tonic-gate 			free(Pmap);
409*0Sstevel@tonic-gate 		if (mapfd >= 0)
410*0Sstevel@tonic-gate 			(void) close(mapfd);
411*0Sstevel@tonic-gate 		Preset_maps(P);	/* utter failure; destroy tables */
412*0Sstevel@tonic-gate 		return;
413*0Sstevel@tonic-gate 	}
414*0Sstevel@tonic-gate 	(void) close(mapfd);
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 	if ((newmap = calloc(1, nmap * sizeof (map_info_t))) == NULL)
417*0Sstevel@tonic-gate 		return;
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate 	/*
420*0Sstevel@tonic-gate 	 * We try to merge any file information we may have for existing
421*0Sstevel@tonic-gate 	 * mappings, to avoid having to rebuild the file info.
422*0Sstevel@tonic-gate 	 */
423*0Sstevel@tonic-gate 	mptr = P->mappings;
424*0Sstevel@tonic-gate 	pmap = Pmap;
425*0Sstevel@tonic-gate 	newp = newmap;
426*0Sstevel@tonic-gate 	oldmapcount = P->map_count;
427*0Sstevel@tonic-gate 	for (i = 0; i < nmap; i++, pmap++, newp++) {
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 		if (oldmapcount == 0) {
430*0Sstevel@tonic-gate 			/*
431*0Sstevel@tonic-gate 			 * We've exhausted all the old mappings.  Every new
432*0Sstevel@tonic-gate 			 * mapping should be added.
433*0Sstevel@tonic-gate 			 */
434*0Sstevel@tonic-gate 			newp->map_pmap = *pmap;
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 		} else if (pmap->pr_vaddr == mptr->map_pmap.pr_vaddr &&
437*0Sstevel@tonic-gate 		    pmap->pr_size == mptr->map_pmap.pr_size &&
438*0Sstevel@tonic-gate 		    pmap->pr_offset == mptr->map_pmap.pr_offset &&
439*0Sstevel@tonic-gate 		    (pmap->pr_mflags & ~(MA_BREAK | MA_STACK)) ==
440*0Sstevel@tonic-gate 		    (mptr->map_pmap.pr_mflags & ~(MA_BREAK | MA_STACK)) &&
441*0Sstevel@tonic-gate 		    pmap->pr_pagesize == mptr->map_pmap.pr_pagesize &&
442*0Sstevel@tonic-gate 		    pmap->pr_shmid == mptr->map_pmap.pr_shmid &&
443*0Sstevel@tonic-gate 		    strcmp(pmap->pr_mapname, mptr->map_pmap.pr_mapname) == 0) {
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 			/*
446*0Sstevel@tonic-gate 			 * This mapping matches exactly.  Copy over the old
447*0Sstevel@tonic-gate 			 * mapping, taking care to get the latest flags.
448*0Sstevel@tonic-gate 			 * Make sure the associated file_info_t is updated
449*0Sstevel@tonic-gate 			 * appropriately.
450*0Sstevel@tonic-gate 			 */
451*0Sstevel@tonic-gate 			*newp = *mptr;
452*0Sstevel@tonic-gate 			if (P->map_exec == mptr)
453*0Sstevel@tonic-gate 				P->map_exec = newp;
454*0Sstevel@tonic-gate 			if (P->map_ldso == mptr)
455*0Sstevel@tonic-gate 				P->map_ldso = newp;
456*0Sstevel@tonic-gate 			newp->map_pmap.pr_mflags = pmap->pr_mflags;
457*0Sstevel@tonic-gate 			if (mptr->map_file != NULL &&
458*0Sstevel@tonic-gate 			    mptr->map_file->file_map == mptr)
459*0Sstevel@tonic-gate 				mptr->map_file->file_map = newp;
460*0Sstevel@tonic-gate 			oldmapcount--;
461*0Sstevel@tonic-gate 			mptr++;
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 		} else if (pmap->pr_vaddr + pmap->pr_size >
464*0Sstevel@tonic-gate 		    mptr->map_pmap.pr_vaddr) {
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 			/*
467*0Sstevel@tonic-gate 			 * The old mapping doesn't exist any more, remove it
468*0Sstevel@tonic-gate 			 * from the list.
469*0Sstevel@tonic-gate 			 */
470*0Sstevel@tonic-gate 			map_info_free(P, mptr);
471*0Sstevel@tonic-gate 			oldmapcount--;
472*0Sstevel@tonic-gate 			i--;
473*0Sstevel@tonic-gate 			newp--;
474*0Sstevel@tonic-gate 			pmap--;
475*0Sstevel@tonic-gate 			mptr++;
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 		} else {
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 			/*
480*0Sstevel@tonic-gate 			 * This is a new mapping, add it directly.
481*0Sstevel@tonic-gate 			 */
482*0Sstevel@tonic-gate 			newp->map_pmap = *pmap;
483*0Sstevel@tonic-gate 		}
484*0Sstevel@tonic-gate 	}
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 	/*
487*0Sstevel@tonic-gate 	 * Free any old maps
488*0Sstevel@tonic-gate 	 */
489*0Sstevel@tonic-gate 	while (oldmapcount) {
490*0Sstevel@tonic-gate 		map_info_free(P, mptr);
491*0Sstevel@tonic-gate 		oldmapcount--;
492*0Sstevel@tonic-gate 		mptr++;
493*0Sstevel@tonic-gate 	}
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 	free(Pmap);
496*0Sstevel@tonic-gate 	if (P->mappings != NULL)
497*0Sstevel@tonic-gate 		free(P->mappings);
498*0Sstevel@tonic-gate 	P->mappings = newmap;
499*0Sstevel@tonic-gate 	P->map_count = P->map_alloc = nmap;
500*0Sstevel@tonic-gate 	P->info_valid = 1;
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	/*
503*0Sstevel@tonic-gate 	 * Consult librtld_db to get the load object
504*0Sstevel@tonic-gate 	 * names for all of the shared libraries.
505*0Sstevel@tonic-gate 	 */
506*0Sstevel@tonic-gate 	if (P->rap != NULL)
507*0Sstevel@tonic-gate 		(void) rd_loadobj_iter(P->rap, map_iter, P);
508*0Sstevel@tonic-gate }
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate /*
511*0Sstevel@tonic-gate  * Update all of the mappings and rtld_db as if by Pupdate_maps(), and then
512*0Sstevel@tonic-gate  * forcibly cache all of the symbol tables associated with all object files.
513*0Sstevel@tonic-gate  */
514*0Sstevel@tonic-gate void
515*0Sstevel@tonic-gate Pupdate_syms(struct ps_prochandle *P)
516*0Sstevel@tonic-gate {
517*0Sstevel@tonic-gate 	file_info_t *fptr = list_next(&P->file_head);
518*0Sstevel@tonic-gate 	int i;
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate 	Pupdate_maps(P);
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 	for (i = 0; i < P->num_files; i++, fptr = list_next(fptr)) {
523*0Sstevel@tonic-gate 		Pbuild_file_symtab(P, fptr);
524*0Sstevel@tonic-gate 		(void) Pbuild_file_ctf(P, fptr);
525*0Sstevel@tonic-gate 	}
526*0Sstevel@tonic-gate }
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate /*
529*0Sstevel@tonic-gate  * Return the librtld_db agent handle for the victim process.
530*0Sstevel@tonic-gate  * The handle will become invalid at the next successful exec() and the
531*0Sstevel@tonic-gate  * client (caller of proc_rd_agent()) must not use it beyond that point.
532*0Sstevel@tonic-gate  * If the process is already dead, we've already tried our best to
533*0Sstevel@tonic-gate  * create the agent during core file initialization.
534*0Sstevel@tonic-gate  */
535*0Sstevel@tonic-gate rd_agent_t *
536*0Sstevel@tonic-gate Prd_agent(struct ps_prochandle *P)
537*0Sstevel@tonic-gate {
538*0Sstevel@tonic-gate 	if (P->rap == NULL && P->state != PS_DEAD && P->state != PS_IDLE) {
539*0Sstevel@tonic-gate 		Pupdate_maps(P);
540*0Sstevel@tonic-gate 		if (P->num_files == 0)
541*0Sstevel@tonic-gate 			load_static_maps(P);
542*0Sstevel@tonic-gate 		rd_log(_libproc_debug);
543*0Sstevel@tonic-gate 		if ((P->rap = rd_new(P)) != NULL)
544*0Sstevel@tonic-gate 			(void) rd_loadobj_iter(P->rap, map_iter, P);
545*0Sstevel@tonic-gate 	}
546*0Sstevel@tonic-gate 	return (P->rap);
547*0Sstevel@tonic-gate }
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate /*
550*0Sstevel@tonic-gate  * Return the prmap_t structure containing 'addr', but only if it
551*0Sstevel@tonic-gate  * is in the dynamic linker's link map and is the text section.
552*0Sstevel@tonic-gate  */
553*0Sstevel@tonic-gate const prmap_t *
554*0Sstevel@tonic-gate Paddr_to_text_map(struct ps_prochandle *P, uintptr_t addr)
555*0Sstevel@tonic-gate {
556*0Sstevel@tonic-gate 	map_info_t *mptr;
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 	if (!P->info_valid)
559*0Sstevel@tonic-gate 		Pupdate_maps(P);
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 	if ((mptr = Paddr2mptr(P, addr)) != NULL) {
562*0Sstevel@tonic-gate 		file_info_t *fptr = build_map_symtab(P, mptr);
563*0Sstevel@tonic-gate 		const prmap_t *pmp = &mptr->map_pmap;
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 		if (fptr != NULL && fptr->file_lo != NULL &&
566*0Sstevel@tonic-gate 		    fptr->file_lo->rl_base >= pmp->pr_vaddr &&
567*0Sstevel@tonic-gate 		    fptr->file_lo->rl_base < pmp->pr_vaddr + pmp->pr_size)
568*0Sstevel@tonic-gate 			return (pmp);
569*0Sstevel@tonic-gate 	}
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	return (NULL);
572*0Sstevel@tonic-gate }
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate /*
575*0Sstevel@tonic-gate  * Return the prmap_t structure containing 'addr' (no restrictions on
576*0Sstevel@tonic-gate  * the type of mapping).
577*0Sstevel@tonic-gate  */
578*0Sstevel@tonic-gate const prmap_t *
579*0Sstevel@tonic-gate Paddr_to_map(struct ps_prochandle *P, uintptr_t addr)
580*0Sstevel@tonic-gate {
581*0Sstevel@tonic-gate 	map_info_t *mptr;
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 	if (!P->info_valid)
584*0Sstevel@tonic-gate 		Pupdate_maps(P);
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	if ((mptr = Paddr2mptr(P, addr)) != NULL)
587*0Sstevel@tonic-gate 		return (&mptr->map_pmap);
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 	return (NULL);
590*0Sstevel@tonic-gate }
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate /*
593*0Sstevel@tonic-gate  * Convert a full or partial load object name to the prmap_t for its
594*0Sstevel@tonic-gate  * corresponding primary text mapping.
595*0Sstevel@tonic-gate  */
596*0Sstevel@tonic-gate const prmap_t *
597*0Sstevel@tonic-gate Plmid_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *name)
598*0Sstevel@tonic-gate {
599*0Sstevel@tonic-gate 	map_info_t *mptr;
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 	if (name == PR_OBJ_EVERY)
602*0Sstevel@tonic-gate 		return (NULL); /* A reasonable mistake */
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	if ((mptr = object_name_to_map(P, lmid, name)) != NULL)
605*0Sstevel@tonic-gate 		return (&mptr->map_pmap);
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate 	return (NULL);
608*0Sstevel@tonic-gate }
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate const prmap_t *
611*0Sstevel@tonic-gate Pname_to_map(struct ps_prochandle *P, const char *name)
612*0Sstevel@tonic-gate {
613*0Sstevel@tonic-gate 	return (Plmid_to_map(P, PR_LMID_EVERY, name));
614*0Sstevel@tonic-gate }
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate const rd_loadobj_t *
617*0Sstevel@tonic-gate Paddr_to_loadobj(struct ps_prochandle *P, uintptr_t addr)
618*0Sstevel@tonic-gate {
619*0Sstevel@tonic-gate 	map_info_t *mptr;
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 	if (!P->info_valid)
622*0Sstevel@tonic-gate 		Pupdate_maps(P);
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 	if ((mptr = Paddr2mptr(P, addr)) == NULL)
625*0Sstevel@tonic-gate 		return (NULL);
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 	/*
628*0Sstevel@tonic-gate 	 * By building the symbol table, we implicitly bring the PLT
629*0Sstevel@tonic-gate 	 * information up to date in the load object.
630*0Sstevel@tonic-gate 	 */
631*0Sstevel@tonic-gate 	(void) build_map_symtab(P, mptr);
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	return (mptr->map_file->file_lo);
634*0Sstevel@tonic-gate }
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate const rd_loadobj_t *
637*0Sstevel@tonic-gate Plmid_to_loadobj(struct ps_prochandle *P, Lmid_t lmid, const char *name)
638*0Sstevel@tonic-gate {
639*0Sstevel@tonic-gate 	map_info_t *mptr;
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 	if (name == PR_OBJ_EVERY)
642*0Sstevel@tonic-gate 		return (NULL);
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 	if ((mptr = object_name_to_map(P, lmid, name)) == NULL)
645*0Sstevel@tonic-gate 		return (NULL);
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	/*
648*0Sstevel@tonic-gate 	 * By building the symbol table, we implicitly bring the PLT
649*0Sstevel@tonic-gate 	 * information up to date in the load object.
650*0Sstevel@tonic-gate 	 */
651*0Sstevel@tonic-gate 	(void) build_map_symtab(P, mptr);
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	return (mptr->map_file->file_lo);
654*0Sstevel@tonic-gate }
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate const rd_loadobj_t *
657*0Sstevel@tonic-gate Pname_to_loadobj(struct ps_prochandle *P, const char *name)
658*0Sstevel@tonic-gate {
659*0Sstevel@tonic-gate 	return (Plmid_to_loadobj(P, PR_LMID_EVERY, name));
660*0Sstevel@tonic-gate }
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate ctf_file_t *
663*0Sstevel@tonic-gate Pbuild_file_ctf(struct ps_prochandle *P, file_info_t *fptr)
664*0Sstevel@tonic-gate {
665*0Sstevel@tonic-gate 	ctf_sect_t ctdata, symtab, strtab;
666*0Sstevel@tonic-gate 	sym_tbl_t *symp;
667*0Sstevel@tonic-gate 	int err;
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	if (fptr->file_ctfp != NULL)
670*0Sstevel@tonic-gate 		return (fptr->file_ctfp);
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 	Pbuild_file_symtab(P, fptr);
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 	if (fptr->file_ctf_size == 0)
675*0Sstevel@tonic-gate 		return (NULL);
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 	symp = fptr->file_ctf_dyn ? &fptr->file_dynsym : &fptr->file_symtab;
678*0Sstevel@tonic-gate 	if (symp->sym_data == NULL)
679*0Sstevel@tonic-gate 		return (NULL);
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 	/*
682*0Sstevel@tonic-gate 	 * The buffer may alread be allocated if this is a core file that
683*0Sstevel@tonic-gate 	 * contained CTF data for this file.
684*0Sstevel@tonic-gate 	 */
685*0Sstevel@tonic-gate 	if (fptr->file_ctf_buf == NULL) {
686*0Sstevel@tonic-gate 		fptr->file_ctf_buf = malloc(fptr->file_ctf_size);
687*0Sstevel@tonic-gate 		if (fptr->file_ctf_buf == NULL) {
688*0Sstevel@tonic-gate 			dprintf("failed to allocate ctf buffer\n");
689*0Sstevel@tonic-gate 			return (NULL);
690*0Sstevel@tonic-gate 		}
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 		if (pread(fptr->file_fd, fptr->file_ctf_buf,
693*0Sstevel@tonic-gate 		    fptr->file_ctf_size, fptr->file_ctf_off) !=
694*0Sstevel@tonic-gate 		    fptr->file_ctf_size) {
695*0Sstevel@tonic-gate 			free(fptr->file_ctf_buf);
696*0Sstevel@tonic-gate 			fptr->file_ctf_buf = NULL;
697*0Sstevel@tonic-gate 			dprintf("failed to read ctf data\n");
698*0Sstevel@tonic-gate 			return (NULL);
699*0Sstevel@tonic-gate 		}
700*0Sstevel@tonic-gate 	}
701*0Sstevel@tonic-gate 
702*0Sstevel@tonic-gate 	ctdata.cts_name = ".SUNW_ctf";
703*0Sstevel@tonic-gate 	ctdata.cts_type = SHT_PROGBITS;
704*0Sstevel@tonic-gate 	ctdata.cts_flags = 0;
705*0Sstevel@tonic-gate 	ctdata.cts_data = fptr->file_ctf_buf;
706*0Sstevel@tonic-gate 	ctdata.cts_size = fptr->file_ctf_size;
707*0Sstevel@tonic-gate 	ctdata.cts_entsize = 1;
708*0Sstevel@tonic-gate 	ctdata.cts_offset = 0;
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate 	symtab.cts_name = fptr->file_ctf_dyn ? ".dynsym" : ".symtab";
711*0Sstevel@tonic-gate 	symtab.cts_type = symp->sym_hdr.sh_type;
712*0Sstevel@tonic-gate 	symtab.cts_flags = symp->sym_hdr.sh_flags;
713*0Sstevel@tonic-gate 	symtab.cts_data = symp->sym_data->d_buf;
714*0Sstevel@tonic-gate 	symtab.cts_size = symp->sym_hdr.sh_size;
715*0Sstevel@tonic-gate 	symtab.cts_entsize = symp->sym_hdr.sh_entsize;
716*0Sstevel@tonic-gate 	symtab.cts_offset = symp->sym_hdr.sh_offset;
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 	strtab.cts_name = fptr->file_ctf_dyn ? ".dynstr" : ".strtab";
719*0Sstevel@tonic-gate 	strtab.cts_type = symp->sym_strhdr.sh_type;
720*0Sstevel@tonic-gate 	strtab.cts_flags = symp->sym_strhdr.sh_flags;
721*0Sstevel@tonic-gate 	strtab.cts_data = symp->sym_strs;
722*0Sstevel@tonic-gate 	strtab.cts_size = symp->sym_strhdr.sh_size;
723*0Sstevel@tonic-gate 	strtab.cts_entsize = symp->sym_strhdr.sh_entsize;
724*0Sstevel@tonic-gate 	strtab.cts_offset = symp->sym_strhdr.sh_offset;
725*0Sstevel@tonic-gate 
726*0Sstevel@tonic-gate 	fptr->file_ctfp = ctf_bufopen(&ctdata, &symtab, &strtab, &err);
727*0Sstevel@tonic-gate 	if (fptr->file_ctfp == NULL) {
728*0Sstevel@tonic-gate 		free(fptr->file_ctf_buf);
729*0Sstevel@tonic-gate 		fptr->file_ctf_buf = NULL;
730*0Sstevel@tonic-gate 		return (NULL);
731*0Sstevel@tonic-gate 	}
732*0Sstevel@tonic-gate 
733*0Sstevel@tonic-gate 	dprintf("loaded %lu bytes of CTF data for %s\n",
734*0Sstevel@tonic-gate 	    (ulong_t)fptr->file_ctf_size, fptr->file_pname);
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 	return (fptr->file_ctfp);
737*0Sstevel@tonic-gate }
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate ctf_file_t *
740*0Sstevel@tonic-gate Paddr_to_ctf(struct ps_prochandle *P, uintptr_t addr)
741*0Sstevel@tonic-gate {
742*0Sstevel@tonic-gate 	map_info_t *mptr;
743*0Sstevel@tonic-gate 	file_info_t *fptr;
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	if (!P->info_valid)
746*0Sstevel@tonic-gate 		Pupdate_maps(P);
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate 	if ((mptr = Paddr2mptr(P, addr)) == NULL ||
749*0Sstevel@tonic-gate 	    (fptr = mptr->map_file) == NULL)
750*0Sstevel@tonic-gate 		return (NULL);
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate 	return (Pbuild_file_ctf(P, fptr));
753*0Sstevel@tonic-gate }
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate ctf_file_t *
756*0Sstevel@tonic-gate Plmid_to_ctf(struct ps_prochandle *P, Lmid_t lmid, const char *name)
757*0Sstevel@tonic-gate {
758*0Sstevel@tonic-gate 	map_info_t *mptr;
759*0Sstevel@tonic-gate 	file_info_t *fptr;
760*0Sstevel@tonic-gate 
761*0Sstevel@tonic-gate 	if (name == PR_OBJ_EVERY)
762*0Sstevel@tonic-gate 		return (NULL);
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate 	if ((mptr = object_name_to_map(P, lmid, name)) == NULL ||
765*0Sstevel@tonic-gate 	    (fptr = mptr->map_file) == NULL)
766*0Sstevel@tonic-gate 		return (NULL);
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate 	return (Pbuild_file_ctf(P, fptr));
769*0Sstevel@tonic-gate }
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate ctf_file_t *
772*0Sstevel@tonic-gate Pname_to_ctf(struct ps_prochandle *P, const char *name)
773*0Sstevel@tonic-gate {
774*0Sstevel@tonic-gate 	return (Plmid_to_ctf(P, PR_LMID_EVERY, name));
775*0Sstevel@tonic-gate }
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate /*
778*0Sstevel@tonic-gate  * If we're not a core file, re-read the /proc/<pid>/auxv file and store
779*0Sstevel@tonic-gate  * its contents in P->auxv.  In the case of a core file, we either
780*0Sstevel@tonic-gate  * initialized P->auxv in Pcore() from the NT_AUXV, or we don't have an
781*0Sstevel@tonic-gate  * auxv because the note was missing.
782*0Sstevel@tonic-gate  */
783*0Sstevel@tonic-gate void
784*0Sstevel@tonic-gate Preadauxvec(struct ps_prochandle *P)
785*0Sstevel@tonic-gate {
786*0Sstevel@tonic-gate 	char auxfile[64];
787*0Sstevel@tonic-gate 	struct stat statb;
788*0Sstevel@tonic-gate 	ssize_t naux;
789*0Sstevel@tonic-gate 	int fd;
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 	if (P->state == PS_DEAD)
792*0Sstevel@tonic-gate 		return; /* Already read during Pgrab_core() */
793*0Sstevel@tonic-gate 	if (P->state == PS_IDLE)
794*0Sstevel@tonic-gate 		return; /* No aux vec for Pgrab_file() */
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate 	if (P->auxv != NULL) {
797*0Sstevel@tonic-gate 		free(P->auxv);
798*0Sstevel@tonic-gate 		P->auxv = NULL;
799*0Sstevel@tonic-gate 		P->nauxv = 0;
800*0Sstevel@tonic-gate 	}
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate 	(void) sprintf(auxfile, "/proc/%d/auxv", (int)P->pid);
803*0Sstevel@tonic-gate 	if ((fd = open(auxfile, O_RDONLY)) < 0)
804*0Sstevel@tonic-gate 		return;
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	if (fstat(fd, &statb) == 0 &&
807*0Sstevel@tonic-gate 	    statb.st_size >= sizeof (auxv_t) &&
808*0Sstevel@tonic-gate 	    (P->auxv = malloc(statb.st_size + sizeof (auxv_t))) != NULL) {
809*0Sstevel@tonic-gate 		if ((naux = read(fd, P->auxv, statb.st_size)) < 0 ||
810*0Sstevel@tonic-gate 		    (naux /= sizeof (auxv_t)) < 1) {
811*0Sstevel@tonic-gate 			free(P->auxv);
812*0Sstevel@tonic-gate 			P->auxv = NULL;
813*0Sstevel@tonic-gate 		} else {
814*0Sstevel@tonic-gate 			P->auxv[naux].a_type = AT_NULL;
815*0Sstevel@tonic-gate 			P->auxv[naux].a_un.a_val = 0L;
816*0Sstevel@tonic-gate 			P->nauxv = (int)naux;
817*0Sstevel@tonic-gate 		}
818*0Sstevel@tonic-gate 	}
819*0Sstevel@tonic-gate 
820*0Sstevel@tonic-gate 	(void) close(fd);
821*0Sstevel@tonic-gate }
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate /*
824*0Sstevel@tonic-gate  * Return a requested element from the process's aux vector.
825*0Sstevel@tonic-gate  * Return -1 on failure (this is adequate for our purposes).
826*0Sstevel@tonic-gate  */
827*0Sstevel@tonic-gate long
828*0Sstevel@tonic-gate Pgetauxval(struct ps_prochandle *P, int type)
829*0Sstevel@tonic-gate {
830*0Sstevel@tonic-gate 	auxv_t *auxv;
831*0Sstevel@tonic-gate 
832*0Sstevel@tonic-gate 	if (P->auxv == NULL)
833*0Sstevel@tonic-gate 		Preadauxvec(P);
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	if (P->auxv == NULL)
836*0Sstevel@tonic-gate 		return (-1);
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate 	for (auxv = P->auxv; auxv->a_type != AT_NULL; auxv++) {
839*0Sstevel@tonic-gate 		if (auxv->a_type == type)
840*0Sstevel@tonic-gate 			return (auxv->a_un.a_val);
841*0Sstevel@tonic-gate 	}
842*0Sstevel@tonic-gate 
843*0Sstevel@tonic-gate 	return (-1);
844*0Sstevel@tonic-gate }
845*0Sstevel@tonic-gate 
846*0Sstevel@tonic-gate /*
847*0Sstevel@tonic-gate  * Return a pointer to our internal copy of the process's aux vector.
848*0Sstevel@tonic-gate  * The caller should not hold on to this pointer across any libproc calls.
849*0Sstevel@tonic-gate  */
850*0Sstevel@tonic-gate const auxv_t *
851*0Sstevel@tonic-gate Pgetauxvec(struct ps_prochandle *P)
852*0Sstevel@tonic-gate {
853*0Sstevel@tonic-gate 	static const auxv_t empty = { AT_NULL, 0L };
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate 	if (P->auxv == NULL)
856*0Sstevel@tonic-gate 		Preadauxvec(P);
857*0Sstevel@tonic-gate 
858*0Sstevel@tonic-gate 	if (P->auxv == NULL)
859*0Sstevel@tonic-gate 		return (&empty);
860*0Sstevel@tonic-gate 
861*0Sstevel@tonic-gate 	return (P->auxv);
862*0Sstevel@tonic-gate }
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate /*
865*0Sstevel@tonic-gate  * Find or build the symbol table for the given mapping.
866*0Sstevel@tonic-gate  */
867*0Sstevel@tonic-gate static file_info_t *
868*0Sstevel@tonic-gate build_map_symtab(struct ps_prochandle *P, map_info_t *mptr)
869*0Sstevel@tonic-gate {
870*0Sstevel@tonic-gate 	prmap_t *pmap = &mptr->map_pmap;
871*0Sstevel@tonic-gate 	file_info_t *fptr;
872*0Sstevel@tonic-gate 	rd_loadobj_t *lop;
873*0Sstevel@tonic-gate 	uint_t i;
874*0Sstevel@tonic-gate 
875*0Sstevel@tonic-gate 	if ((fptr = mptr->map_file) != NULL) {
876*0Sstevel@tonic-gate 		Pbuild_file_symtab(P, fptr);
877*0Sstevel@tonic-gate 		return (fptr);
878*0Sstevel@tonic-gate 	}
879*0Sstevel@tonic-gate 
880*0Sstevel@tonic-gate 	if (pmap->pr_mapname[0] == '\0')
881*0Sstevel@tonic-gate 		return (NULL);
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 	/*
884*0Sstevel@tonic-gate 	 * Attempt to find a matching file.
885*0Sstevel@tonic-gate 	 * (A file can be mapped at several different addresses.)
886*0Sstevel@tonic-gate 	 */
887*0Sstevel@tonic-gate 	for (i = 0, fptr = list_next(&P->file_head); i < P->num_files;
888*0Sstevel@tonic-gate 	    i++, fptr = list_next(fptr)) {
889*0Sstevel@tonic-gate 		if (strcmp(fptr->file_pname, pmap->pr_mapname) == 0 &&
890*0Sstevel@tonic-gate 		    (lop = fptr->file_lo) != NULL &&
891*0Sstevel@tonic-gate 		    ((pmap->pr_vaddr <= lop->rl_base &&
892*0Sstevel@tonic-gate 		    lop->rl_base < pmap->pr_vaddr + pmap->pr_size) ||
893*0Sstevel@tonic-gate 		    (pmap->pr_vaddr <= lop->rl_data_base &&
894*0Sstevel@tonic-gate 		    lop->rl_data_base < pmap->pr_vaddr + pmap->pr_size))) {
895*0Sstevel@tonic-gate 			mptr->map_file = fptr;
896*0Sstevel@tonic-gate 			fptr->file_ref++;
897*0Sstevel@tonic-gate 			Pbuild_file_symtab(P, fptr);
898*0Sstevel@tonic-gate 			return (fptr);
899*0Sstevel@tonic-gate 		}
900*0Sstevel@tonic-gate 	}
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	/*
903*0Sstevel@tonic-gate 	 * If we need to create a new file_info structure, iterate
904*0Sstevel@tonic-gate 	 * through the load objects in order to attempt to connect
905*0Sstevel@tonic-gate 	 * this new file with its primary text mapping.  We again
906*0Sstevel@tonic-gate 	 * need to handle ld.so as a special case because we need
907*0Sstevel@tonic-gate 	 * to be able to bootstrap librtld_db.
908*0Sstevel@tonic-gate 	 */
909*0Sstevel@tonic-gate 	if ((fptr = file_info_new(P, mptr)) == NULL)
910*0Sstevel@tonic-gate 		return (NULL);
911*0Sstevel@tonic-gate 
912*0Sstevel@tonic-gate 	if (P->map_ldso != mptr) {
913*0Sstevel@tonic-gate 		if (P->rap != NULL)
914*0Sstevel@tonic-gate 			(void) rd_loadobj_iter(P->rap, map_iter, P);
915*0Sstevel@tonic-gate 		else
916*0Sstevel@tonic-gate 			(void) Prd_agent(P);
917*0Sstevel@tonic-gate 	} else {
918*0Sstevel@tonic-gate 		fptr->file_map = mptr;
919*0Sstevel@tonic-gate 	}
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate 	/*
922*0Sstevel@tonic-gate 	 * If librtld_db wasn't able to help us connect the file to a primary
923*0Sstevel@tonic-gate 	 * text mapping, set file_map to the current mapping because we require
924*0Sstevel@tonic-gate 	 * fptr->file_map to be set in Pbuild_file_symtab.  librtld_db may be
925*0Sstevel@tonic-gate 	 * unaware of what's going on in the rare case that a legitimate ELF
926*0Sstevel@tonic-gate 	 * file has been mmap(2)ed into the process address space *without*
927*0Sstevel@tonic-gate 	 * the use of dlopen(3x).  Why would this happen?  See pwdx ... :)
928*0Sstevel@tonic-gate 	 */
929*0Sstevel@tonic-gate 	if (fptr->file_map == NULL)
930*0Sstevel@tonic-gate 		fptr->file_map = mptr;
931*0Sstevel@tonic-gate 
932*0Sstevel@tonic-gate 	Pbuild_file_symtab(P, fptr);
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 	return (fptr);
935*0Sstevel@tonic-gate }
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate static int
938*0Sstevel@tonic-gate read_ehdr32(struct ps_prochandle *P, Elf32_Ehdr *ehdr, uintptr_t addr)
939*0Sstevel@tonic-gate {
940*0Sstevel@tonic-gate 	if (Pread(P, ehdr, sizeof (*ehdr), addr) != sizeof (*ehdr))
941*0Sstevel@tonic-gate 		return (-1);
942*0Sstevel@tonic-gate 
943*0Sstevel@tonic-gate 	if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
944*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
945*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
946*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_MAG3] != ELFMAG3 ||
947*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
948*0Sstevel@tonic-gate #ifdef _BIG_ENDIAN
949*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_DATA] != ELFDATA2MSB ||
950*0Sstevel@tonic-gate #else
951*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_DATA] != ELFDATA2LSB ||
952*0Sstevel@tonic-gate #endif
953*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_VERSION] != EV_CURRENT)
954*0Sstevel@tonic-gate 		return (-1);
955*0Sstevel@tonic-gate 
956*0Sstevel@tonic-gate 	return (0);
957*0Sstevel@tonic-gate }
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate static int
960*0Sstevel@tonic-gate read_dynamic_phdr32(struct ps_prochandle *P, const Elf32_Ehdr *ehdr,
961*0Sstevel@tonic-gate     Elf32_Phdr *phdr, uintptr_t addr)
962*0Sstevel@tonic-gate {
963*0Sstevel@tonic-gate 	uint_t i;
964*0Sstevel@tonic-gate 
965*0Sstevel@tonic-gate 	for (i = 0; i < ehdr->e_phnum; i++) {
966*0Sstevel@tonic-gate 		uintptr_t a = addr + ehdr->e_phoff + i * ehdr->e_phentsize;
967*0Sstevel@tonic-gate 		if (Pread(P, phdr, sizeof (*phdr), a) != sizeof (*phdr))
968*0Sstevel@tonic-gate 			return (-1);
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate 		if (phdr->p_type == PT_DYNAMIC)
971*0Sstevel@tonic-gate 			return (0);
972*0Sstevel@tonic-gate 	}
973*0Sstevel@tonic-gate 
974*0Sstevel@tonic-gate 	return (-1);
975*0Sstevel@tonic-gate }
976*0Sstevel@tonic-gate 
977*0Sstevel@tonic-gate #ifdef _LP64
978*0Sstevel@tonic-gate static int
979*0Sstevel@tonic-gate read_ehdr64(struct ps_prochandle *P, Elf64_Ehdr *ehdr, uintptr_t addr)
980*0Sstevel@tonic-gate {
981*0Sstevel@tonic-gate 	if (Pread(P, ehdr, sizeof (Elf64_Ehdr), addr) != sizeof (Elf64_Ehdr))
982*0Sstevel@tonic-gate 		return (-1);
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate 	if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
985*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
986*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
987*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_MAG3] != ELFMAG3 ||
988*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
989*0Sstevel@tonic-gate #ifdef _BIG_ENDIAN
990*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_DATA] != ELFDATA2MSB ||
991*0Sstevel@tonic-gate #else
992*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_DATA] != ELFDATA2LSB ||
993*0Sstevel@tonic-gate #endif
994*0Sstevel@tonic-gate 	    ehdr->e_ident[EI_VERSION] != EV_CURRENT)
995*0Sstevel@tonic-gate 		return (-1);
996*0Sstevel@tonic-gate 
997*0Sstevel@tonic-gate 	return (0);
998*0Sstevel@tonic-gate }
999*0Sstevel@tonic-gate 
1000*0Sstevel@tonic-gate static int
1001*0Sstevel@tonic-gate read_dynamic_phdr64(struct ps_prochandle *P, const Elf64_Ehdr *ehdr,
1002*0Sstevel@tonic-gate     Elf64_Phdr *phdr, uintptr_t addr)
1003*0Sstevel@tonic-gate {
1004*0Sstevel@tonic-gate 	uint_t i;
1005*0Sstevel@tonic-gate 
1006*0Sstevel@tonic-gate 	for (i = 0; i < ehdr->e_phnum; i++) {
1007*0Sstevel@tonic-gate 		uintptr_t a = addr + ehdr->e_phoff + i * ehdr->e_phentsize;
1008*0Sstevel@tonic-gate 		if (Pread(P, phdr, sizeof (*phdr), a) != sizeof (*phdr))
1009*0Sstevel@tonic-gate 			return (-1);
1010*0Sstevel@tonic-gate 
1011*0Sstevel@tonic-gate 		if (phdr->p_type == PT_DYNAMIC)
1012*0Sstevel@tonic-gate 			return (0);
1013*0Sstevel@tonic-gate 	}
1014*0Sstevel@tonic-gate 
1015*0Sstevel@tonic-gate 	return (-1);
1016*0Sstevel@tonic-gate }
1017*0Sstevel@tonic-gate #endif	/* _LP64 */
1018*0Sstevel@tonic-gate 
1019*0Sstevel@tonic-gate /*
1020*0Sstevel@tonic-gate  * The text segment for each load object contains the elf header and
1021*0Sstevel@tonic-gate  * program headers. We can use this information to determine if the
1022*0Sstevel@tonic-gate  * file that corresponds to the load object is the same file that
1023*0Sstevel@tonic-gate  * was loaded into the process's address space. There can be a discrepency
1024*0Sstevel@tonic-gate  * if a file is recompiled after the process is started or if the target
1025*0Sstevel@tonic-gate  * represents a core file from a differently configured system -- two
1026*0Sstevel@tonic-gate  * common examples. The DT_CHECKSUM entry in the dynamic section
1027*0Sstevel@tonic-gate  * provides an easy method of comparison. It is important to note that
1028*0Sstevel@tonic-gate  * the dynamic section usually lives in the data segment, but the meta
1029*0Sstevel@tonic-gate  * data we use to find the dynamic section lives in the text segment so
1030*0Sstevel@tonic-gate  * if either of those segments is absent we can't proceed.
1031*0Sstevel@tonic-gate  *
1032*0Sstevel@tonic-gate  * We're looking through the elf file for several items: the symbol tables
1033*0Sstevel@tonic-gate  * (both dynsym and symtab), the procedure linkage table (PLT) base,
1034*0Sstevel@tonic-gate  * size, and relocation base, and the CTF information. Most of this can
1035*0Sstevel@tonic-gate  * be recovered from the loaded image of the file itself, the exceptions
1036*0Sstevel@tonic-gate  * being the symtab and CTF data.
1037*0Sstevel@tonic-gate  *
1038*0Sstevel@tonic-gate  * First we try to open the file that we think corresponds to the load
1039*0Sstevel@tonic-gate  * object, if the DT_CHECKSUM values match, we're all set, and can simply
1040*0Sstevel@tonic-gate  * recover all the information we need from the file. If the values of
1041*0Sstevel@tonic-gate  * DT_CHECKSUM don't match, or if we can't access the file for whatever
1042*0Sstevel@tonic-gate  * reasaon, we fake up a elf file to use in its stead. If we can't read
1043*0Sstevel@tonic-gate  * the elf data in the process's address space, we fall back to using
1044*0Sstevel@tonic-gate  * the file even though it may give inaccurate information.
1045*0Sstevel@tonic-gate  *
1046*0Sstevel@tonic-gate  * The elf file that we fake up has to consist of sections for the
1047*0Sstevel@tonic-gate  * dynsym, the PLT and the dynamic section. Note that in the case of a
1048*0Sstevel@tonic-gate  * core file, we'll get the CTF data in the file_info_t later on from
1049*0Sstevel@tonic-gate  * a section embedded the core file (if it's present).
1050*0Sstevel@tonic-gate  *
1051*0Sstevel@tonic-gate  * file_differs() conservatively looks for mismatched files, identifying
1052*0Sstevel@tonic-gate  * a match when there is any ambiguity (since that's the legacy behavior).
1053*0Sstevel@tonic-gate  */
1054*0Sstevel@tonic-gate static int
1055*0Sstevel@tonic-gate file_differs(struct ps_prochandle *P, Elf *elf, file_info_t *fptr)
1056*0Sstevel@tonic-gate {
1057*0Sstevel@tonic-gate 	Elf_Scn *scn;
1058*0Sstevel@tonic-gate 	GElf_Shdr shdr;
1059*0Sstevel@tonic-gate 	GElf_Dyn dyn;
1060*0Sstevel@tonic-gate 	Elf_Data *data;
1061*0Sstevel@tonic-gate 	uint_t i, ndyn;
1062*0Sstevel@tonic-gate 	GElf_Xword cksum;
1063*0Sstevel@tonic-gate 	uintptr_t addr;
1064*0Sstevel@tonic-gate 
1065*0Sstevel@tonic-gate 	if (fptr->file_map == NULL)
1066*0Sstevel@tonic-gate 		return (0);
1067*0Sstevel@tonic-gate 
1068*0Sstevel@tonic-gate 	if ((Pcontent(P) & (CC_CONTENT_TEXT | CC_CONTENT_DATA)) !=
1069*0Sstevel@tonic-gate 	    (CC_CONTENT_TEXT | CC_CONTENT_DATA))
1070*0Sstevel@tonic-gate 		return (0);
1071*0Sstevel@tonic-gate 
1072*0Sstevel@tonic-gate 	/*
1073*0Sstevel@tonic-gate 	 * First, we find the checksum value in the elf file.
1074*0Sstevel@tonic-gate 	 */
1075*0Sstevel@tonic-gate 	scn = NULL;
1076*0Sstevel@tonic-gate 	while ((scn = elf_nextscn(elf, scn)) != NULL) {
1077*0Sstevel@tonic-gate 		if (gelf_getshdr(scn, &shdr) != NULL &&
1078*0Sstevel@tonic-gate 		    shdr.sh_type == SHT_DYNAMIC)
1079*0Sstevel@tonic-gate 			goto found_shdr;
1080*0Sstevel@tonic-gate 	}
1081*0Sstevel@tonic-gate 	return (0);
1082*0Sstevel@tonic-gate 
1083*0Sstevel@tonic-gate found_shdr:
1084*0Sstevel@tonic-gate 	if ((data = elf_getdata(scn, NULL)) == NULL)
1085*0Sstevel@tonic-gate 		return (0);
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_ILP32)
1088*0Sstevel@tonic-gate 		ndyn = shdr.sh_size / sizeof (Elf32_Dyn);
1089*0Sstevel@tonic-gate #ifdef _LP64
1090*0Sstevel@tonic-gate 	else if (P->status.pr_dmodel == PR_MODEL_LP64)
1091*0Sstevel@tonic-gate 		ndyn = shdr.sh_size / sizeof (Elf64_Dyn);
1092*0Sstevel@tonic-gate #endif
1093*0Sstevel@tonic-gate 	else
1094*0Sstevel@tonic-gate 		return (0);
1095*0Sstevel@tonic-gate 
1096*0Sstevel@tonic-gate 	for (i = 0; i < ndyn; i++) {
1097*0Sstevel@tonic-gate 		if (gelf_getdyn(data, i, &dyn) != NULL &&
1098*0Sstevel@tonic-gate 		    dyn.d_tag == DT_CHECKSUM)
1099*0Sstevel@tonic-gate 			goto found_cksum;
1100*0Sstevel@tonic-gate 	}
1101*0Sstevel@tonic-gate 	return (0);
1102*0Sstevel@tonic-gate 
1103*0Sstevel@tonic-gate found_cksum:
1104*0Sstevel@tonic-gate 	cksum = dyn.d_un.d_val;
1105*0Sstevel@tonic-gate 	dprintf("elf cksum value is %llx\n", (u_longlong_t)cksum);
1106*0Sstevel@tonic-gate 
1107*0Sstevel@tonic-gate 	/*
1108*0Sstevel@tonic-gate 	 * Get the base of the text mapping that corresponds to this file.
1109*0Sstevel@tonic-gate 	 */
1110*0Sstevel@tonic-gate 	addr = fptr->file_map->map_pmap.pr_vaddr;
1111*0Sstevel@tonic-gate 
1112*0Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
1113*0Sstevel@tonic-gate 		Elf32_Ehdr ehdr;
1114*0Sstevel@tonic-gate 		Elf32_Phdr phdr;
1115*0Sstevel@tonic-gate 		Elf32_Dyn dync, *dynp;
1116*0Sstevel@tonic-gate 		uint_t i;
1117*0Sstevel@tonic-gate 
1118*0Sstevel@tonic-gate 		if (read_ehdr32(P, &ehdr, addr) != 0 ||
1119*0Sstevel@tonic-gate 		    read_dynamic_phdr32(P, &ehdr, &phdr, addr) != 0)
1120*0Sstevel@tonic-gate 			return (0);
1121*0Sstevel@tonic-gate 
1122*0Sstevel@tonic-gate 		if (ehdr.e_type == ET_DYN)
1123*0Sstevel@tonic-gate 			phdr.p_vaddr += addr;
1124*0Sstevel@tonic-gate 		if ((dynp = malloc(phdr.p_filesz)) == NULL)
1125*0Sstevel@tonic-gate 			return (0);
1126*0Sstevel@tonic-gate 		dync.d_tag = DT_NULL;
1127*0Sstevel@tonic-gate 		if (Pread(P, dynp, phdr.p_filesz, phdr.p_vaddr) !=
1128*0Sstevel@tonic-gate 		    phdr.p_filesz) {
1129*0Sstevel@tonic-gate 			free(dynp);
1130*0Sstevel@tonic-gate 			return (0);
1131*0Sstevel@tonic-gate 		}
1132*0Sstevel@tonic-gate 
1133*0Sstevel@tonic-gate 		for (i = 0; i < phdr.p_filesz / sizeof (Elf32_Dyn); i++) {
1134*0Sstevel@tonic-gate 			if (dynp[i].d_tag == DT_CHECKSUM)
1135*0Sstevel@tonic-gate 				dync = dynp[i];
1136*0Sstevel@tonic-gate 		}
1137*0Sstevel@tonic-gate 
1138*0Sstevel@tonic-gate 		free(dynp);
1139*0Sstevel@tonic-gate 
1140*0Sstevel@tonic-gate 		if (dync.d_tag != DT_CHECKSUM)
1141*0Sstevel@tonic-gate 			return (0);
1142*0Sstevel@tonic-gate 
1143*0Sstevel@tonic-gate 		dprintf("image cksum value is %llx\n",
1144*0Sstevel@tonic-gate 		    (u_longlong_t)dync.d_un.d_val);
1145*0Sstevel@tonic-gate 		return (dync.d_un.d_val != cksum);
1146*0Sstevel@tonic-gate #ifdef _LP64
1147*0Sstevel@tonic-gate 	} else if (P->status.pr_dmodel == PR_MODEL_LP64) {
1148*0Sstevel@tonic-gate 		Elf64_Ehdr ehdr;
1149*0Sstevel@tonic-gate 		Elf64_Phdr phdr;
1150*0Sstevel@tonic-gate 		Elf64_Dyn dync, *dynp;
1151*0Sstevel@tonic-gate 		uint_t i;
1152*0Sstevel@tonic-gate 
1153*0Sstevel@tonic-gate 		if (read_ehdr64(P, &ehdr, addr) != 0 ||
1154*0Sstevel@tonic-gate 		    read_dynamic_phdr64(P, &ehdr, &phdr, addr) != 0)
1155*0Sstevel@tonic-gate 			return (0);
1156*0Sstevel@tonic-gate 
1157*0Sstevel@tonic-gate 		if (ehdr.e_type == ET_DYN)
1158*0Sstevel@tonic-gate 			phdr.p_vaddr += addr;
1159*0Sstevel@tonic-gate 		if ((dynp = malloc(phdr.p_filesz)) == NULL)
1160*0Sstevel@tonic-gate 			return (0);
1161*0Sstevel@tonic-gate 		dync.d_tag = DT_NULL;
1162*0Sstevel@tonic-gate 		if (Pread(P, dynp, phdr.p_filesz, phdr.p_vaddr) !=
1163*0Sstevel@tonic-gate 		    phdr.p_filesz) {
1164*0Sstevel@tonic-gate 			free(dynp);
1165*0Sstevel@tonic-gate 			return (0);
1166*0Sstevel@tonic-gate 		}
1167*0Sstevel@tonic-gate 
1168*0Sstevel@tonic-gate 		for (i = 0; i < phdr.p_filesz / sizeof (Elf64_Dyn); i++) {
1169*0Sstevel@tonic-gate 			if (dynp[i].d_tag == DT_CHECKSUM)
1170*0Sstevel@tonic-gate 				dync = dynp[i];
1171*0Sstevel@tonic-gate 		}
1172*0Sstevel@tonic-gate 
1173*0Sstevel@tonic-gate 		free(dynp);
1174*0Sstevel@tonic-gate 
1175*0Sstevel@tonic-gate 		if (dync.d_tag != DT_CHECKSUM)
1176*0Sstevel@tonic-gate 			return (0);
1177*0Sstevel@tonic-gate 
1178*0Sstevel@tonic-gate 		dprintf("image cksum value is %llx\n",
1179*0Sstevel@tonic-gate 		    (u_longlong_t)dync.d_un.d_val);
1180*0Sstevel@tonic-gate 		return (dync.d_un.d_val != cksum);
1181*0Sstevel@tonic-gate #endif	/* _LP64 */
1182*0Sstevel@tonic-gate 	}
1183*0Sstevel@tonic-gate 
1184*0Sstevel@tonic-gate 	return (0);
1185*0Sstevel@tonic-gate }
1186*0Sstevel@tonic-gate 
1187*0Sstevel@tonic-gate static Elf *
1188*0Sstevel@tonic-gate fake_elf(struct ps_prochandle *P, file_info_t *fptr)
1189*0Sstevel@tonic-gate {
1190*0Sstevel@tonic-gate 	enum {
1191*0Sstevel@tonic-gate 		DI_PLTGOT = 0,
1192*0Sstevel@tonic-gate 		DI_JMPREL,
1193*0Sstevel@tonic-gate 		DI_PLTRELSZ,
1194*0Sstevel@tonic-gate 		DI_PLTREL,
1195*0Sstevel@tonic-gate 		DI_SYMTAB,
1196*0Sstevel@tonic-gate 		DI_HASH,
1197*0Sstevel@tonic-gate 		DI_SYMENT,
1198*0Sstevel@tonic-gate 		DI_STRTAB,
1199*0Sstevel@tonic-gate 		DI_STRSZ,
1200*0Sstevel@tonic-gate 		DI_NENT
1201*0Sstevel@tonic-gate 	};
1202*0Sstevel@tonic-gate 	uintptr_t addr;
1203*0Sstevel@tonic-gate 	size_t size = 0;
1204*0Sstevel@tonic-gate 	caddr_t elfdata = NULL;
1205*0Sstevel@tonic-gate 	Elf *elf;
1206*0Sstevel@tonic-gate 	Elf32_Word nchain;
1207*0Sstevel@tonic-gate 	static char shstr[] = ".shstrtab\0.dynsym\0.dynstr\0.dynamic\0.plt";
1208*0Sstevel@tonic-gate 
1209*0Sstevel@tonic-gate 	if (fptr->file_map == NULL)
1210*0Sstevel@tonic-gate 		return (NULL);
1211*0Sstevel@tonic-gate 
1212*0Sstevel@tonic-gate 	if ((Pcontent(P) & (CC_CONTENT_TEXT | CC_CONTENT_DATA)) !=
1213*0Sstevel@tonic-gate 	    (CC_CONTENT_TEXT | CC_CONTENT_DATA))
1214*0Sstevel@tonic-gate 		return (NULL);
1215*0Sstevel@tonic-gate 
1216*0Sstevel@tonic-gate 	addr = fptr->file_map->map_pmap.pr_vaddr;
1217*0Sstevel@tonic-gate 
1218*0Sstevel@tonic-gate 	/*
1219*0Sstevel@tonic-gate 	 * We're building a in memory elf file that will let us use libelf
1220*0Sstevel@tonic-gate 	 * for most of the work we need to later (e.g. symbol table lookups).
1221*0Sstevel@tonic-gate 	 * We need sections for the dynsym, dynstr, and plt, and we need
1222*0Sstevel@tonic-gate 	 * the program headers from the text section. The former is used in
1223*0Sstevel@tonic-gate 	 * Pbuild_file_symtab(); the latter is used in several functions in
1224*0Sstevel@tonic-gate 	 * Pcore.c to reconstruct the origin of each mapping from the load
1225*0Sstevel@tonic-gate 	 * object that spawned it.
1226*0Sstevel@tonic-gate 	 *
1227*0Sstevel@tonic-gate 	 * Here are some useful pieces of elf trivia that will help
1228*0Sstevel@tonic-gate 	 * to elucidate this code.
1229*0Sstevel@tonic-gate 	 *
1230*0Sstevel@tonic-gate 	 * All the information we need about the dynstr can be found in these
1231*0Sstevel@tonic-gate 	 * two entries in the dynamic section:
1232*0Sstevel@tonic-gate 	 *
1233*0Sstevel@tonic-gate 	 *	DT_STRTAB	base of dynstr
1234*0Sstevel@tonic-gate 	 *	DT_STRSZ	size of dynstr
1235*0Sstevel@tonic-gate 	 *
1236*0Sstevel@tonic-gate 	 * So deciphering the dynstr is pretty straightforward.
1237*0Sstevel@tonic-gate 	 *
1238*0Sstevel@tonic-gate 	 * The dynsym is a little trickier.
1239*0Sstevel@tonic-gate 	 *
1240*0Sstevel@tonic-gate 	 *	DT_SYMTAB	base of dynsym
1241*0Sstevel@tonic-gate 	 *	DT_SYMENT	size of a dynstr entry (Elf{32,64}_Sym)
1242*0Sstevel@tonic-gate 	 *	DT_HASH		base of hash table for dynamic lookups
1243*0Sstevel@tonic-gate 	 *
1244*0Sstevel@tonic-gate 	 * The DT_SYMTAB entry gives us any easy way of getting to the base
1245*0Sstevel@tonic-gate 	 * of the dynsym, but getting the size involves rooting around in the
1246*0Sstevel@tonic-gate 	 * dynamic lookup hash table. Here's the layout of the hash table:
1247*0Sstevel@tonic-gate 	 *
1248*0Sstevel@tonic-gate 	 *		+-------------------+
1249*0Sstevel@tonic-gate 	 *		|	nbucket	    |	All values are of type
1250*0Sstevel@tonic-gate 	 *		+-------------------+	Elf32_Word
1251*0Sstevel@tonic-gate 	 *		|	nchain	    |
1252*0Sstevel@tonic-gate 	 *		+-------------------+
1253*0Sstevel@tonic-gate 	 *		|	bucket[0]   |
1254*0Sstevel@tonic-gate 	 *		|	. . .	    |
1255*0Sstevel@tonic-gate 	 *		| bucket[nbucket-1] |
1256*0Sstevel@tonic-gate 	 *		+-------------------+
1257*0Sstevel@tonic-gate 	 *		|	chain[0]    |
1258*0Sstevel@tonic-gate 	 *		|	. . .	    |
1259*0Sstevel@tonic-gate 	 *		|  chain[nchain-1]  |
1260*0Sstevel@tonic-gate 	 *		+-------------------+
1261*0Sstevel@tonic-gate 	 *	(figure 5-12 from the SYS V Generic ABI)
1262*0Sstevel@tonic-gate 	 *
1263*0Sstevel@tonic-gate 	 * Symbols names are hashed into a particular bucket which contains
1264*0Sstevel@tonic-gate 	 * an index into the symbol table. Each entry in the symbol table
1265*0Sstevel@tonic-gate 	 * has a corresponding entry in the chain table which tells the
1266*0Sstevel@tonic-gate 	 * consumer where the next entry in the hash chain is. We can use
1267*0Sstevel@tonic-gate 	 * the nchain field to find out the size of the dynsym.
1268*0Sstevel@tonic-gate 	 *
1269*0Sstevel@tonic-gate 	 * We can figure out the size of the .plt section, but it takes some
1270*0Sstevel@tonic-gate 	 * doing. We need to use the following information:
1271*0Sstevel@tonic-gate 	 *
1272*0Sstevel@tonic-gate 	 *	DT_PLTGOT	base of the PLT
1273*0Sstevel@tonic-gate 	 *	DT_JMPREL	base of the PLT's relocation section
1274*0Sstevel@tonic-gate 	 *	DT_PLTRELSZ	size of the PLT's relocation section
1275*0Sstevel@tonic-gate 	 *	DT_PLTREL	type of the PLT's relocation section
1276*0Sstevel@tonic-gate 	 *
1277*0Sstevel@tonic-gate 	 * We can use the relocation section to figure out the address of the
1278*0Sstevel@tonic-gate 	 * last entry and subtract off the value of DT_PLTGOT to calculate
1279*0Sstevel@tonic-gate 	 * the size of the PLT.
1280*0Sstevel@tonic-gate 	 *
1281*0Sstevel@tonic-gate 	 * For more information, check out the System V Generic ABI.
1282*0Sstevel@tonic-gate 	 */
1283*0Sstevel@tonic-gate 
1284*0Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
1285*0Sstevel@tonic-gate 		Elf32_Ehdr ehdr, *ep;
1286*0Sstevel@tonic-gate 		Elf32_Phdr phdr;
1287*0Sstevel@tonic-gate 		Elf32_Shdr *sp;
1288*0Sstevel@tonic-gate 		Elf32_Dyn *dp;
1289*0Sstevel@tonic-gate 		Elf32_Dyn *d[DI_NENT] = { 0 };
1290*0Sstevel@tonic-gate 		uint_t i, dcount = 0;
1291*0Sstevel@tonic-gate 		uint32_t off;
1292*0Sstevel@tonic-gate 		size_t pltsz = 0, pltentsz;
1293*0Sstevel@tonic-gate 
1294*0Sstevel@tonic-gate 		if (read_ehdr32(P, &ehdr, addr) != 0 ||
1295*0Sstevel@tonic-gate 		    read_dynamic_phdr32(P, &ehdr, &phdr, addr) != 0)
1296*0Sstevel@tonic-gate 			return (NULL);
1297*0Sstevel@tonic-gate 
1298*0Sstevel@tonic-gate 		if (ehdr.e_type == ET_DYN)
1299*0Sstevel@tonic-gate 			phdr.p_vaddr += addr;
1300*0Sstevel@tonic-gate 
1301*0Sstevel@tonic-gate 		if ((dp = malloc(phdr.p_filesz)) == NULL)
1302*0Sstevel@tonic-gate 			return (NULL);
1303*0Sstevel@tonic-gate 
1304*0Sstevel@tonic-gate 		if (Pread(P, dp, phdr.p_filesz, phdr.p_vaddr) !=
1305*0Sstevel@tonic-gate 		    phdr.p_filesz) {
1306*0Sstevel@tonic-gate 			free(dp);
1307*0Sstevel@tonic-gate 			return (NULL);
1308*0Sstevel@tonic-gate 		}
1309*0Sstevel@tonic-gate 
1310*0Sstevel@tonic-gate 		for (i = 0; i < phdr.p_filesz / sizeof (Elf32_Dyn); i++) {
1311*0Sstevel@tonic-gate 			switch (dp[i].d_tag) {
1312*0Sstevel@tonic-gate 			/*
1313*0Sstevel@tonic-gate 			 * For the .plt section.
1314*0Sstevel@tonic-gate 			 */
1315*0Sstevel@tonic-gate 			case DT_PLTGOT:
1316*0Sstevel@tonic-gate 				d[DI_PLTGOT] = &dp[i];
1317*0Sstevel@tonic-gate 				continue;
1318*0Sstevel@tonic-gate 			case DT_JMPREL:
1319*0Sstevel@tonic-gate 				d[DI_JMPREL] = &dp[i];
1320*0Sstevel@tonic-gate 				continue;
1321*0Sstevel@tonic-gate 			case DT_PLTRELSZ:
1322*0Sstevel@tonic-gate 				d[DI_PLTRELSZ] = &dp[i];
1323*0Sstevel@tonic-gate 				continue;
1324*0Sstevel@tonic-gate 			case DT_PLTREL:
1325*0Sstevel@tonic-gate 				d[DI_PLTREL] = &dp[i];
1326*0Sstevel@tonic-gate 				continue;
1327*0Sstevel@tonic-gate 			default:
1328*0Sstevel@tonic-gate 				continue;
1329*0Sstevel@tonic-gate 
1330*0Sstevel@tonic-gate 			/*
1331*0Sstevel@tonic-gate 			 * For the .dynsym section.
1332*0Sstevel@tonic-gate 			 */
1333*0Sstevel@tonic-gate 			case DT_SYMTAB:
1334*0Sstevel@tonic-gate 				d[DI_SYMTAB] = &dp[i];
1335*0Sstevel@tonic-gate 				break;
1336*0Sstevel@tonic-gate 			case DT_HASH:
1337*0Sstevel@tonic-gate 				d[DI_HASH] = &dp[i];
1338*0Sstevel@tonic-gate 				break;
1339*0Sstevel@tonic-gate 			case DT_SYMENT:
1340*0Sstevel@tonic-gate 				d[DI_SYMENT] = &dp[i];
1341*0Sstevel@tonic-gate 				break;
1342*0Sstevel@tonic-gate 
1343*0Sstevel@tonic-gate 			/*
1344*0Sstevel@tonic-gate 			 * For the .dynstr section.
1345*0Sstevel@tonic-gate 			 */
1346*0Sstevel@tonic-gate 			case DT_STRTAB:
1347*0Sstevel@tonic-gate 				d[DI_STRTAB] = &dp[i];
1348*0Sstevel@tonic-gate 				break;
1349*0Sstevel@tonic-gate 			case DT_STRSZ:
1350*0Sstevel@tonic-gate 				d[DI_STRSZ] = &dp[i];
1351*0Sstevel@tonic-gate 				break;
1352*0Sstevel@tonic-gate 			}
1353*0Sstevel@tonic-gate 
1354*0Sstevel@tonic-gate 			dcount++;
1355*0Sstevel@tonic-gate 		}
1356*0Sstevel@tonic-gate 
1357*0Sstevel@tonic-gate 		/*
1358*0Sstevel@tonic-gate 		 * We need all of those dynamic entries in order to put
1359*0Sstevel@tonic-gate 		 * together a complete set of elf sections, but we'll
1360*0Sstevel@tonic-gate 		 * let the PLT section slide if need be. The dynsym- and
1361*0Sstevel@tonic-gate 		 * dynstr-related dynamic entries are mandatory in both
1362*0Sstevel@tonic-gate 		 * executables and shared objects so if one of those is
1363*0Sstevel@tonic-gate 		 * missing, we're in some trouble and should abort.
1364*0Sstevel@tonic-gate 		 */
1365*0Sstevel@tonic-gate 		if (dcount + 4 != DI_NENT) {
1366*0Sstevel@tonic-gate 			dprintf("text section missing required dynamic "
1367*0Sstevel@tonic-gate 			    "entries\n");
1368*0Sstevel@tonic-gate 			return (NULL);
1369*0Sstevel@tonic-gate 		}
1370*0Sstevel@tonic-gate 
1371*0Sstevel@tonic-gate 		if (ehdr.e_type == ET_DYN) {
1372*0Sstevel@tonic-gate 			if (d[DI_PLTGOT] != NULL)
1373*0Sstevel@tonic-gate 				d[DI_PLTGOT]->d_un.d_ptr += addr;
1374*0Sstevel@tonic-gate 			if (d[DI_JMPREL] != NULL)
1375*0Sstevel@tonic-gate 				d[DI_JMPREL]->d_un.d_ptr += addr;
1376*0Sstevel@tonic-gate 			d[DI_SYMTAB]->d_un.d_ptr += addr;
1377*0Sstevel@tonic-gate 			d[DI_HASH]->d_un.d_ptr += addr;
1378*0Sstevel@tonic-gate 			d[DI_STRTAB]->d_un.d_ptr += addr;
1379*0Sstevel@tonic-gate 		}
1380*0Sstevel@tonic-gate 
1381*0Sstevel@tonic-gate 		/* elf header */
1382*0Sstevel@tonic-gate 		size = sizeof (Elf32_Ehdr);
1383*0Sstevel@tonic-gate 
1384*0Sstevel@tonic-gate 		/* program headers from in-core elf fragment */
1385*0Sstevel@tonic-gate 		size += ehdr.e_phnum * ehdr.e_phentsize;
1386*0Sstevel@tonic-gate 
1387*0Sstevel@tonic-gate 		/* unused shdr, and .shstrtab section */
1388*0Sstevel@tonic-gate 		size += sizeof (Elf32_Shdr);
1389*0Sstevel@tonic-gate 		size += sizeof (Elf32_Shdr);
1390*0Sstevel@tonic-gate 		size += roundup(sizeof (shstr), 4);
1391*0Sstevel@tonic-gate 
1392*0Sstevel@tonic-gate 		/* .dynsym section */
1393*0Sstevel@tonic-gate 		size += sizeof (Elf32_Shdr);
1394*0Sstevel@tonic-gate 		if (Pread(P, &nchain, sizeof (nchain),
1395*0Sstevel@tonic-gate 		    d[DI_HASH]->d_un.d_ptr + 4) != sizeof (nchain))
1396*0Sstevel@tonic-gate 			goto bad32;
1397*0Sstevel@tonic-gate 		size += sizeof (Elf32_Sym) * nchain;
1398*0Sstevel@tonic-gate 
1399*0Sstevel@tonic-gate 		/* .dynstr section */
1400*0Sstevel@tonic-gate 		size += sizeof (Elf32_Shdr);
1401*0Sstevel@tonic-gate 		size += roundup(d[DI_STRSZ]->d_un.d_val, 4);
1402*0Sstevel@tonic-gate 
1403*0Sstevel@tonic-gate 		/* .dynamic section */
1404*0Sstevel@tonic-gate 		size += sizeof (Elf32_Shdr);
1405*0Sstevel@tonic-gate 		size += roundup(phdr.p_filesz, 4);
1406*0Sstevel@tonic-gate 
1407*0Sstevel@tonic-gate 		/* .plt section */
1408*0Sstevel@tonic-gate 		if (d[DI_PLTGOT] != NULL && d[DI_JMPREL] != NULL &&
1409*0Sstevel@tonic-gate 		    d[DI_PLTRELSZ] != NULL && d[DI_PLTREL] != NULL) {
1410*0Sstevel@tonic-gate 			uintptr_t penult, ult;
1411*0Sstevel@tonic-gate 			uintptr_t jmprel = d[DI_JMPREL]->d_un.d_ptr;
1412*0Sstevel@tonic-gate 			size_t pltrelsz = d[DI_PLTRELSZ]->d_un.d_val;
1413*0Sstevel@tonic-gate 
1414*0Sstevel@tonic-gate 			if (d[DI_PLTREL]->d_un.d_val == DT_RELA) {
1415*0Sstevel@tonic-gate 				uint_t ndx = pltrelsz / sizeof (Elf32_Rela) - 2;
1416*0Sstevel@tonic-gate 				Elf32_Rela r[2];
1417*0Sstevel@tonic-gate 
1418*0Sstevel@tonic-gate 				if (Pread(P, r, sizeof (r), jmprel +
1419*0Sstevel@tonic-gate 				    sizeof (r[0]) * ndx) != sizeof (r))
1420*0Sstevel@tonic-gate 					goto bad32;
1421*0Sstevel@tonic-gate 
1422*0Sstevel@tonic-gate 				penult = r[0].r_offset;
1423*0Sstevel@tonic-gate 				ult = r[1].r_offset;
1424*0Sstevel@tonic-gate 
1425*0Sstevel@tonic-gate 			} else if (d[DI_PLTREL]->d_un.d_val == DT_REL) {
1426*0Sstevel@tonic-gate 				uint_t ndx = pltrelsz / sizeof (Elf32_Rel) - 2;
1427*0Sstevel@tonic-gate 				Elf32_Rel r[2];
1428*0Sstevel@tonic-gate 
1429*0Sstevel@tonic-gate 				if (Pread(P, r, sizeof (r), jmprel +
1430*0Sstevel@tonic-gate 				    sizeof (r[0]) * ndx) != sizeof (r))
1431*0Sstevel@tonic-gate 					goto bad32;
1432*0Sstevel@tonic-gate 
1433*0Sstevel@tonic-gate 				penult = r[0].r_offset;
1434*0Sstevel@tonic-gate 				ult = r[1].r_offset;
1435*0Sstevel@tonic-gate 			} else {
1436*0Sstevel@tonic-gate 				goto bad32;
1437*0Sstevel@tonic-gate 			}
1438*0Sstevel@tonic-gate 
1439*0Sstevel@tonic-gate 			pltentsz = ult - penult;
1440*0Sstevel@tonic-gate 
1441*0Sstevel@tonic-gate 			if (ehdr.e_type == ET_DYN)
1442*0Sstevel@tonic-gate 				ult += addr;
1443*0Sstevel@tonic-gate 
1444*0Sstevel@tonic-gate 			pltsz = ult - d[DI_PLTGOT]->d_un.d_ptr + pltentsz;
1445*0Sstevel@tonic-gate 
1446*0Sstevel@tonic-gate 			size += sizeof (Elf32_Shdr);
1447*0Sstevel@tonic-gate 			size += roundup(pltsz, 4);
1448*0Sstevel@tonic-gate 		}
1449*0Sstevel@tonic-gate 
1450*0Sstevel@tonic-gate 		if ((elfdata = calloc(1, size)) == NULL)
1451*0Sstevel@tonic-gate 			goto bad32;
1452*0Sstevel@tonic-gate 
1453*0Sstevel@tonic-gate 		/* LINTED - alignment */
1454*0Sstevel@tonic-gate 		ep = (Elf32_Ehdr *)elfdata;
1455*0Sstevel@tonic-gate 		(void) memcpy(ep, &ehdr, offsetof(Elf32_Ehdr, e_phoff));
1456*0Sstevel@tonic-gate 
1457*0Sstevel@tonic-gate 		ep->e_ehsize = sizeof (Elf32_Ehdr);
1458*0Sstevel@tonic-gate 		ep->e_phoff = sizeof (Elf32_Ehdr);
1459*0Sstevel@tonic-gate 		ep->e_phentsize = ehdr.e_phentsize;
1460*0Sstevel@tonic-gate 		ep->e_phnum = ehdr.e_phnum;
1461*0Sstevel@tonic-gate 		ep->e_shoff = ep->e_phoff + ep->e_phnum * ep->e_phentsize;
1462*0Sstevel@tonic-gate 		ep->e_shentsize = sizeof (Elf32_Shdr);
1463*0Sstevel@tonic-gate 		ep->e_shnum = (pltsz == 0) ? 5 : 6;
1464*0Sstevel@tonic-gate 		ep->e_shstrndx = 1;
1465*0Sstevel@tonic-gate 
1466*0Sstevel@tonic-gate 		/* LINTED - alignment */
1467*0Sstevel@tonic-gate 		sp = (Elf32_Shdr *)(elfdata + ep->e_shoff);
1468*0Sstevel@tonic-gate 		off = ep->e_shoff + ep->e_shentsize * ep->e_shnum;
1469*0Sstevel@tonic-gate 
1470*0Sstevel@tonic-gate 		/*
1471*0Sstevel@tonic-gate 		 * Copying the program headers directly from the process's
1472*0Sstevel@tonic-gate 		 * address space is a little suspect, but since we only
1473*0Sstevel@tonic-gate 		 * use them for their address and size values, this is fine.
1474*0Sstevel@tonic-gate 		 */
1475*0Sstevel@tonic-gate 		if (Pread(P, &elfdata[ep->e_phoff],
1476*0Sstevel@tonic-gate 		    ep->e_phnum * ep->e_phentsize, addr + ehdr.e_phoff) !=
1477*0Sstevel@tonic-gate 		    ep->e_phnum * ep->e_phentsize) {
1478*0Sstevel@tonic-gate 			free(elfdata);
1479*0Sstevel@tonic-gate 			goto bad32;
1480*0Sstevel@tonic-gate 		}
1481*0Sstevel@tonic-gate 
1482*0Sstevel@tonic-gate 		/*
1483*0Sstevel@tonic-gate 		 * The first elf section is always skipped.
1484*0Sstevel@tonic-gate 		 */
1485*0Sstevel@tonic-gate 		sp++;
1486*0Sstevel@tonic-gate 
1487*0Sstevel@tonic-gate 		/*
1488*0Sstevel@tonic-gate 		 * Section Header[1]  sh_name: .shstrtab
1489*0Sstevel@tonic-gate 		 */
1490*0Sstevel@tonic-gate 		sp->sh_name = 0;
1491*0Sstevel@tonic-gate 		sp->sh_type = SHT_STRTAB;
1492*0Sstevel@tonic-gate 		sp->sh_flags = SHF_STRINGS;
1493*0Sstevel@tonic-gate 		sp->sh_addr = 0;
1494*0Sstevel@tonic-gate 		sp->sh_offset = off;
1495*0Sstevel@tonic-gate 		sp->sh_size = sizeof (shstr);
1496*0Sstevel@tonic-gate 		sp->sh_link = 0;
1497*0Sstevel@tonic-gate 		sp->sh_info = 0;
1498*0Sstevel@tonic-gate 		sp->sh_addralign = 1;
1499*0Sstevel@tonic-gate 		sp->sh_entsize = 0;
1500*0Sstevel@tonic-gate 
1501*0Sstevel@tonic-gate 		(void) memcpy(&elfdata[off], shstr, sizeof (shstr));
1502*0Sstevel@tonic-gate 		off += roundup(sp->sh_size, 4);
1503*0Sstevel@tonic-gate 		sp++;
1504*0Sstevel@tonic-gate 
1505*0Sstevel@tonic-gate 		/*
1506*0Sstevel@tonic-gate 		 * Section Header[2]  sh_name: .dynsym
1507*0Sstevel@tonic-gate 		 */
1508*0Sstevel@tonic-gate 		sp->sh_name = 10;
1509*0Sstevel@tonic-gate 		sp->sh_type = SHT_DYNSYM;
1510*0Sstevel@tonic-gate 		sp->sh_flags = SHF_ALLOC;
1511*0Sstevel@tonic-gate 		sp->sh_addr = d[DI_SYMTAB]->d_un.d_ptr;
1512*0Sstevel@tonic-gate 		if (ehdr.e_type == ET_DYN)
1513*0Sstevel@tonic-gate 			sp->sh_addr -= addr;
1514*0Sstevel@tonic-gate 		sp->sh_offset = off;
1515*0Sstevel@tonic-gate 		sp->sh_size = nchain * sizeof (Elf32_Sym);
1516*0Sstevel@tonic-gate 		sp->sh_link = 3;
1517*0Sstevel@tonic-gate 		sp->sh_info = 1;
1518*0Sstevel@tonic-gate 		sp->sh_addralign = 4;
1519*0Sstevel@tonic-gate 		sp->sh_entsize = sizeof (Elf32_Sym);
1520*0Sstevel@tonic-gate 
1521*0Sstevel@tonic-gate 		if (Pread(P, &elfdata[off], sp->sh_size,
1522*0Sstevel@tonic-gate 		    d[DI_SYMTAB]->d_un.d_ptr) != sp->sh_size) {
1523*0Sstevel@tonic-gate 			free(elfdata);
1524*0Sstevel@tonic-gate 			goto bad32;
1525*0Sstevel@tonic-gate 		}
1526*0Sstevel@tonic-gate 
1527*0Sstevel@tonic-gate 		off += roundup(sp->sh_size, 4);
1528*0Sstevel@tonic-gate 		sp++;
1529*0Sstevel@tonic-gate 
1530*0Sstevel@tonic-gate 		/*
1531*0Sstevel@tonic-gate 		 * Section Header[3]  sh_name: .dynstr
1532*0Sstevel@tonic-gate 		 */
1533*0Sstevel@tonic-gate 		sp->sh_name = 18;
1534*0Sstevel@tonic-gate 		sp->sh_type = SHT_STRTAB;
1535*0Sstevel@tonic-gate 		sp->sh_flags = SHF_ALLOC | SHF_STRINGS;
1536*0Sstevel@tonic-gate 		sp->sh_addr = d[DI_STRTAB]->d_un.d_ptr;
1537*0Sstevel@tonic-gate 		if (ehdr.e_type == ET_DYN)
1538*0Sstevel@tonic-gate 			sp->sh_addr -= addr;
1539*0Sstevel@tonic-gate 		sp->sh_offset = off;
1540*0Sstevel@tonic-gate 		sp->sh_size = d[DI_STRSZ]->d_un.d_val;
1541*0Sstevel@tonic-gate 		sp->sh_link = 0;
1542*0Sstevel@tonic-gate 		sp->sh_info = 0;
1543*0Sstevel@tonic-gate 		sp->sh_addralign = 1;
1544*0Sstevel@tonic-gate 		sp->sh_entsize = 0;
1545*0Sstevel@tonic-gate 
1546*0Sstevel@tonic-gate 		if (Pread(P, &elfdata[off], sp->sh_size,
1547*0Sstevel@tonic-gate 		    d[DI_STRTAB]->d_un.d_ptr) != sp->sh_size) {
1548*0Sstevel@tonic-gate 			free(elfdata);
1549*0Sstevel@tonic-gate 			goto bad32;
1550*0Sstevel@tonic-gate 		}
1551*0Sstevel@tonic-gate 		off += roundup(sp->sh_size, 4);
1552*0Sstevel@tonic-gate 		sp++;
1553*0Sstevel@tonic-gate 
1554*0Sstevel@tonic-gate 		/*
1555*0Sstevel@tonic-gate 		 * Section Header[4]  sh_name: .dynamic
1556*0Sstevel@tonic-gate 		 */
1557*0Sstevel@tonic-gate 		sp->sh_name = 26;
1558*0Sstevel@tonic-gate 		sp->sh_type = SHT_DYNAMIC;
1559*0Sstevel@tonic-gate 		sp->sh_flags = SHF_WRITE | SHF_ALLOC;
1560*0Sstevel@tonic-gate 		sp->sh_addr = phdr.p_vaddr;
1561*0Sstevel@tonic-gate 		if (ehdr.e_type == ET_DYN)
1562*0Sstevel@tonic-gate 			sp->sh_addr -= addr;
1563*0Sstevel@tonic-gate 		sp->sh_offset = off;
1564*0Sstevel@tonic-gate 		sp->sh_size = phdr.p_filesz;
1565*0Sstevel@tonic-gate 		sp->sh_link = 3;
1566*0Sstevel@tonic-gate 		sp->sh_info = 0;
1567*0Sstevel@tonic-gate 		sp->sh_addralign = 4;
1568*0Sstevel@tonic-gate 		sp->sh_entsize = sizeof (Elf32_Dyn);
1569*0Sstevel@tonic-gate 
1570*0Sstevel@tonic-gate 		(void) memcpy(&elfdata[off], dp, sp->sh_size);
1571*0Sstevel@tonic-gate 		off += roundup(sp->sh_size, 4);
1572*0Sstevel@tonic-gate 		sp++;
1573*0Sstevel@tonic-gate 
1574*0Sstevel@tonic-gate 		/*
1575*0Sstevel@tonic-gate 		 * Section Header[5]  sh_name: .plt
1576*0Sstevel@tonic-gate 		 */
1577*0Sstevel@tonic-gate 		if (pltsz != 0) {
1578*0Sstevel@tonic-gate 			sp->sh_name = 35;
1579*0Sstevel@tonic-gate 			sp->sh_type = SHT_PROGBITS;
1580*0Sstevel@tonic-gate 			sp->sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
1581*0Sstevel@tonic-gate 			sp->sh_addr = d[DI_PLTGOT]->d_un.d_ptr;
1582*0Sstevel@tonic-gate 			if (ehdr.e_type == ET_DYN)
1583*0Sstevel@tonic-gate 				sp->sh_addr -= addr;
1584*0Sstevel@tonic-gate 			sp->sh_offset = off;
1585*0Sstevel@tonic-gate 			sp->sh_size = pltsz;
1586*0Sstevel@tonic-gate 			sp->sh_link = 0;
1587*0Sstevel@tonic-gate 			sp->sh_info = 0;
1588*0Sstevel@tonic-gate 			sp->sh_addralign = 4;
1589*0Sstevel@tonic-gate 			sp->sh_entsize = pltentsz;
1590*0Sstevel@tonic-gate 
1591*0Sstevel@tonic-gate 			if (Pread(P, &elfdata[off], sp->sh_size,
1592*0Sstevel@tonic-gate 			    d[DI_PLTGOT]->d_un.d_ptr) != sp->sh_size) {
1593*0Sstevel@tonic-gate 				free(elfdata);
1594*0Sstevel@tonic-gate 				goto bad32;
1595*0Sstevel@tonic-gate 			}
1596*0Sstevel@tonic-gate 			off += roundup(sp->sh_size, 4);
1597*0Sstevel@tonic-gate 			sp++;
1598*0Sstevel@tonic-gate 		}
1599*0Sstevel@tonic-gate 
1600*0Sstevel@tonic-gate 		free(dp);
1601*0Sstevel@tonic-gate 		goto good;
1602*0Sstevel@tonic-gate 
1603*0Sstevel@tonic-gate bad32:
1604*0Sstevel@tonic-gate 		free(dp);
1605*0Sstevel@tonic-gate 		return (NULL);
1606*0Sstevel@tonic-gate #ifdef _LP64
1607*0Sstevel@tonic-gate 	} else if (P->status.pr_dmodel == PR_MODEL_LP64) {
1608*0Sstevel@tonic-gate 		Elf64_Ehdr ehdr, *ep;
1609*0Sstevel@tonic-gate 		Elf64_Phdr phdr;
1610*0Sstevel@tonic-gate 		Elf64_Shdr *sp;
1611*0Sstevel@tonic-gate 		Elf64_Dyn *dp;
1612*0Sstevel@tonic-gate 		Elf64_Dyn *d[DI_NENT] = { 0 };
1613*0Sstevel@tonic-gate 		uint_t i, dcount = 0;
1614*0Sstevel@tonic-gate 		uint64_t off;
1615*0Sstevel@tonic-gate 		size_t pltsz = 0, pltentsz;
1616*0Sstevel@tonic-gate 
1617*0Sstevel@tonic-gate 		if (read_ehdr64(P, &ehdr, addr) != 0 ||
1618*0Sstevel@tonic-gate 		    read_dynamic_phdr64(P, &ehdr, &phdr, addr) != 0)
1619*0Sstevel@tonic-gate 			return (NULL);
1620*0Sstevel@tonic-gate 
1621*0Sstevel@tonic-gate 		if (ehdr.e_type == ET_DYN)
1622*0Sstevel@tonic-gate 			phdr.p_vaddr += addr;
1623*0Sstevel@tonic-gate 
1624*0Sstevel@tonic-gate 		if ((dp = malloc(phdr.p_filesz)) == NULL)
1625*0Sstevel@tonic-gate 			return (NULL);
1626*0Sstevel@tonic-gate 
1627*0Sstevel@tonic-gate 		if (Pread(P, dp, phdr.p_filesz, phdr.p_vaddr) !=
1628*0Sstevel@tonic-gate 		    phdr.p_filesz) {
1629*0Sstevel@tonic-gate 			free(dp);
1630*0Sstevel@tonic-gate 			return (NULL);
1631*0Sstevel@tonic-gate 		}
1632*0Sstevel@tonic-gate 
1633*0Sstevel@tonic-gate 		for (i = 0; i < phdr.p_filesz / sizeof (Elf64_Dyn); i++) {
1634*0Sstevel@tonic-gate 			switch (dp[i].d_tag) {
1635*0Sstevel@tonic-gate 			/*
1636*0Sstevel@tonic-gate 			 * For the .plt section.
1637*0Sstevel@tonic-gate 			 */
1638*0Sstevel@tonic-gate 			case DT_PLTGOT:
1639*0Sstevel@tonic-gate 				d[DI_PLTGOT] = &dp[i];
1640*0Sstevel@tonic-gate 				continue;
1641*0Sstevel@tonic-gate 			case DT_JMPREL:
1642*0Sstevel@tonic-gate 				d[DI_JMPREL] = &dp[i];
1643*0Sstevel@tonic-gate 				continue;
1644*0Sstevel@tonic-gate 			case DT_PLTRELSZ:
1645*0Sstevel@tonic-gate 				d[DI_PLTRELSZ] = &dp[i];
1646*0Sstevel@tonic-gate 				continue;
1647*0Sstevel@tonic-gate 			case DT_PLTREL:
1648*0Sstevel@tonic-gate 				d[DI_PLTREL] = &dp[i];
1649*0Sstevel@tonic-gate 				continue;
1650*0Sstevel@tonic-gate 			default:
1651*0Sstevel@tonic-gate 				continue;
1652*0Sstevel@tonic-gate 
1653*0Sstevel@tonic-gate 			/*
1654*0Sstevel@tonic-gate 			 * For the .dynsym section.
1655*0Sstevel@tonic-gate 			 */
1656*0Sstevel@tonic-gate 			case DT_SYMTAB:
1657*0Sstevel@tonic-gate 				d[DI_SYMTAB] = &dp[i];
1658*0Sstevel@tonic-gate 				break;
1659*0Sstevel@tonic-gate 			case DT_HASH:
1660*0Sstevel@tonic-gate 				d[DI_HASH] = &dp[i];
1661*0Sstevel@tonic-gate 				break;
1662*0Sstevel@tonic-gate 			case DT_SYMENT:
1663*0Sstevel@tonic-gate 				d[DI_SYMENT] = &dp[i];
1664*0Sstevel@tonic-gate 				break;
1665*0Sstevel@tonic-gate 
1666*0Sstevel@tonic-gate 			/*
1667*0Sstevel@tonic-gate 			 * For the .dynstr section.
1668*0Sstevel@tonic-gate 			 */
1669*0Sstevel@tonic-gate 			case DT_STRTAB:
1670*0Sstevel@tonic-gate 				d[DI_STRTAB] = &dp[i];
1671*0Sstevel@tonic-gate 				break;
1672*0Sstevel@tonic-gate 			case DT_STRSZ:
1673*0Sstevel@tonic-gate 				d[DI_STRSZ] = &dp[i];
1674*0Sstevel@tonic-gate 				break;
1675*0Sstevel@tonic-gate 			}
1676*0Sstevel@tonic-gate 
1677*0Sstevel@tonic-gate 			dcount++;
1678*0Sstevel@tonic-gate 		}
1679*0Sstevel@tonic-gate 
1680*0Sstevel@tonic-gate 		/*
1681*0Sstevel@tonic-gate 		 * We need all of those dynamic entries in order to put
1682*0Sstevel@tonic-gate 		 * together a complete set of elf sections, but we'll
1683*0Sstevel@tonic-gate 		 * let the PLT section slide if need be. The dynsym- and
1684*0Sstevel@tonic-gate 		 * dynstr-related dynamic entries are mandatory in both
1685*0Sstevel@tonic-gate 		 * executables and shared objects so if one of those is
1686*0Sstevel@tonic-gate 		 * missing, we're in some trouble and should abort.
1687*0Sstevel@tonic-gate 		 */
1688*0Sstevel@tonic-gate 		if (dcount + 4 != DI_NENT) {
1689*0Sstevel@tonic-gate 			dprintf("text section missing required dynamic "
1690*0Sstevel@tonic-gate 			    "entries\n");
1691*0Sstevel@tonic-gate 			return (NULL);
1692*0Sstevel@tonic-gate 		}
1693*0Sstevel@tonic-gate 
1694*0Sstevel@tonic-gate 		if (ehdr.e_type == ET_DYN) {
1695*0Sstevel@tonic-gate 			if (d[DI_PLTGOT] != NULL)
1696*0Sstevel@tonic-gate 				d[DI_PLTGOT]->d_un.d_ptr += addr;
1697*0Sstevel@tonic-gate 			if (d[DI_JMPREL] != NULL)
1698*0Sstevel@tonic-gate 				d[DI_JMPREL]->d_un.d_ptr += addr;
1699*0Sstevel@tonic-gate 			d[DI_SYMTAB]->d_un.d_ptr += addr;
1700*0Sstevel@tonic-gate 			d[DI_HASH]->d_un.d_ptr += addr;
1701*0Sstevel@tonic-gate 			d[DI_STRTAB]->d_un.d_ptr += addr;
1702*0Sstevel@tonic-gate 		}
1703*0Sstevel@tonic-gate 
1704*0Sstevel@tonic-gate 		/* elf header */
1705*0Sstevel@tonic-gate 		size = sizeof (Elf64_Ehdr);
1706*0Sstevel@tonic-gate 
1707*0Sstevel@tonic-gate 		/* program headers from in-core elf fragment */
1708*0Sstevel@tonic-gate 		size += ehdr.e_phnum * ehdr.e_phentsize;
1709*0Sstevel@tonic-gate 
1710*0Sstevel@tonic-gate 		/* unused shdr, and .shstrtab section */
1711*0Sstevel@tonic-gate 		size += sizeof (Elf64_Shdr);
1712*0Sstevel@tonic-gate 		size += sizeof (Elf64_Shdr);
1713*0Sstevel@tonic-gate 		size += roundup(sizeof (shstr), 8);
1714*0Sstevel@tonic-gate 
1715*0Sstevel@tonic-gate 		/* .dynsym section */
1716*0Sstevel@tonic-gate 		size += sizeof (Elf64_Shdr);
1717*0Sstevel@tonic-gate 		if (Pread(P, &nchain, sizeof (nchain),
1718*0Sstevel@tonic-gate 		    d[DI_HASH]->d_un.d_ptr + 4) != sizeof (nchain))
1719*0Sstevel@tonic-gate 			goto bad64;
1720*0Sstevel@tonic-gate 		size += sizeof (Elf64_Sym) * nchain;
1721*0Sstevel@tonic-gate 
1722*0Sstevel@tonic-gate 		/* .dynstr section */
1723*0Sstevel@tonic-gate 		size += sizeof (Elf64_Shdr);
1724*0Sstevel@tonic-gate 		size += roundup(d[DI_STRSZ]->d_un.d_val, 8);
1725*0Sstevel@tonic-gate 
1726*0Sstevel@tonic-gate 		/* .dynamic section */
1727*0Sstevel@tonic-gate 		size += sizeof (Elf64_Shdr);
1728*0Sstevel@tonic-gate 		size += roundup(phdr.p_filesz, 8);
1729*0Sstevel@tonic-gate 
1730*0Sstevel@tonic-gate 		/* .plt section */
1731*0Sstevel@tonic-gate 		if (d[DI_PLTGOT] != NULL && d[DI_JMPREL] != NULL &&
1732*0Sstevel@tonic-gate 		    d[DI_PLTRELSZ] != NULL && d[DI_PLTREL] != NULL) {
1733*0Sstevel@tonic-gate 			uintptr_t penult, ult;
1734*0Sstevel@tonic-gate 			uintptr_t jmprel = d[DI_JMPREL]->d_un.d_ptr;
1735*0Sstevel@tonic-gate 			size_t pltrelsz = d[DI_PLTRELSZ]->d_un.d_val;
1736*0Sstevel@tonic-gate 
1737*0Sstevel@tonic-gate 			if (d[DI_PLTREL]->d_un.d_val == DT_RELA) {
1738*0Sstevel@tonic-gate 				uint_t ndx = pltrelsz / sizeof (Elf64_Rela) - 2;
1739*0Sstevel@tonic-gate 				Elf64_Rela r[2];
1740*0Sstevel@tonic-gate 
1741*0Sstevel@tonic-gate 				if (Pread(P, r, sizeof (r), jmprel +
1742*0Sstevel@tonic-gate 				    sizeof (r[0]) * ndx) != sizeof (r))
1743*0Sstevel@tonic-gate 					goto bad64;
1744*0Sstevel@tonic-gate 
1745*0Sstevel@tonic-gate 				penult = r[0].r_offset;
1746*0Sstevel@tonic-gate 				ult = r[1].r_offset;
1747*0Sstevel@tonic-gate 
1748*0Sstevel@tonic-gate 			} else if (d[DI_PLTREL]->d_un.d_val == DT_REL) {
1749*0Sstevel@tonic-gate 				uint_t ndx = pltrelsz / sizeof (Elf64_Rel) - 2;
1750*0Sstevel@tonic-gate 				Elf64_Rel r[2];
1751*0Sstevel@tonic-gate 
1752*0Sstevel@tonic-gate 				if (Pread(P, r, sizeof (r), jmprel +
1753*0Sstevel@tonic-gate 				    sizeof (r[0]) * ndx) != sizeof (r))
1754*0Sstevel@tonic-gate 					goto bad64;
1755*0Sstevel@tonic-gate 
1756*0Sstevel@tonic-gate 				penult = r[0].r_offset;
1757*0Sstevel@tonic-gate 				ult = r[1].r_offset;
1758*0Sstevel@tonic-gate 			} else {
1759*0Sstevel@tonic-gate 				goto bad64;
1760*0Sstevel@tonic-gate 			}
1761*0Sstevel@tonic-gate 
1762*0Sstevel@tonic-gate 			pltentsz = ult - penult;
1763*0Sstevel@tonic-gate 
1764*0Sstevel@tonic-gate 			if (ehdr.e_type == ET_DYN)
1765*0Sstevel@tonic-gate 				ult += addr;
1766*0Sstevel@tonic-gate 
1767*0Sstevel@tonic-gate 			pltsz = ult - d[DI_PLTGOT]->d_un.d_ptr + pltentsz;
1768*0Sstevel@tonic-gate 
1769*0Sstevel@tonic-gate 			size += sizeof (Elf64_Shdr);
1770*0Sstevel@tonic-gate 			size += roundup(pltsz, 8);
1771*0Sstevel@tonic-gate 		}
1772*0Sstevel@tonic-gate 
1773*0Sstevel@tonic-gate 		if ((elfdata = calloc(1, size)) == NULL)
1774*0Sstevel@tonic-gate 			goto bad64;
1775*0Sstevel@tonic-gate 
1776*0Sstevel@tonic-gate 		/* LINTED - alignment */
1777*0Sstevel@tonic-gate 		ep = (Elf64_Ehdr *)elfdata;
1778*0Sstevel@tonic-gate 		(void) memcpy(ep, &ehdr, offsetof(Elf64_Ehdr, e_phoff));
1779*0Sstevel@tonic-gate 
1780*0Sstevel@tonic-gate 		ep->e_ehsize = sizeof (Elf64_Ehdr);
1781*0Sstevel@tonic-gate 		ep->e_phoff = sizeof (Elf64_Ehdr);
1782*0Sstevel@tonic-gate 		ep->e_phentsize = ehdr.e_phentsize;
1783*0Sstevel@tonic-gate 		ep->e_phnum = ehdr.e_phnum;
1784*0Sstevel@tonic-gate 		ep->e_shoff = ep->e_phoff + ep->e_phnum * ep->e_phentsize;
1785*0Sstevel@tonic-gate 		ep->e_shentsize = sizeof (Elf64_Shdr);
1786*0Sstevel@tonic-gate 		ep->e_shnum = (pltsz == 0) ? 5 : 6;
1787*0Sstevel@tonic-gate 		ep->e_shstrndx = 1;
1788*0Sstevel@tonic-gate 
1789*0Sstevel@tonic-gate 		/* LINTED - alignment */
1790*0Sstevel@tonic-gate 		sp = (Elf64_Shdr *)(elfdata + ep->e_shoff);
1791*0Sstevel@tonic-gate 		off = ep->e_shoff + ep->e_shentsize * ep->e_shnum;
1792*0Sstevel@tonic-gate 
1793*0Sstevel@tonic-gate 		/*
1794*0Sstevel@tonic-gate 		 * Copying the program headers directly from the process's
1795*0Sstevel@tonic-gate 		 * address space is a little suspect, but since we only
1796*0Sstevel@tonic-gate 		 * use them for their address and size values, this is fine.
1797*0Sstevel@tonic-gate 		 */
1798*0Sstevel@tonic-gate 		if (Pread(P, &elfdata[ep->e_phoff],
1799*0Sstevel@tonic-gate 		    ep->e_phnum * ep->e_phentsize, addr + ehdr.e_phoff) !=
1800*0Sstevel@tonic-gate 		    ep->e_phnum * ep->e_phentsize) {
1801*0Sstevel@tonic-gate 			free(elfdata);
1802*0Sstevel@tonic-gate 			goto bad64;
1803*0Sstevel@tonic-gate 		}
1804*0Sstevel@tonic-gate 
1805*0Sstevel@tonic-gate 		/*
1806*0Sstevel@tonic-gate 		 * The first elf section is always skipped.
1807*0Sstevel@tonic-gate 		 */
1808*0Sstevel@tonic-gate 		sp++;
1809*0Sstevel@tonic-gate 
1810*0Sstevel@tonic-gate 		/*
1811*0Sstevel@tonic-gate 		 * Section Header[1]  sh_name: .shstrtab
1812*0Sstevel@tonic-gate 		 */
1813*0Sstevel@tonic-gate 		sp->sh_name = 0;
1814*0Sstevel@tonic-gate 		sp->sh_type = SHT_STRTAB;
1815*0Sstevel@tonic-gate 		sp->sh_flags = SHF_STRINGS;
1816*0Sstevel@tonic-gate 		sp->sh_addr = 0;
1817*0Sstevel@tonic-gate 		sp->sh_offset = off;
1818*0Sstevel@tonic-gate 		sp->sh_size = sizeof (shstr);
1819*0Sstevel@tonic-gate 		sp->sh_link = 0;
1820*0Sstevel@tonic-gate 		sp->sh_info = 0;
1821*0Sstevel@tonic-gate 		sp->sh_addralign = 1;
1822*0Sstevel@tonic-gate 		sp->sh_entsize = 0;
1823*0Sstevel@tonic-gate 
1824*0Sstevel@tonic-gate 		(void) memcpy(&elfdata[off], shstr, sizeof (shstr));
1825*0Sstevel@tonic-gate 		off += roundup(sp->sh_size, 8);
1826*0Sstevel@tonic-gate 		sp++;
1827*0Sstevel@tonic-gate 
1828*0Sstevel@tonic-gate 		/*
1829*0Sstevel@tonic-gate 		 * Section Header[2]  sh_name: .dynsym
1830*0Sstevel@tonic-gate 		 */
1831*0Sstevel@tonic-gate 		sp->sh_name = 10;
1832*0Sstevel@tonic-gate 		sp->sh_type = SHT_DYNSYM;
1833*0Sstevel@tonic-gate 		sp->sh_flags = SHF_ALLOC;
1834*0Sstevel@tonic-gate 		sp->sh_addr = d[DI_SYMTAB]->d_un.d_ptr;
1835*0Sstevel@tonic-gate 		if (ehdr.e_type == ET_DYN)
1836*0Sstevel@tonic-gate 			sp->sh_addr -= addr;
1837*0Sstevel@tonic-gate 		sp->sh_offset = off;
1838*0Sstevel@tonic-gate 		sp->sh_size = nchain * sizeof (Elf64_Sym);
1839*0Sstevel@tonic-gate 		sp->sh_link = 3;
1840*0Sstevel@tonic-gate 		sp->sh_info = 1;
1841*0Sstevel@tonic-gate 		sp->sh_addralign = 8;
1842*0Sstevel@tonic-gate 		sp->sh_entsize = sizeof (Elf64_Sym);
1843*0Sstevel@tonic-gate 
1844*0Sstevel@tonic-gate 		if (Pread(P, &elfdata[off], sp->sh_size,
1845*0Sstevel@tonic-gate 		    d[DI_SYMTAB]->d_un.d_ptr) != sp->sh_size) {
1846*0Sstevel@tonic-gate 			free(elfdata);
1847*0Sstevel@tonic-gate 			goto bad64;
1848*0Sstevel@tonic-gate 		}
1849*0Sstevel@tonic-gate 
1850*0Sstevel@tonic-gate 		off += roundup(sp->sh_size, 8);
1851*0Sstevel@tonic-gate 		sp++;
1852*0Sstevel@tonic-gate 
1853*0Sstevel@tonic-gate 		/*
1854*0Sstevel@tonic-gate 		 * Section Header[3]  sh_name: .dynstr
1855*0Sstevel@tonic-gate 		 */
1856*0Sstevel@tonic-gate 		sp->sh_name = 18;
1857*0Sstevel@tonic-gate 		sp->sh_type = SHT_STRTAB;
1858*0Sstevel@tonic-gate 		sp->sh_flags = SHF_ALLOC | SHF_STRINGS;
1859*0Sstevel@tonic-gate 		sp->sh_addr = d[DI_STRTAB]->d_un.d_ptr;
1860*0Sstevel@tonic-gate 		if (ehdr.e_type == ET_DYN)
1861*0Sstevel@tonic-gate 			sp->sh_addr -= addr;
1862*0Sstevel@tonic-gate 		sp->sh_offset = off;
1863*0Sstevel@tonic-gate 		sp->sh_size = d[DI_STRSZ]->d_un.d_val;
1864*0Sstevel@tonic-gate 		sp->sh_link = 0;
1865*0Sstevel@tonic-gate 		sp->sh_info = 0;
1866*0Sstevel@tonic-gate 		sp->sh_addralign = 1;
1867*0Sstevel@tonic-gate 		sp->sh_entsize = 0;
1868*0Sstevel@tonic-gate 
1869*0Sstevel@tonic-gate 		if (Pread(P, &elfdata[off], sp->sh_size,
1870*0Sstevel@tonic-gate 		    d[DI_STRTAB]->d_un.d_ptr) != sp->sh_size) {
1871*0Sstevel@tonic-gate 			free(elfdata);
1872*0Sstevel@tonic-gate 			goto bad64;
1873*0Sstevel@tonic-gate 		}
1874*0Sstevel@tonic-gate 		off += roundup(sp->sh_size, 8);
1875*0Sstevel@tonic-gate 		sp++;
1876*0Sstevel@tonic-gate 
1877*0Sstevel@tonic-gate 		/*
1878*0Sstevel@tonic-gate 		 * Section Header[4]  sh_name: .dynamic
1879*0Sstevel@tonic-gate 		 */
1880*0Sstevel@tonic-gate 		sp->sh_name = 26;
1881*0Sstevel@tonic-gate 		sp->sh_type = SHT_DYNAMIC;
1882*0Sstevel@tonic-gate 		sp->sh_flags = SHF_WRITE | SHF_ALLOC;
1883*0Sstevel@tonic-gate 		sp->sh_addr = phdr.p_vaddr;
1884*0Sstevel@tonic-gate 		if (ehdr.e_type == ET_DYN)
1885*0Sstevel@tonic-gate 			sp->sh_addr -= addr;
1886*0Sstevel@tonic-gate 		sp->sh_offset = off;
1887*0Sstevel@tonic-gate 		sp->sh_size = phdr.p_filesz;
1888*0Sstevel@tonic-gate 		sp->sh_link = 3;
1889*0Sstevel@tonic-gate 		sp->sh_info = 0;
1890*0Sstevel@tonic-gate 		sp->sh_addralign = 8;
1891*0Sstevel@tonic-gate 		sp->sh_entsize = sizeof (Elf64_Dyn);
1892*0Sstevel@tonic-gate 
1893*0Sstevel@tonic-gate 		(void) memcpy(&elfdata[off], dp, sp->sh_size);
1894*0Sstevel@tonic-gate 		off += roundup(sp->sh_size, 8);
1895*0Sstevel@tonic-gate 		sp++;
1896*0Sstevel@tonic-gate 
1897*0Sstevel@tonic-gate 		/*
1898*0Sstevel@tonic-gate 		 * Section Header[5]  sh_name: .plt
1899*0Sstevel@tonic-gate 		 */
1900*0Sstevel@tonic-gate 		if (pltsz != 0) {
1901*0Sstevel@tonic-gate 			sp->sh_name = 35;
1902*0Sstevel@tonic-gate 			sp->sh_type = SHT_PROGBITS;
1903*0Sstevel@tonic-gate 			sp->sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
1904*0Sstevel@tonic-gate 			sp->sh_addr = d[DI_PLTGOT]->d_un.d_ptr;
1905*0Sstevel@tonic-gate 			if (ehdr.e_type == ET_DYN)
1906*0Sstevel@tonic-gate 				sp->sh_addr -= addr;
1907*0Sstevel@tonic-gate 			sp->sh_offset = off;
1908*0Sstevel@tonic-gate 			sp->sh_size = pltsz;
1909*0Sstevel@tonic-gate 			sp->sh_link = 0;
1910*0Sstevel@tonic-gate 			sp->sh_info = 0;
1911*0Sstevel@tonic-gate 			sp->sh_addralign = 8;
1912*0Sstevel@tonic-gate 			sp->sh_entsize = pltentsz;
1913*0Sstevel@tonic-gate 
1914*0Sstevel@tonic-gate 			if (Pread(P, &elfdata[off], sp->sh_size,
1915*0Sstevel@tonic-gate 			    d[DI_PLTGOT]->d_un.d_ptr) != sp->sh_size) {
1916*0Sstevel@tonic-gate 				free(elfdata);
1917*0Sstevel@tonic-gate 				goto bad64;
1918*0Sstevel@tonic-gate 			}
1919*0Sstevel@tonic-gate 			off += roundup(sp->sh_size, 8);
1920*0Sstevel@tonic-gate 			sp++;
1921*0Sstevel@tonic-gate 		}
1922*0Sstevel@tonic-gate 
1923*0Sstevel@tonic-gate 		free(dp);
1924*0Sstevel@tonic-gate 		goto good;
1925*0Sstevel@tonic-gate 
1926*0Sstevel@tonic-gate bad64:
1927*0Sstevel@tonic-gate 		free(dp);
1928*0Sstevel@tonic-gate 		return (NULL);
1929*0Sstevel@tonic-gate #endif	/* _LP64 */
1930*0Sstevel@tonic-gate 	}
1931*0Sstevel@tonic-gate good:
1932*0Sstevel@tonic-gate 	if ((elf = elf_memory(elfdata, size)) == NULL) {
1933*0Sstevel@tonic-gate 		free(elfdata);
1934*0Sstevel@tonic-gate 		return (NULL);
1935*0Sstevel@tonic-gate 	}
1936*0Sstevel@tonic-gate 
1937*0Sstevel@tonic-gate 	fptr->file_elfmem = elfdata;
1938*0Sstevel@tonic-gate 
1939*0Sstevel@tonic-gate 	return (elf);
1940*0Sstevel@tonic-gate }
1941*0Sstevel@tonic-gate 
1942*0Sstevel@tonic-gate /*
1943*0Sstevel@tonic-gate  * We wouldn't need these if qsort(3C) took an argument for the callback...
1944*0Sstevel@tonic-gate  */
1945*0Sstevel@tonic-gate static mutex_t sort_mtx = DEFAULTMUTEX;
1946*0Sstevel@tonic-gate static char *sort_strs;
1947*0Sstevel@tonic-gate static GElf_Sym *sort_syms;
1948*0Sstevel@tonic-gate 
1949*0Sstevel@tonic-gate int
1950*0Sstevel@tonic-gate byaddr_cmp_common(GElf_Sym *a, char *aname, GElf_Sym *b, char *bname)
1951*0Sstevel@tonic-gate {
1952*0Sstevel@tonic-gate 	if (a->st_value < b->st_value)
1953*0Sstevel@tonic-gate 		return (-1);
1954*0Sstevel@tonic-gate 	if (a->st_value > b->st_value)
1955*0Sstevel@tonic-gate 		return (1);
1956*0Sstevel@tonic-gate 
1957*0Sstevel@tonic-gate 	/*
1958*0Sstevel@tonic-gate 	 * Prefer the function to the non-function.
1959*0Sstevel@tonic-gate 	 */
1960*0Sstevel@tonic-gate 	if (GELF_ST_TYPE(a->st_info) != GELF_ST_TYPE(b->st_info)) {
1961*0Sstevel@tonic-gate 		if (GELF_ST_TYPE(a->st_info) == STT_FUNC)
1962*0Sstevel@tonic-gate 			return (-1);
1963*0Sstevel@tonic-gate 		if (GELF_ST_TYPE(b->st_info) == STT_FUNC)
1964*0Sstevel@tonic-gate 			return (1);
1965*0Sstevel@tonic-gate 	}
1966*0Sstevel@tonic-gate 
1967*0Sstevel@tonic-gate 	/*
1968*0Sstevel@tonic-gate 	 * Prefer the weak or strong global symbol to the local symbol.
1969*0Sstevel@tonic-gate 	 */
1970*0Sstevel@tonic-gate 	if (GELF_ST_BIND(a->st_info) != GELF_ST_BIND(b->st_info)) {
1971*0Sstevel@tonic-gate 		if (GELF_ST_BIND(b->st_info) == STB_LOCAL)
1972*0Sstevel@tonic-gate 			return (-1);
1973*0Sstevel@tonic-gate 		if (GELF_ST_BIND(a->st_info) == STB_LOCAL)
1974*0Sstevel@tonic-gate 			return (1);
1975*0Sstevel@tonic-gate 	}
1976*0Sstevel@tonic-gate 
1977*0Sstevel@tonic-gate 	/*
1978*0Sstevel@tonic-gate 	 * Prefer the name with fewer leading underscores in the name.
1979*0Sstevel@tonic-gate 	 */
1980*0Sstevel@tonic-gate 	while (*aname == '_' && *bname == '_') {
1981*0Sstevel@tonic-gate 		aname++;
1982*0Sstevel@tonic-gate 		bname++;
1983*0Sstevel@tonic-gate 	}
1984*0Sstevel@tonic-gate 
1985*0Sstevel@tonic-gate 	if (*bname == '_')
1986*0Sstevel@tonic-gate 		return (-1);
1987*0Sstevel@tonic-gate 	if (*aname == '_')
1988*0Sstevel@tonic-gate 		return (1);
1989*0Sstevel@tonic-gate 
1990*0Sstevel@tonic-gate 	/*
1991*0Sstevel@tonic-gate 	 * Prefer the symbol with the smaller size.
1992*0Sstevel@tonic-gate 	 */
1993*0Sstevel@tonic-gate 	if (a->st_size < b->st_size)
1994*0Sstevel@tonic-gate 		return (-1);
1995*0Sstevel@tonic-gate 	if (a->st_size > b->st_size)
1996*0Sstevel@tonic-gate 		return (1);
1997*0Sstevel@tonic-gate 
1998*0Sstevel@tonic-gate 	/*
1999*0Sstevel@tonic-gate 	 * All other factors being equal, fall back to lexicographic order.
2000*0Sstevel@tonic-gate 	 */
2001*0Sstevel@tonic-gate 	return (strcmp(aname, bname));
2002*0Sstevel@tonic-gate }
2003*0Sstevel@tonic-gate 
2004*0Sstevel@tonic-gate static int
2005*0Sstevel@tonic-gate byaddr_cmp(const void *aa, const void *bb)
2006*0Sstevel@tonic-gate {
2007*0Sstevel@tonic-gate 	GElf_Sym *a = &sort_syms[*(uint_t *)aa];
2008*0Sstevel@tonic-gate 	GElf_Sym *b = &sort_syms[*(uint_t *)bb];
2009*0Sstevel@tonic-gate 	char *aname = sort_strs + a->st_name;
2010*0Sstevel@tonic-gate 	char *bname = sort_strs + b->st_name;
2011*0Sstevel@tonic-gate 
2012*0Sstevel@tonic-gate 	return (byaddr_cmp_common(a, aname, b, bname));
2013*0Sstevel@tonic-gate }
2014*0Sstevel@tonic-gate 
2015*0Sstevel@tonic-gate static int
2016*0Sstevel@tonic-gate byname_cmp(const void *aa, const void *bb)
2017*0Sstevel@tonic-gate {
2018*0Sstevel@tonic-gate 	GElf_Sym *a = &sort_syms[*(uint_t *)aa];
2019*0Sstevel@tonic-gate 	GElf_Sym *b = &sort_syms[*(uint_t *)bb];
2020*0Sstevel@tonic-gate 	char *aname = sort_strs + a->st_name;
2021*0Sstevel@tonic-gate 	char *bname = sort_strs + b->st_name;
2022*0Sstevel@tonic-gate 
2023*0Sstevel@tonic-gate 	return (strcmp(aname, bname));
2024*0Sstevel@tonic-gate }
2025*0Sstevel@tonic-gate 
2026*0Sstevel@tonic-gate void
2027*0Sstevel@tonic-gate optimize_symtab(sym_tbl_t *symtab)
2028*0Sstevel@tonic-gate {
2029*0Sstevel@tonic-gate 	GElf_Sym *symp, *syms;
2030*0Sstevel@tonic-gate 	uint_t i, *indexa, *indexb;
2031*0Sstevel@tonic-gate 	Elf_Data *data;
2032*0Sstevel@tonic-gate 	size_t symn, strsz, count;
2033*0Sstevel@tonic-gate 
2034*0Sstevel@tonic-gate 	if (symtab == NULL || symtab->sym_data == NULL ||
2035*0Sstevel@tonic-gate 	    symtab->sym_byaddr != NULL)
2036*0Sstevel@tonic-gate 		return;
2037*0Sstevel@tonic-gate 
2038*0Sstevel@tonic-gate 	data = symtab->sym_data;
2039*0Sstevel@tonic-gate 	symn = symtab->sym_symn;
2040*0Sstevel@tonic-gate 	strsz = symtab->sym_strsz;
2041*0Sstevel@tonic-gate 
2042*0Sstevel@tonic-gate 	symp = syms = malloc(sizeof (GElf_Sym) * symn);
2043*0Sstevel@tonic-gate 
2044*0Sstevel@tonic-gate 	/*
2045*0Sstevel@tonic-gate 	 * First record all the symbols into a table and count up the ones
2046*0Sstevel@tonic-gate 	 * that we're interested in. We mark symbols as invalid by setting
2047*0Sstevel@tonic-gate 	 * the st_name to an illegal value.
2048*0Sstevel@tonic-gate 	 */
2049*0Sstevel@tonic-gate 	for (i = 0, count = 0; i < symn; i++, symp++) {
2050*0Sstevel@tonic-gate 		if (gelf_getsym(data, i, symp) != NULL &&
2051*0Sstevel@tonic-gate 		    symp->st_name < strsz &&
2052*0Sstevel@tonic-gate 		    IS_DATA_TYPE(GELF_ST_TYPE(symp->st_info)))
2053*0Sstevel@tonic-gate 			count++;
2054*0Sstevel@tonic-gate 		else
2055*0Sstevel@tonic-gate 			symp->st_name = strsz;
2056*0Sstevel@tonic-gate 	}
2057*0Sstevel@tonic-gate 
2058*0Sstevel@tonic-gate 	/*
2059*0Sstevel@tonic-gate 	 * Allocate sufficient space for both tables and populate them
2060*0Sstevel@tonic-gate 	 * with the same symbols we just counted.
2061*0Sstevel@tonic-gate 	 */
2062*0Sstevel@tonic-gate 	symtab->sym_count = count;
2063*0Sstevel@tonic-gate 	indexa = symtab->sym_byaddr = calloc(sizeof (uint_t), count);
2064*0Sstevel@tonic-gate 	indexb = symtab->sym_byname = calloc(sizeof (uint_t), count);
2065*0Sstevel@tonic-gate 
2066*0Sstevel@tonic-gate 	for (i = 0, symp = syms; i < symn; i++, symp++) {
2067*0Sstevel@tonic-gate 		if (symp->st_name < strsz)
2068*0Sstevel@tonic-gate 			*indexa++ = *indexb++ = i;
2069*0Sstevel@tonic-gate 	}
2070*0Sstevel@tonic-gate 
2071*0Sstevel@tonic-gate 	/*
2072*0Sstevel@tonic-gate 	 * Sort the two tables according to the appropriate criteria.
2073*0Sstevel@tonic-gate 	 */
2074*0Sstevel@tonic-gate 	(void) mutex_lock(&sort_mtx);
2075*0Sstevel@tonic-gate 	sort_strs = symtab->sym_strs;
2076*0Sstevel@tonic-gate 	sort_syms = syms;
2077*0Sstevel@tonic-gate 
2078*0Sstevel@tonic-gate 	qsort(symtab->sym_byaddr, count, sizeof (uint_t), byaddr_cmp);
2079*0Sstevel@tonic-gate 	qsort(symtab->sym_byname, count, sizeof (uint_t), byname_cmp);
2080*0Sstevel@tonic-gate 
2081*0Sstevel@tonic-gate 	sort_strs = NULL;
2082*0Sstevel@tonic-gate 	sort_syms = NULL;
2083*0Sstevel@tonic-gate 	(void) mutex_unlock(&sort_mtx);
2084*0Sstevel@tonic-gate 
2085*0Sstevel@tonic-gate 	free(syms);
2086*0Sstevel@tonic-gate }
2087*0Sstevel@tonic-gate 
2088*0Sstevel@tonic-gate /*
2089*0Sstevel@tonic-gate  * Build the symbol table for the given mapped file.
2090*0Sstevel@tonic-gate  */
2091*0Sstevel@tonic-gate void
2092*0Sstevel@tonic-gate Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
2093*0Sstevel@tonic-gate {
2094*0Sstevel@tonic-gate 	char objectfile[PATH_MAX];
2095*0Sstevel@tonic-gate 	uint_t i;
2096*0Sstevel@tonic-gate 
2097*0Sstevel@tonic-gate 	GElf_Ehdr ehdr;
2098*0Sstevel@tonic-gate 	GElf_Sym s;
2099*0Sstevel@tonic-gate 
2100*0Sstevel@tonic-gate 	Elf_Data *shdata;
2101*0Sstevel@tonic-gate 	Elf_Scn *scn;
2102*0Sstevel@tonic-gate 	Elf *elf;
2103*0Sstevel@tonic-gate 
2104*0Sstevel@tonic-gate 	struct {
2105*0Sstevel@tonic-gate 		GElf_Shdr c_shdr;
2106*0Sstevel@tonic-gate 		Elf_Data *c_data;
2107*0Sstevel@tonic-gate 		const char *c_name;
2108*0Sstevel@tonic-gate 	} *cp, *cache = NULL, *dyn = NULL, *plt = NULL, *ctf = NULL;
2109*0Sstevel@tonic-gate 
2110*0Sstevel@tonic-gate 	if (fptr->file_init)
2111*0Sstevel@tonic-gate 		return;	/* We've already processed this file */
2112*0Sstevel@tonic-gate 
2113*0Sstevel@tonic-gate 	/*
2114*0Sstevel@tonic-gate 	 * Mark the file_info struct as having the symbol table initialized
2115*0Sstevel@tonic-gate 	 * even if we fail below.  We tried once; we don't try again.
2116*0Sstevel@tonic-gate 	 */
2117*0Sstevel@tonic-gate 	fptr->file_init = 1;
2118*0Sstevel@tonic-gate 
2119*0Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
2120*0Sstevel@tonic-gate 		dprintf("libproc ELF version is more recent than libelf\n");
2121*0Sstevel@tonic-gate 		return;
2122*0Sstevel@tonic-gate 	}
2123*0Sstevel@tonic-gate 
2124*0Sstevel@tonic-gate 	if (P->state == PS_DEAD || P->state == PS_IDLE) {
2125*0Sstevel@tonic-gate 		/*
2126*0Sstevel@tonic-gate 		 * If we're a not live, we can't open files from the /proc
2127*0Sstevel@tonic-gate 		 * object directory; we have only the mapping and file names
2128*0Sstevel@tonic-gate 		 * to guide us.  We prefer the file_lname, but need to handle
2129*0Sstevel@tonic-gate 		 * the case of it being NULL in order to bootstrap: we first
2130*0Sstevel@tonic-gate 		 * come here during rd_new() when the only information we have
2131*0Sstevel@tonic-gate 		 * is interpreter name associated with the AT_BASE mapping.
2132*0Sstevel@tonic-gate 		 */
2133*0Sstevel@tonic-gate 		(void) snprintf(objectfile, sizeof (objectfile), "%s",
2134*0Sstevel@tonic-gate 		    fptr->file_lname ? fptr->file_lname : fptr->file_pname);
2135*0Sstevel@tonic-gate 	} else {
2136*0Sstevel@tonic-gate 		(void) snprintf(objectfile, sizeof (objectfile),
2137*0Sstevel@tonic-gate 		    "/proc/%d/object/%s", (int)P->pid, fptr->file_pname);
2138*0Sstevel@tonic-gate 	}
2139*0Sstevel@tonic-gate 
2140*0Sstevel@tonic-gate 	/*
2141*0Sstevel@tonic-gate 	 * Open the object file, create the elf file, and then get the elf
2142*0Sstevel@tonic-gate 	 * header and .shstrtab data buffer so we can process sections by
2143*0Sstevel@tonic-gate 	 * name. If anything goes wrong try to fake up an elf file from
2144*0Sstevel@tonic-gate 	 * the in-core elf image.
2145*0Sstevel@tonic-gate 	 */
2146*0Sstevel@tonic-gate 	if ((fptr->file_fd = open(objectfile, O_RDONLY)) < 0) {
2147*0Sstevel@tonic-gate 		dprintf("Pbuild_file_symtab: failed to open %s: %s\n",
2148*0Sstevel@tonic-gate 		    objectfile, strerror(errno));
2149*0Sstevel@tonic-gate 
2150*0Sstevel@tonic-gate 		if ((elf = fake_elf(P, fptr)) == NULL ||
2151*0Sstevel@tonic-gate 		    elf_kind(elf) != ELF_K_ELF ||
2152*0Sstevel@tonic-gate 		    gelf_getehdr(elf, &ehdr) == NULL ||
2153*0Sstevel@tonic-gate 		    (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL ||
2154*0Sstevel@tonic-gate 		    (shdata = elf_getdata(scn, NULL)) == NULL) {
2155*0Sstevel@tonic-gate 			dprintf("failed to fake up ELF file\n");
2156*0Sstevel@tonic-gate 			return;
2157*0Sstevel@tonic-gate 		}
2158*0Sstevel@tonic-gate 
2159*0Sstevel@tonic-gate 	} else if ((elf = elf_begin(fptr->file_fd, ELF_C_READ, NULL)) == NULL ||
2160*0Sstevel@tonic-gate 	    elf_kind(elf) != ELF_K_ELF ||
2161*0Sstevel@tonic-gate 	    gelf_getehdr(elf, &ehdr) == NULL ||
2162*0Sstevel@tonic-gate 	    (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL ||
2163*0Sstevel@tonic-gate 	    (shdata = elf_getdata(scn, NULL)) == NULL) {
2164*0Sstevel@tonic-gate 		dprintf("failed to process ELF file %s: %s\n",
2165*0Sstevel@tonic-gate 		    objectfile, elf_errmsg(elf_errno()));
2166*0Sstevel@tonic-gate 
2167*0Sstevel@tonic-gate 		if ((elf = fake_elf(P, fptr)) == NULL ||
2168*0Sstevel@tonic-gate 		    elf_kind(elf) != ELF_K_ELF ||
2169*0Sstevel@tonic-gate 		    gelf_getehdr(elf, &ehdr) == NULL ||
2170*0Sstevel@tonic-gate 		    (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL ||
2171*0Sstevel@tonic-gate 		    (shdata = elf_getdata(scn, NULL)) == NULL) {
2172*0Sstevel@tonic-gate 			dprintf("failed to fake up ELF file\n");
2173*0Sstevel@tonic-gate 			goto bad;
2174*0Sstevel@tonic-gate 		}
2175*0Sstevel@tonic-gate 
2176*0Sstevel@tonic-gate 	} else if (file_differs(P, elf, fptr)) {
2177*0Sstevel@tonic-gate 		Elf *newelf;
2178*0Sstevel@tonic-gate 
2179*0Sstevel@tonic-gate 		/*
2180*0Sstevel@tonic-gate 		 * Before we get too excited about this elf file, we'll check
2181*0Sstevel@tonic-gate 		 * its checksum value against the value we have in memory. If
2182*0Sstevel@tonic-gate 		 * they don't agree, we try to fake up a new elf file and
2183*0Sstevel@tonic-gate 		 * proceed with that instead.
2184*0Sstevel@tonic-gate 		 */
2185*0Sstevel@tonic-gate 
2186*0Sstevel@tonic-gate 		dprintf("ELF file %s (%lx) doesn't match in-core image\n",
2187*0Sstevel@tonic-gate 		    fptr->file_pname,
2188*0Sstevel@tonic-gate 		    (ulong_t)fptr->file_map->map_pmap.pr_vaddr);
2189*0Sstevel@tonic-gate 
2190*0Sstevel@tonic-gate 		if ((newelf = fake_elf(P, fptr)) == NULL ||
2191*0Sstevel@tonic-gate 		    elf_kind(newelf) != ELF_K_ELF ||
2192*0Sstevel@tonic-gate 		    gelf_getehdr(newelf, &ehdr) == NULL ||
2193*0Sstevel@tonic-gate 		    (scn = elf_getscn(newelf, ehdr.e_shstrndx)) == NULL ||
2194*0Sstevel@tonic-gate 		    (shdata = elf_getdata(scn, NULL)) == NULL) {
2195*0Sstevel@tonic-gate 			dprintf("failed to fake up ELF file\n");
2196*0Sstevel@tonic-gate 		} else {
2197*0Sstevel@tonic-gate 			(void) elf_end(elf);
2198*0Sstevel@tonic-gate 			elf = newelf;
2199*0Sstevel@tonic-gate 
2200*0Sstevel@tonic-gate 			dprintf("switched to faked up ELF file\n");
2201*0Sstevel@tonic-gate 		}
2202*0Sstevel@tonic-gate 	}
2203*0Sstevel@tonic-gate 
2204*0Sstevel@tonic-gate 	if ((cache = malloc(ehdr.e_shnum * sizeof (*cache))) == NULL) {
2205*0Sstevel@tonic-gate 		dprintf("failed to malloc section cache for %s\n", objectfile);
2206*0Sstevel@tonic-gate 		goto bad;
2207*0Sstevel@tonic-gate 	}
2208*0Sstevel@tonic-gate 
2209*0Sstevel@tonic-gate 	dprintf("processing ELF file %s\n", objectfile);
2210*0Sstevel@tonic-gate 	fptr->file_class = ehdr.e_ident[EI_CLASS];
2211*0Sstevel@tonic-gate 	fptr->file_etype = ehdr.e_type;
2212*0Sstevel@tonic-gate 	fptr->file_elf = elf;
2213*0Sstevel@tonic-gate 
2214*0Sstevel@tonic-gate 	/*
2215*0Sstevel@tonic-gate 	 * Iterate through each section, caching its section header, data
2216*0Sstevel@tonic-gate 	 * pointer, and name.  We use this for handling sh_link values below.
2217*0Sstevel@tonic-gate 	 */
2218*0Sstevel@tonic-gate 	for (cp = cache + 1, scn = NULL; scn = elf_nextscn(elf, scn); cp++) {
2219*0Sstevel@tonic-gate 		if (gelf_getshdr(scn, &cp->c_shdr) == NULL)
2220*0Sstevel@tonic-gate 			goto bad; /* Failed to get section header */
2221*0Sstevel@tonic-gate 
2222*0Sstevel@tonic-gate 		if ((cp->c_data = elf_getdata(scn, NULL)) == NULL)
2223*0Sstevel@tonic-gate 			goto bad; /* Failed to get section data */
2224*0Sstevel@tonic-gate 
2225*0Sstevel@tonic-gate 		if (cp->c_shdr.sh_name >= shdata->d_size)
2226*0Sstevel@tonic-gate 			goto bad; /* Corrupt section name */
2227*0Sstevel@tonic-gate 
2228*0Sstevel@tonic-gate 		cp->c_name = (const char *)shdata->d_buf + cp->c_shdr.sh_name;
2229*0Sstevel@tonic-gate 	}
2230*0Sstevel@tonic-gate 
2231*0Sstevel@tonic-gate 	/*
2232*0Sstevel@tonic-gate 	 * Now iterate through the section cache in order to locate info
2233*0Sstevel@tonic-gate 	 * for the .symtab, .dynsym, .dynamic, .plt, and .SUNW_ctf sections:
2234*0Sstevel@tonic-gate 	 */
2235*0Sstevel@tonic-gate 	for (i = 1, cp = cache + 1; i < ehdr.e_shnum; i++, cp++) {
2236*0Sstevel@tonic-gate 		GElf_Shdr *shp = &cp->c_shdr;
2237*0Sstevel@tonic-gate 
2238*0Sstevel@tonic-gate 		if (shp->sh_type == SHT_SYMTAB || shp->sh_type == SHT_DYNSYM) {
2239*0Sstevel@tonic-gate 			sym_tbl_t *symp = shp->sh_type == SHT_SYMTAB ?
2240*0Sstevel@tonic-gate 			    &fptr->file_symtab : &fptr->file_dynsym;
2241*0Sstevel@tonic-gate 
2242*0Sstevel@tonic-gate 			/*
2243*0Sstevel@tonic-gate 			 * It's possible that the we already got the symbol
2244*0Sstevel@tonic-gate 			 * table from the core file itself. Either the file
2245*0Sstevel@tonic-gate 			 * differs in which case our faked up elf file will
2246*0Sstevel@tonic-gate 			 * only contain the dynsym (not the symtab) or the
2247*0Sstevel@tonic-gate 			 * file matches in which case we'll just be replacing
2248*0Sstevel@tonic-gate 			 * the symbol table we pulled out of the core file
2249*0Sstevel@tonic-gate 			 * with an equivalent one. In either case, this
2250*0Sstevel@tonic-gate 			 * check isn't essential, but it's a good idea.
2251*0Sstevel@tonic-gate 			 */
2252*0Sstevel@tonic-gate 			if (symp->sym_data == NULL) {
2253*0Sstevel@tonic-gate 				symp->sym_data = cp->c_data;
2254*0Sstevel@tonic-gate 				symp->sym_symn = shp->sh_size / shp->sh_entsize;
2255*0Sstevel@tonic-gate 				symp->sym_strs =
2256*0Sstevel@tonic-gate 				    cache[shp->sh_link].c_data->d_buf;
2257*0Sstevel@tonic-gate 				symp->sym_strsz =
2258*0Sstevel@tonic-gate 				    cache[shp->sh_link].c_data->d_size;
2259*0Sstevel@tonic-gate 				symp->sym_hdr = cp->c_shdr;
2260*0Sstevel@tonic-gate 				symp->sym_strhdr = cache[shp->sh_link].c_shdr;
2261*0Sstevel@tonic-gate 			}
2262*0Sstevel@tonic-gate 
2263*0Sstevel@tonic-gate 		} else if (shp->sh_type == SHT_DYNAMIC) {
2264*0Sstevel@tonic-gate 			dyn = cp;
2265*0Sstevel@tonic-gate 
2266*0Sstevel@tonic-gate 		} else if (strcmp(cp->c_name, ".plt") == 0) {
2267*0Sstevel@tonic-gate 			plt = cp;
2268*0Sstevel@tonic-gate 
2269*0Sstevel@tonic-gate 		} else if (strcmp(cp->c_name, ".SUNW_ctf") == 0) {
2270*0Sstevel@tonic-gate 			/*
2271*0Sstevel@tonic-gate 			 * Skip over bogus CTF sections so they don't come back
2272*0Sstevel@tonic-gate 			 * to haunt us later.
2273*0Sstevel@tonic-gate 			 */
2274*0Sstevel@tonic-gate 			if (shp->sh_link == 0 ||
2275*0Sstevel@tonic-gate 			    shp->sh_link > ehdr.e_shnum ||
2276*0Sstevel@tonic-gate 			    (cache[shp->sh_link].c_shdr.sh_type != SHT_DYNSYM &&
2277*0Sstevel@tonic-gate 			    cache[shp->sh_link].c_shdr.sh_type != SHT_SYMTAB)) {
2278*0Sstevel@tonic-gate 				dprintf("Bad sh_link %d for "
2279*0Sstevel@tonic-gate 				    "CTF\n", shp->sh_link);
2280*0Sstevel@tonic-gate 				continue;
2281*0Sstevel@tonic-gate 			}
2282*0Sstevel@tonic-gate 			ctf = cp;
2283*0Sstevel@tonic-gate 		}
2284*0Sstevel@tonic-gate 	}
2285*0Sstevel@tonic-gate 
2286*0Sstevel@tonic-gate 	/*
2287*0Sstevel@tonic-gate 	 * At this point, we've found all the symbol tables we're ever going
2288*0Sstevel@tonic-gate 	 * to find: the ones in the loop above and possibly the symtab that
2289*0Sstevel@tonic-gate 	 * was included in the core file. Before we perform any lookups, we
2290*0Sstevel@tonic-gate 	 * create sorted versions to optimize for lookups.
2291*0Sstevel@tonic-gate 	 */
2292*0Sstevel@tonic-gate 	optimize_symtab(&fptr->file_symtab);
2293*0Sstevel@tonic-gate 	optimize_symtab(&fptr->file_dynsym);
2294*0Sstevel@tonic-gate 
2295*0Sstevel@tonic-gate 	/*
2296*0Sstevel@tonic-gate 	 * Fill in the base address of the text mapping for shared libraries.
2297*0Sstevel@tonic-gate 	 * This allows us to translate symbols before librtld_db is ready.
2298*0Sstevel@tonic-gate 	 */
2299*0Sstevel@tonic-gate 	if (fptr->file_etype == ET_DYN) {
2300*0Sstevel@tonic-gate 		fptr->file_dyn_base = fptr->file_map->map_pmap.pr_vaddr -
2301*0Sstevel@tonic-gate 		    fptr->file_map->map_pmap.pr_offset;
2302*0Sstevel@tonic-gate 		dprintf("setting file_dyn_base for %s to %p\n",
2303*0Sstevel@tonic-gate 		    objectfile, (void *)fptr->file_dyn_base);
2304*0Sstevel@tonic-gate 	}
2305*0Sstevel@tonic-gate 
2306*0Sstevel@tonic-gate 	/*
2307*0Sstevel@tonic-gate 	 * Record the CTF section information in the file info structure.
2308*0Sstevel@tonic-gate 	 */
2309*0Sstevel@tonic-gate 	if (ctf != NULL) {
2310*0Sstevel@tonic-gate 		fptr->file_ctf_off = ctf->c_shdr.sh_offset;
2311*0Sstevel@tonic-gate 		fptr->file_ctf_size = ctf->c_shdr.sh_size;
2312*0Sstevel@tonic-gate 		if (ctf->c_shdr.sh_link != 0 &&
2313*0Sstevel@tonic-gate 		    cache[ctf->c_shdr.sh_link].c_shdr.sh_type == SHT_DYNSYM)
2314*0Sstevel@tonic-gate 			fptr->file_ctf_dyn = 1;
2315*0Sstevel@tonic-gate 	}
2316*0Sstevel@tonic-gate 
2317*0Sstevel@tonic-gate 	if (fptr->file_lo == NULL)
2318*0Sstevel@tonic-gate 		goto done; /* Nothing else to do if no load object info */
2319*0Sstevel@tonic-gate 
2320*0Sstevel@tonic-gate 	/*
2321*0Sstevel@tonic-gate 	 * If the object is a shared library and we have a different rl_base
2322*0Sstevel@tonic-gate 	 * value, reset file_dyn_base according to librtld_db's information.
2323*0Sstevel@tonic-gate 	 */
2324*0Sstevel@tonic-gate 	if (fptr->file_etype == ET_DYN &&
2325*0Sstevel@tonic-gate 	    fptr->file_lo->rl_base != fptr->file_dyn_base) {
2326*0Sstevel@tonic-gate 		dprintf("resetting file_dyn_base for %s to %p\n",
2327*0Sstevel@tonic-gate 		    objectfile, (void *)fptr->file_lo->rl_base);
2328*0Sstevel@tonic-gate 		fptr->file_dyn_base = fptr->file_lo->rl_base;
2329*0Sstevel@tonic-gate 	}
2330*0Sstevel@tonic-gate 
2331*0Sstevel@tonic-gate 	/*
2332*0Sstevel@tonic-gate 	 * Fill in the PLT information for this file if a PLT symbol is found.
2333*0Sstevel@tonic-gate 	 */
2334*0Sstevel@tonic-gate 	if (sym_by_name(&fptr->file_dynsym, "_PROCEDURE_LINKAGE_TABLE_", &s,
2335*0Sstevel@tonic-gate 	    NULL) != NULL) {
2336*0Sstevel@tonic-gate 		fptr->file_plt_base = s.st_value + fptr->file_dyn_base;
2337*0Sstevel@tonic-gate 		fptr->file_plt_size = (plt != NULL) ? plt->c_shdr.sh_size : 0;
2338*0Sstevel@tonic-gate 
2339*0Sstevel@tonic-gate 		/*
2340*0Sstevel@tonic-gate 		 * Bring the load object up to date; it is the only way the
2341*0Sstevel@tonic-gate 		 * user has to access the PLT data. The PLT information in the
2342*0Sstevel@tonic-gate 		 * rd_loadobj_t is not set in the call to map_iter() (the
2343*0Sstevel@tonic-gate 		 * callback for rd_loadobj_iter) where we set file_lo.
2344*0Sstevel@tonic-gate 		 */
2345*0Sstevel@tonic-gate 		fptr->file_lo->rl_plt_base = fptr->file_plt_base;
2346*0Sstevel@tonic-gate 		fptr->file_lo->rl_plt_size = fptr->file_plt_size;
2347*0Sstevel@tonic-gate 
2348*0Sstevel@tonic-gate 		dprintf("PLT found at %p, size = %lu\n",
2349*0Sstevel@tonic-gate 		    (void *)fptr->file_plt_base, (ulong_t)fptr->file_plt_size);
2350*0Sstevel@tonic-gate 	}
2351*0Sstevel@tonic-gate 
2352*0Sstevel@tonic-gate 	/*
2353*0Sstevel@tonic-gate 	 * Fill in the PLT information.
2354*0Sstevel@tonic-gate 	 */
2355*0Sstevel@tonic-gate 	if (dyn != NULL) {
2356*0Sstevel@tonic-gate 		uintptr_t dynaddr = dyn->c_shdr.sh_addr + fptr->file_dyn_base;
2357*0Sstevel@tonic-gate 		size_t ndyn = dyn->c_shdr.sh_size / dyn->c_shdr.sh_entsize;
2358*0Sstevel@tonic-gate 		GElf_Dyn d;
2359*0Sstevel@tonic-gate 
2360*0Sstevel@tonic-gate 		for (i = 0; i < ndyn; i++) {
2361*0Sstevel@tonic-gate 			if (gelf_getdyn(dyn->c_data, i, &d) != NULL &&
2362*0Sstevel@tonic-gate 			    d.d_tag == DT_JMPREL) {
2363*0Sstevel@tonic-gate 				fptr->file_jmp_rel =
2364*0Sstevel@tonic-gate 				    d.d_un.d_ptr + fptr->file_dyn_base;
2365*0Sstevel@tonic-gate 				break;
2366*0Sstevel@tonic-gate 			}
2367*0Sstevel@tonic-gate 		}
2368*0Sstevel@tonic-gate 
2369*0Sstevel@tonic-gate 		dprintf("_DYNAMIC found at %p, %lu entries, DT_JMPREL = %p\n",
2370*0Sstevel@tonic-gate 		    (void *)dynaddr, (ulong_t)ndyn, (void *)fptr->file_jmp_rel);
2371*0Sstevel@tonic-gate 	}
2372*0Sstevel@tonic-gate 
2373*0Sstevel@tonic-gate done:
2374*0Sstevel@tonic-gate 	free(cache);
2375*0Sstevel@tonic-gate 	return;
2376*0Sstevel@tonic-gate 
2377*0Sstevel@tonic-gate bad:
2378*0Sstevel@tonic-gate 	if (cache != NULL)
2379*0Sstevel@tonic-gate 		free(cache);
2380*0Sstevel@tonic-gate 
2381*0Sstevel@tonic-gate 	(void) elf_end(elf);
2382*0Sstevel@tonic-gate 	fptr->file_elf = NULL;
2383*0Sstevel@tonic-gate 	if (fptr->file_elfmem != NULL) {
2384*0Sstevel@tonic-gate 		free(fptr->file_elfmem);
2385*0Sstevel@tonic-gate 		fptr->file_elfmem = NULL;
2386*0Sstevel@tonic-gate 	}
2387*0Sstevel@tonic-gate 	(void) close(fptr->file_fd);
2388*0Sstevel@tonic-gate 	fptr->file_fd = -1;
2389*0Sstevel@tonic-gate }
2390*0Sstevel@tonic-gate 
2391*0Sstevel@tonic-gate /*
2392*0Sstevel@tonic-gate  * Given a process virtual address, return the map_info_t containing it.
2393*0Sstevel@tonic-gate  * If none found, return NULL.
2394*0Sstevel@tonic-gate  */
2395*0Sstevel@tonic-gate map_info_t *
2396*0Sstevel@tonic-gate Paddr2mptr(struct ps_prochandle *P, uintptr_t addr)
2397*0Sstevel@tonic-gate {
2398*0Sstevel@tonic-gate 	int lo = 0;
2399*0Sstevel@tonic-gate 	int hi = P->map_count - 1;
2400*0Sstevel@tonic-gate 	int mid;
2401*0Sstevel@tonic-gate 	map_info_t *mp;
2402*0Sstevel@tonic-gate 
2403*0Sstevel@tonic-gate 	while (lo <= hi) {
2404*0Sstevel@tonic-gate 
2405*0Sstevel@tonic-gate 		mid = (lo + hi) / 2;
2406*0Sstevel@tonic-gate 		mp = &P->mappings[mid];
2407*0Sstevel@tonic-gate 
2408*0Sstevel@tonic-gate 		/* check that addr is in [vaddr, vaddr + size) */
2409*0Sstevel@tonic-gate 		if ((addr - mp->map_pmap.pr_vaddr) < mp->map_pmap.pr_size)
2410*0Sstevel@tonic-gate 			return (mp);
2411*0Sstevel@tonic-gate 
2412*0Sstevel@tonic-gate 		if (addr < mp->map_pmap.pr_vaddr)
2413*0Sstevel@tonic-gate 			hi = mid - 1;
2414*0Sstevel@tonic-gate 		else
2415*0Sstevel@tonic-gate 			lo = mid + 1;
2416*0Sstevel@tonic-gate 	}
2417*0Sstevel@tonic-gate 
2418*0Sstevel@tonic-gate 	return (NULL);
2419*0Sstevel@tonic-gate }
2420*0Sstevel@tonic-gate 
2421*0Sstevel@tonic-gate /*
2422*0Sstevel@tonic-gate  * Return the map_info_t for the executable file.
2423*0Sstevel@tonic-gate  * If not found, return NULL.
2424*0Sstevel@tonic-gate  */
2425*0Sstevel@tonic-gate static map_info_t *
2426*0Sstevel@tonic-gate exec_map(struct ps_prochandle *P)
2427*0Sstevel@tonic-gate {
2428*0Sstevel@tonic-gate 	uint_t i;
2429*0Sstevel@tonic-gate 	map_info_t *mptr;
2430*0Sstevel@tonic-gate 	map_info_t *mold = NULL;
2431*0Sstevel@tonic-gate 	file_info_t *fptr;
2432*0Sstevel@tonic-gate 	uintptr_t base;
2433*0Sstevel@tonic-gate 
2434*0Sstevel@tonic-gate 	for (i = 0, mptr = P->mappings; i < P->map_count; i++, mptr++) {
2435*0Sstevel@tonic-gate 		if (mptr->map_pmap.pr_mapname[0] == '\0')
2436*0Sstevel@tonic-gate 			continue;
2437*0Sstevel@tonic-gate 		if (strcmp(mptr->map_pmap.pr_mapname, "a.out") == 0) {
2438*0Sstevel@tonic-gate 			if ((fptr = mptr->map_file) != NULL &&
2439*0Sstevel@tonic-gate 			    fptr->file_lo != NULL) {
2440*0Sstevel@tonic-gate 				base = fptr->file_lo->rl_base;
2441*0Sstevel@tonic-gate 				if (base >= mptr->map_pmap.pr_vaddr &&
2442*0Sstevel@tonic-gate 				    base < mptr->map_pmap.pr_vaddr +
2443*0Sstevel@tonic-gate 				    mptr->map_pmap.pr_size)	/* text space */
2444*0Sstevel@tonic-gate 					return (mptr);
2445*0Sstevel@tonic-gate 				mold = mptr;	/* must be the data */
2446*0Sstevel@tonic-gate 				continue;
2447*0Sstevel@tonic-gate 			}
2448*0Sstevel@tonic-gate 			/* This is a poor way to test for text space */
2449*0Sstevel@tonic-gate 			if (!(mptr->map_pmap.pr_mflags & MA_EXEC) ||
2450*0Sstevel@tonic-gate 			    (mptr->map_pmap.pr_mflags & MA_WRITE)) {
2451*0Sstevel@tonic-gate 				mold = mptr;
2452*0Sstevel@tonic-gate 				continue;
2453*0Sstevel@tonic-gate 			}
2454*0Sstevel@tonic-gate 			return (mptr);
2455*0Sstevel@tonic-gate 		}
2456*0Sstevel@tonic-gate 	}
2457*0Sstevel@tonic-gate 
2458*0Sstevel@tonic-gate 	return (mold);
2459*0Sstevel@tonic-gate }
2460*0Sstevel@tonic-gate 
2461*0Sstevel@tonic-gate /*
2462*0Sstevel@tonic-gate  * Given a shared object name, return the map_info_t for it.  If no matching
2463*0Sstevel@tonic-gate  * object is found, return NULL.  Normally, the link maps contain the full
2464*0Sstevel@tonic-gate  * object pathname, e.g. /usr/lib/libc.so.1.  We allow the object name to
2465*0Sstevel@tonic-gate  * take one of the following forms:
2466*0Sstevel@tonic-gate  *
2467*0Sstevel@tonic-gate  * 1. An exact match (i.e. a full pathname): "/usr/lib/libc.so.1"
2468*0Sstevel@tonic-gate  * 2. An exact basename match: "libc.so.1"
2469*0Sstevel@tonic-gate  * 3. An initial basename match up to a '.' suffix: "libc.so" or "libc"
2470*0Sstevel@tonic-gate  * 4. The literal string "a.out" is an alias for the executable mapping
2471*0Sstevel@tonic-gate  *
2472*0Sstevel@tonic-gate  * The third case is a convenience for callers and may not be necessary.
2473*0Sstevel@tonic-gate  *
2474*0Sstevel@tonic-gate  * As the exact same object name may be loaded on different link maps (see
2475*0Sstevel@tonic-gate  * dlmopen(3DL)), we also allow the caller to resolve the object name by
2476*0Sstevel@tonic-gate  * specifying a particular link map id.  If lmid is PR_LMID_EVERY, the
2477*0Sstevel@tonic-gate  * first matching name will be returned, regardless of the link map id.
2478*0Sstevel@tonic-gate  */
2479*0Sstevel@tonic-gate static map_info_t *
2480*0Sstevel@tonic-gate object_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *objname)
2481*0Sstevel@tonic-gate {
2482*0Sstevel@tonic-gate 	map_info_t *mp;
2483*0Sstevel@tonic-gate 	file_info_t *fp;
2484*0Sstevel@tonic-gate 	size_t objlen;
2485*0Sstevel@tonic-gate 	uint_t i;
2486*0Sstevel@tonic-gate 
2487*0Sstevel@tonic-gate 	/*
2488*0Sstevel@tonic-gate 	 * First pass: look for exact matches of the entire pathname or
2489*0Sstevel@tonic-gate 	 * basename (cases 1 and 2 above):
2490*0Sstevel@tonic-gate 	 */
2491*0Sstevel@tonic-gate 	for (i = 0, mp = P->mappings; i < P->map_count; i++, mp++) {
2492*0Sstevel@tonic-gate 
2493*0Sstevel@tonic-gate 		if (mp->map_pmap.pr_mapname[0] == '\0' ||
2494*0Sstevel@tonic-gate 		    (fp = mp->map_file) == NULL || fp->file_lname == NULL)
2495*0Sstevel@tonic-gate 			continue;
2496*0Sstevel@tonic-gate 
2497*0Sstevel@tonic-gate 		if (lmid != PR_LMID_EVERY &&
2498*0Sstevel@tonic-gate 		    (fp->file_lo == NULL || lmid != fp->file_lo->rl_lmident))
2499*0Sstevel@tonic-gate 			continue;
2500*0Sstevel@tonic-gate 
2501*0Sstevel@tonic-gate 		/*
2502*0Sstevel@tonic-gate 		 * If we match, return the primary text mapping; otherwise
2503*0Sstevel@tonic-gate 		 * just return the mapping we matched.
2504*0Sstevel@tonic-gate 		 */
2505*0Sstevel@tonic-gate 		if (strcmp(fp->file_lname, objname) == 0 ||
2506*0Sstevel@tonic-gate 		    strcmp(fp->file_lbase, objname) == 0)
2507*0Sstevel@tonic-gate 			return (fp->file_map ? fp->file_map : mp);
2508*0Sstevel@tonic-gate 	}
2509*0Sstevel@tonic-gate 
2510*0Sstevel@tonic-gate 	objlen = strlen(objname);
2511*0Sstevel@tonic-gate 
2512*0Sstevel@tonic-gate 	/*
2513*0Sstevel@tonic-gate 	 * Second pass: look for partial matches (case 3 above):
2514*0Sstevel@tonic-gate 	 */
2515*0Sstevel@tonic-gate 	for (i = 0, mp = P->mappings; i < P->map_count; i++, mp++) {
2516*0Sstevel@tonic-gate 
2517*0Sstevel@tonic-gate 		if (mp->map_pmap.pr_mapname[0] == '\0' ||
2518*0Sstevel@tonic-gate 		    (fp = mp->map_file) == NULL || fp->file_lname == NULL)
2519*0Sstevel@tonic-gate 			continue;
2520*0Sstevel@tonic-gate 
2521*0Sstevel@tonic-gate 		if (lmid != PR_LMID_EVERY &&
2522*0Sstevel@tonic-gate 		    (fp->file_lo == NULL || lmid != fp->file_lo->rl_lmident))
2523*0Sstevel@tonic-gate 			continue;
2524*0Sstevel@tonic-gate 
2525*0Sstevel@tonic-gate 		/*
2526*0Sstevel@tonic-gate 		 * If we match, return the primary text mapping; otherwise
2527*0Sstevel@tonic-gate 		 * just return the mapping we matched.
2528*0Sstevel@tonic-gate 		 */
2529*0Sstevel@tonic-gate 		if (strncmp(fp->file_lbase, objname, objlen) == 0 &&
2530*0Sstevel@tonic-gate 		    fp->file_lbase[objlen] == '.')
2531*0Sstevel@tonic-gate 			return (fp->file_map ? fp->file_map : mp);
2532*0Sstevel@tonic-gate 	}
2533*0Sstevel@tonic-gate 
2534*0Sstevel@tonic-gate 	/*
2535*0Sstevel@tonic-gate 	 * One last check: we allow "a.out" to always alias the executable,
2536*0Sstevel@tonic-gate 	 * assuming this name was not in use for something else.
2537*0Sstevel@tonic-gate 	 */
2538*0Sstevel@tonic-gate 	if ((lmid == PR_LMID_EVERY || lmid == LM_ID_BASE) &&
2539*0Sstevel@tonic-gate 	    (strcmp(objname, "a.out") == 0))
2540*0Sstevel@tonic-gate 		return (P->map_exec);
2541*0Sstevel@tonic-gate 
2542*0Sstevel@tonic-gate 	return (NULL);
2543*0Sstevel@tonic-gate }
2544*0Sstevel@tonic-gate 
2545*0Sstevel@tonic-gate static map_info_t *
2546*0Sstevel@tonic-gate object_name_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *name)
2547*0Sstevel@tonic-gate {
2548*0Sstevel@tonic-gate 	map_info_t *mptr;
2549*0Sstevel@tonic-gate 
2550*0Sstevel@tonic-gate 	if (!P->info_valid)
2551*0Sstevel@tonic-gate 		Pupdate_maps(P);
2552*0Sstevel@tonic-gate 
2553*0Sstevel@tonic-gate 	if (P->map_exec == NULL && ((mptr = Paddr2mptr(P,
2554*0Sstevel@tonic-gate 	    Pgetauxval(P, AT_ENTRY))) != NULL || (mptr = exec_map(P)) != NULL))
2555*0Sstevel@tonic-gate 		P->map_exec = mptr;
2556*0Sstevel@tonic-gate 
2557*0Sstevel@tonic-gate 	if (P->map_ldso == NULL && (mptr = Paddr2mptr(P,
2558*0Sstevel@tonic-gate 	    Pgetauxval(P, AT_BASE))) != NULL)
2559*0Sstevel@tonic-gate 		P->map_ldso = mptr;
2560*0Sstevel@tonic-gate 
2561*0Sstevel@tonic-gate 	if (name == PR_OBJ_EXEC)
2562*0Sstevel@tonic-gate 		mptr = P->map_exec;
2563*0Sstevel@tonic-gate 	else if (name == PR_OBJ_LDSO)
2564*0Sstevel@tonic-gate 		mptr = P->map_ldso;
2565*0Sstevel@tonic-gate 	else if (Prd_agent(P) != NULL || P->state == PS_IDLE)
2566*0Sstevel@tonic-gate 		mptr = object_to_map(P, lmid, name);
2567*0Sstevel@tonic-gate 	else
2568*0Sstevel@tonic-gate 		mptr = NULL;
2569*0Sstevel@tonic-gate 
2570*0Sstevel@tonic-gate 	return (mptr);
2571*0Sstevel@tonic-gate }
2572*0Sstevel@tonic-gate 
2573*0Sstevel@tonic-gate /*
2574*0Sstevel@tonic-gate  * When two symbols are found by address, decide which one is to be preferred.
2575*0Sstevel@tonic-gate  */
2576*0Sstevel@tonic-gate static GElf_Sym *
2577*0Sstevel@tonic-gate sym_prefer(GElf_Sym *sym1, char *name1, GElf_Sym *sym2, char *name2)
2578*0Sstevel@tonic-gate {
2579*0Sstevel@tonic-gate 	/*
2580*0Sstevel@tonic-gate 	 * Prefer the non-NULL symbol.
2581*0Sstevel@tonic-gate 	 */
2582*0Sstevel@tonic-gate 	if (sym1 == NULL)
2583*0Sstevel@tonic-gate 		return (sym2);
2584*0Sstevel@tonic-gate 	if (sym2 == NULL)
2585*0Sstevel@tonic-gate 		return (sym1);
2586*0Sstevel@tonic-gate 
2587*0Sstevel@tonic-gate 	/*
2588*0Sstevel@tonic-gate 	 * Defer to the sort ordering...
2589*0Sstevel@tonic-gate 	 */
2590*0Sstevel@tonic-gate 	return (byaddr_cmp_common(sym1, name1, sym2, name2) <= 0 ? sym1 : sym2);
2591*0Sstevel@tonic-gate }
2592*0Sstevel@tonic-gate 
2593*0Sstevel@tonic-gate /*
2594*0Sstevel@tonic-gate  * Look up a symbol by address in the specified symbol table.
2595*0Sstevel@tonic-gate  * Adjustment to 'addr' must already have been made for the
2596*0Sstevel@tonic-gate  * offset of the symbol if this is a dynamic library symbol table.
2597*0Sstevel@tonic-gate  */
2598*0Sstevel@tonic-gate static GElf_Sym *
2599*0Sstevel@tonic-gate sym_by_addr(sym_tbl_t *symtab, GElf_Addr addr, GElf_Sym *symp, uint_t *idp)
2600*0Sstevel@tonic-gate {
2601*0Sstevel@tonic-gate 	Elf_Data *data = symtab->sym_data;
2602*0Sstevel@tonic-gate 	GElf_Sym sym, osym;
2603*0Sstevel@tonic-gate 	uint_t i, oid, *byaddr = symtab->sym_byaddr;
2604*0Sstevel@tonic-gate 	int min, max, mid, omid, found = 0;
2605*0Sstevel@tonic-gate 
2606*0Sstevel@tonic-gate 	if (data == NULL)
2607*0Sstevel@tonic-gate 		return (NULL);
2608*0Sstevel@tonic-gate 
2609*0Sstevel@tonic-gate 	min = 0;
2610*0Sstevel@tonic-gate 	max = symtab->sym_count - 1;
2611*0Sstevel@tonic-gate 	osym.st_value = 0;
2612*0Sstevel@tonic-gate 
2613*0Sstevel@tonic-gate 	/*
2614*0Sstevel@tonic-gate 	 * We can't return when we've found a match, we have to continue
2615*0Sstevel@tonic-gate 	 * searching for the closest matching symbol.
2616*0Sstevel@tonic-gate 	 */
2617*0Sstevel@tonic-gate 	while (min <= max) {
2618*0Sstevel@tonic-gate 		mid = (max + min) / 2;
2619*0Sstevel@tonic-gate 
2620*0Sstevel@tonic-gate 		i = byaddr[mid];
2621*0Sstevel@tonic-gate 		(void) gelf_getsym(data, i, &sym);
2622*0Sstevel@tonic-gate 
2623*0Sstevel@tonic-gate 		if (addr >= sym.st_value &&
2624*0Sstevel@tonic-gate 		    addr < sym.st_value + sym.st_size &&
2625*0Sstevel@tonic-gate 		    (!found || sym.st_value > osym.st_value)) {
2626*0Sstevel@tonic-gate 			osym = sym;
2627*0Sstevel@tonic-gate 			omid = mid;
2628*0Sstevel@tonic-gate 			oid = i;
2629*0Sstevel@tonic-gate 			found = 1;
2630*0Sstevel@tonic-gate 		}
2631*0Sstevel@tonic-gate 
2632*0Sstevel@tonic-gate 		if (addr < sym.st_value)
2633*0Sstevel@tonic-gate 			max = mid - 1;
2634*0Sstevel@tonic-gate 		else
2635*0Sstevel@tonic-gate 			min = mid + 1;
2636*0Sstevel@tonic-gate 	}
2637*0Sstevel@tonic-gate 
2638*0Sstevel@tonic-gate 	if (!found)
2639*0Sstevel@tonic-gate 		return (NULL);
2640*0Sstevel@tonic-gate 
2641*0Sstevel@tonic-gate 	/*
2642*0Sstevel@tonic-gate 	 * There may be many symbols with identical values so we walk
2643*0Sstevel@tonic-gate 	 * backward in the byaddr table to find the best match.
2644*0Sstevel@tonic-gate 	 */
2645*0Sstevel@tonic-gate 	do {
2646*0Sstevel@tonic-gate 		sym = osym;
2647*0Sstevel@tonic-gate 		i = oid;
2648*0Sstevel@tonic-gate 
2649*0Sstevel@tonic-gate 		if (omid == 0)
2650*0Sstevel@tonic-gate 			break;
2651*0Sstevel@tonic-gate 
2652*0Sstevel@tonic-gate 		oid = byaddr[--omid];
2653*0Sstevel@tonic-gate 		(void) gelf_getsym(data, oid, &osym);
2654*0Sstevel@tonic-gate 	} while (addr >= osym.st_value &&
2655*0Sstevel@tonic-gate 	    addr < sym.st_value + osym.st_size &&
2656*0Sstevel@tonic-gate 	    osym.st_value == sym.st_value);
2657*0Sstevel@tonic-gate 
2658*0Sstevel@tonic-gate 	*symp = sym;
2659*0Sstevel@tonic-gate 	if (idp != NULL)
2660*0Sstevel@tonic-gate 		*idp = i;
2661*0Sstevel@tonic-gate 	return (symp);
2662*0Sstevel@tonic-gate }
2663*0Sstevel@tonic-gate 
2664*0Sstevel@tonic-gate /*
2665*0Sstevel@tonic-gate  * Look up a symbol by name in the specified symbol table.
2666*0Sstevel@tonic-gate  */
2667*0Sstevel@tonic-gate static GElf_Sym *
2668*0Sstevel@tonic-gate sym_by_name(sym_tbl_t *symtab, const char *name, GElf_Sym *symp, uint_t *idp)
2669*0Sstevel@tonic-gate {
2670*0Sstevel@tonic-gate 	Elf_Data *data = symtab->sym_data;
2671*0Sstevel@tonic-gate 	char *strs = symtab->sym_strs;
2672*0Sstevel@tonic-gate 	uint_t i, *byname = symtab->sym_byname;
2673*0Sstevel@tonic-gate 	int min, mid, max, cmp;
2674*0Sstevel@tonic-gate 
2675*0Sstevel@tonic-gate 	if (data == NULL || strs == NULL)
2676*0Sstevel@tonic-gate 		return (NULL);
2677*0Sstevel@tonic-gate 
2678*0Sstevel@tonic-gate 	min = 0;
2679*0Sstevel@tonic-gate 	max = symtab->sym_count - 1;
2680*0Sstevel@tonic-gate 
2681*0Sstevel@tonic-gate 	while (min <= max) {
2682*0Sstevel@tonic-gate 		mid = (max + min) / 2;
2683*0Sstevel@tonic-gate 
2684*0Sstevel@tonic-gate 		i = byname[mid];
2685*0Sstevel@tonic-gate 		(void) gelf_getsym(data, i, symp);
2686*0Sstevel@tonic-gate 
2687*0Sstevel@tonic-gate 		if ((cmp = strcmp(name, strs + symp->st_name)) == 0) {
2688*0Sstevel@tonic-gate 			if (idp != NULL)
2689*0Sstevel@tonic-gate 				*idp = i;
2690*0Sstevel@tonic-gate 			return (symp);
2691*0Sstevel@tonic-gate 		}
2692*0Sstevel@tonic-gate 
2693*0Sstevel@tonic-gate 		if (cmp < 0)
2694*0Sstevel@tonic-gate 			max = mid - 1;
2695*0Sstevel@tonic-gate 		else
2696*0Sstevel@tonic-gate 			min = mid + 1;
2697*0Sstevel@tonic-gate 	}
2698*0Sstevel@tonic-gate 
2699*0Sstevel@tonic-gate 	return (NULL);
2700*0Sstevel@tonic-gate }
2701*0Sstevel@tonic-gate 
2702*0Sstevel@tonic-gate /*
2703*0Sstevel@tonic-gate  * Search the process symbol tables looking for a symbol whose
2704*0Sstevel@tonic-gate  * value to value+size contain the address specified by addr.
2705*0Sstevel@tonic-gate  * Return values are:
2706*0Sstevel@tonic-gate  *	sym_name_buffer containing the symbol name
2707*0Sstevel@tonic-gate  *	GElf_Sym symbol table entry
2708*0Sstevel@tonic-gate  *	prsyminfo_t ancillary symbol information
2709*0Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
2710*0Sstevel@tonic-gate  */
2711*0Sstevel@tonic-gate int
2712*0Sstevel@tonic-gate Pxlookup_by_addr(
2713*0Sstevel@tonic-gate 	struct ps_prochandle *P,
2714*0Sstevel@tonic-gate 	uintptr_t addr,			/* process address being sought */
2715*0Sstevel@tonic-gate 	char *sym_name_buffer,		/* buffer for the symbol name */
2716*0Sstevel@tonic-gate 	size_t bufsize,			/* size of sym_name_buffer */
2717*0Sstevel@tonic-gate 	GElf_Sym *symbolp,		/* returned symbol table entry */
2718*0Sstevel@tonic-gate 	prsyminfo_t *sip)		/* returned symbol info */
2719*0Sstevel@tonic-gate {
2720*0Sstevel@tonic-gate 	GElf_Sym	*symp;
2721*0Sstevel@tonic-gate 	char		*name;
2722*0Sstevel@tonic-gate 	GElf_Sym	sym1, *sym1p = NULL;
2723*0Sstevel@tonic-gate 	GElf_Sym	sym2, *sym2p = NULL;
2724*0Sstevel@tonic-gate 	char		*name1 = NULL;
2725*0Sstevel@tonic-gate 	char		*name2 = NULL;
2726*0Sstevel@tonic-gate 	uint_t		i1;
2727*0Sstevel@tonic-gate 	uint_t		i2;
2728*0Sstevel@tonic-gate 	map_info_t	*mptr;
2729*0Sstevel@tonic-gate 	file_info_t	*fptr;
2730*0Sstevel@tonic-gate 
2731*0Sstevel@tonic-gate 	(void) Prd_agent(P);
2732*0Sstevel@tonic-gate 
2733*0Sstevel@tonic-gate 	if ((mptr = Paddr2mptr(P, addr)) == NULL ||	/* no such address */
2734*0Sstevel@tonic-gate 	    (fptr = build_map_symtab(P, mptr)) == NULL || /* no mapped file */
2735*0Sstevel@tonic-gate 	    fptr->file_elf == NULL)			/* not an ELF file */
2736*0Sstevel@tonic-gate 		return (-1);
2737*0Sstevel@tonic-gate 
2738*0Sstevel@tonic-gate 	/*
2739*0Sstevel@tonic-gate 	 * Adjust the address by the load object base address in
2740*0Sstevel@tonic-gate 	 * case the address turns out to be in a shared library.
2741*0Sstevel@tonic-gate 	 */
2742*0Sstevel@tonic-gate 	addr -= fptr->file_dyn_base;
2743*0Sstevel@tonic-gate 
2744*0Sstevel@tonic-gate 	/*
2745*0Sstevel@tonic-gate 	 * Search both symbol tables, symtab first, then dynsym.
2746*0Sstevel@tonic-gate 	 */
2747*0Sstevel@tonic-gate 	if ((sym1p = sym_by_addr(&fptr->file_symtab, addr, &sym1, &i1)) != NULL)
2748*0Sstevel@tonic-gate 		name1 = fptr->file_symtab.sym_strs + sym1.st_name;
2749*0Sstevel@tonic-gate 	if ((sym2p = sym_by_addr(&fptr->file_dynsym, addr, &sym2, &i2)) != NULL)
2750*0Sstevel@tonic-gate 		name2 = fptr->file_dynsym.sym_strs + sym2.st_name;
2751*0Sstevel@tonic-gate 
2752*0Sstevel@tonic-gate 	if ((symp = sym_prefer(sym1p, name1, sym2p, name2)) == NULL)
2753*0Sstevel@tonic-gate 		return (-1);
2754*0Sstevel@tonic-gate 
2755*0Sstevel@tonic-gate 	name = (symp == sym1p) ? name1 : name2;
2756*0Sstevel@tonic-gate 	if (bufsize > 0) {
2757*0Sstevel@tonic-gate 		(void) strncpy(sym_name_buffer, name, bufsize);
2758*0Sstevel@tonic-gate 		sym_name_buffer[bufsize - 1] = '\0';
2759*0Sstevel@tonic-gate 	}
2760*0Sstevel@tonic-gate 
2761*0Sstevel@tonic-gate 	*symbolp = *symp;
2762*0Sstevel@tonic-gate 	if (sip != NULL) {
2763*0Sstevel@tonic-gate 		sip->prs_name = bufsize == 0 ? NULL : sym_name_buffer;
2764*0Sstevel@tonic-gate 		sip->prs_object = fptr->file_lbase;
2765*0Sstevel@tonic-gate 		sip->prs_id = (symp == sym1p) ? i1 : i2;
2766*0Sstevel@tonic-gate 		sip->prs_table = (symp == sym1p) ? PR_SYMTAB : PR_DYNSYM;
2767*0Sstevel@tonic-gate 		sip->prs_lmid = (fptr->file_lo == NULL) ? LM_ID_BASE :
2768*0Sstevel@tonic-gate 		    fptr->file_lo->rl_lmident;
2769*0Sstevel@tonic-gate 	}
2770*0Sstevel@tonic-gate 
2771*0Sstevel@tonic-gate 	if (GELF_ST_TYPE(symbolp->st_info) != STT_TLS)
2772*0Sstevel@tonic-gate 		symbolp->st_value += fptr->file_dyn_base;
2773*0Sstevel@tonic-gate 
2774*0Sstevel@tonic-gate 	return (0);
2775*0Sstevel@tonic-gate }
2776*0Sstevel@tonic-gate 
2777*0Sstevel@tonic-gate int
2778*0Sstevel@tonic-gate Plookup_by_addr(struct ps_prochandle *P, uintptr_t addr, char *buf, size_t size,
2779*0Sstevel@tonic-gate     GElf_Sym *symp)
2780*0Sstevel@tonic-gate {
2781*0Sstevel@tonic-gate 	return (Pxlookup_by_addr(P, addr, buf, size, symp, NULL));
2782*0Sstevel@tonic-gate }
2783*0Sstevel@tonic-gate 
2784*0Sstevel@tonic-gate /*
2785*0Sstevel@tonic-gate  * Search the process symbol tables looking for a symbol whose name matches the
2786*0Sstevel@tonic-gate  * specified name and whose object and link map optionally match the specified
2787*0Sstevel@tonic-gate  * parameters.  On success, the function returns 0 and fills in the GElf_Sym
2788*0Sstevel@tonic-gate  * symbol table entry.  On failure, -1 is returned.
2789*0Sstevel@tonic-gate  */
2790*0Sstevel@tonic-gate int
2791*0Sstevel@tonic-gate Pxlookup_by_name(
2792*0Sstevel@tonic-gate 	struct ps_prochandle *P,
2793*0Sstevel@tonic-gate 	Lmid_t lmid,			/* link map to match, or -1 for any */
2794*0Sstevel@tonic-gate 	const char *oname,		/* load object name */
2795*0Sstevel@tonic-gate 	const char *sname,		/* symbol name */
2796*0Sstevel@tonic-gate 	GElf_Sym *symp,			/* returned symbol table entry */
2797*0Sstevel@tonic-gate 	prsyminfo_t *sip)		/* returned symbol info */
2798*0Sstevel@tonic-gate {
2799*0Sstevel@tonic-gate 	map_info_t *mptr;
2800*0Sstevel@tonic-gate 	file_info_t *fptr;
2801*0Sstevel@tonic-gate 	int cnt;
2802*0Sstevel@tonic-gate 
2803*0Sstevel@tonic-gate 	GElf_Sym sym;
2804*0Sstevel@tonic-gate 	prsyminfo_t si;
2805*0Sstevel@tonic-gate 	int rv = -1;
2806*0Sstevel@tonic-gate 	uint_t id;
2807*0Sstevel@tonic-gate 
2808*0Sstevel@tonic-gate 	if (oname == PR_OBJ_EVERY) {
2809*0Sstevel@tonic-gate 		/* create all the file_info_t's for all the mappings */
2810*0Sstevel@tonic-gate 		(void) Prd_agent(P);
2811*0Sstevel@tonic-gate 		cnt = P->num_files;
2812*0Sstevel@tonic-gate 		fptr = list_next(&P->file_head);
2813*0Sstevel@tonic-gate 	} else {
2814*0Sstevel@tonic-gate 		cnt = 1;
2815*0Sstevel@tonic-gate 		if ((mptr = object_name_to_map(P, lmid, oname)) == NULL ||
2816*0Sstevel@tonic-gate 		    (fptr = build_map_symtab(P, mptr)) == NULL)
2817*0Sstevel@tonic-gate 			return (-1);
2818*0Sstevel@tonic-gate 	}
2819*0Sstevel@tonic-gate 
2820*0Sstevel@tonic-gate 	/*
2821*0Sstevel@tonic-gate 	 * Iterate through the loaded object files and look for the symbol
2822*0Sstevel@tonic-gate 	 * name in the .symtab and .dynsym of each.  If we encounter a match
2823*0Sstevel@tonic-gate 	 * with SHN_UNDEF, keep looking in hopes of finding a better match.
2824*0Sstevel@tonic-gate 	 * This means that a name such as "puts" will match the puts function
2825*0Sstevel@tonic-gate 	 * in libc instead of matching the puts PLT entry in the a.out file.
2826*0Sstevel@tonic-gate 	 */
2827*0Sstevel@tonic-gate 	for (; cnt > 0; cnt--, fptr = list_next(fptr)) {
2828*0Sstevel@tonic-gate 		Pbuild_file_symtab(P, fptr);
2829*0Sstevel@tonic-gate 
2830*0Sstevel@tonic-gate 		if (fptr->file_elf == NULL)
2831*0Sstevel@tonic-gate 			continue;
2832*0Sstevel@tonic-gate 
2833*0Sstevel@tonic-gate 		if (lmid != PR_LMID_EVERY && fptr->file_lo != NULL &&
2834*0Sstevel@tonic-gate 		    lmid != fptr->file_lo->rl_lmident)
2835*0Sstevel@tonic-gate 			continue;
2836*0Sstevel@tonic-gate 
2837*0Sstevel@tonic-gate 		if (fptr->file_symtab.sym_data != NULL &&
2838*0Sstevel@tonic-gate 		    sym_by_name(&fptr->file_symtab, sname, symp, &id)) {
2839*0Sstevel@tonic-gate 			if (sip != NULL) {
2840*0Sstevel@tonic-gate 				sip->prs_id = id;
2841*0Sstevel@tonic-gate 				sip->prs_table = PR_SYMTAB;
2842*0Sstevel@tonic-gate 				sip->prs_object = oname;
2843*0Sstevel@tonic-gate 				sip->prs_name = sname;
2844*0Sstevel@tonic-gate 				sip->prs_lmid = fptr->file_lo == NULL ?
2845*0Sstevel@tonic-gate 				    LM_ID_BASE : fptr->file_lo->rl_lmident;
2846*0Sstevel@tonic-gate 			}
2847*0Sstevel@tonic-gate 		} else if (fptr->file_dynsym.sym_data != NULL &&
2848*0Sstevel@tonic-gate 		    sym_by_name(&fptr->file_dynsym, sname, symp, &id)) {
2849*0Sstevel@tonic-gate 			if (sip != NULL) {
2850*0Sstevel@tonic-gate 				sip->prs_id = id;
2851*0Sstevel@tonic-gate 				sip->prs_table = PR_DYNSYM;
2852*0Sstevel@tonic-gate 				sip->prs_object = oname;
2853*0Sstevel@tonic-gate 				sip->prs_name = sname;
2854*0Sstevel@tonic-gate 				sip->prs_lmid = fptr->file_lo == NULL ?
2855*0Sstevel@tonic-gate 				    LM_ID_BASE : fptr->file_lo->rl_lmident;
2856*0Sstevel@tonic-gate 			}
2857*0Sstevel@tonic-gate 		} else {
2858*0Sstevel@tonic-gate 			continue;
2859*0Sstevel@tonic-gate 		}
2860*0Sstevel@tonic-gate 
2861*0Sstevel@tonic-gate 		if (GELF_ST_TYPE(symp->st_info) != STT_TLS)
2862*0Sstevel@tonic-gate 			symp->st_value += fptr->file_dyn_base;
2863*0Sstevel@tonic-gate 
2864*0Sstevel@tonic-gate 		if (symp->st_shndx != SHN_UNDEF)
2865*0Sstevel@tonic-gate 			return (0);
2866*0Sstevel@tonic-gate 
2867*0Sstevel@tonic-gate 		if (rv != 0) {
2868*0Sstevel@tonic-gate 			if (sip != NULL)
2869*0Sstevel@tonic-gate 				si = *sip;
2870*0Sstevel@tonic-gate 			sym = *symp;
2871*0Sstevel@tonic-gate 			rv = 0;
2872*0Sstevel@tonic-gate 		}
2873*0Sstevel@tonic-gate 	}
2874*0Sstevel@tonic-gate 
2875*0Sstevel@tonic-gate 	if (rv == 0) {
2876*0Sstevel@tonic-gate 		if (sip != NULL)
2877*0Sstevel@tonic-gate 			*sip = si;
2878*0Sstevel@tonic-gate 		*symp = sym;
2879*0Sstevel@tonic-gate 	}
2880*0Sstevel@tonic-gate 
2881*0Sstevel@tonic-gate 	return (rv);
2882*0Sstevel@tonic-gate }
2883*0Sstevel@tonic-gate 
2884*0Sstevel@tonic-gate /*
2885*0Sstevel@tonic-gate  * Search the process symbol tables looking for a symbol whose name matches the
2886*0Sstevel@tonic-gate  * specified name, but without any restriction on the link map id.
2887*0Sstevel@tonic-gate  */
2888*0Sstevel@tonic-gate int
2889*0Sstevel@tonic-gate Plookup_by_name(struct ps_prochandle *P, const char *object,
2890*0Sstevel@tonic-gate 	const char *symbol, GElf_Sym *symp)
2891*0Sstevel@tonic-gate {
2892*0Sstevel@tonic-gate 	return (Pxlookup_by_name(P, PR_LMID_EVERY, object, symbol, symp, NULL));
2893*0Sstevel@tonic-gate }
2894*0Sstevel@tonic-gate 
2895*0Sstevel@tonic-gate /*
2896*0Sstevel@tonic-gate  * Iterate over the process's address space mappings.
2897*0Sstevel@tonic-gate  */
2898*0Sstevel@tonic-gate int
2899*0Sstevel@tonic-gate Pmapping_iter(struct ps_prochandle *P, proc_map_f *func, void *cd)
2900*0Sstevel@tonic-gate {
2901*0Sstevel@tonic-gate 	map_info_t *mptr;
2902*0Sstevel@tonic-gate 	file_info_t *fptr;
2903*0Sstevel@tonic-gate 	char *object_name;
2904*0Sstevel@tonic-gate 	int rc = 0;
2905*0Sstevel@tonic-gate 	int i;
2906*0Sstevel@tonic-gate 
2907*0Sstevel@tonic-gate 	/* create all the file_info_t's for all the mappings */
2908*0Sstevel@tonic-gate 	(void) Prd_agent(P);
2909*0Sstevel@tonic-gate 
2910*0Sstevel@tonic-gate 	for (i = 0, mptr = P->mappings; i < P->map_count; i++, mptr++) {
2911*0Sstevel@tonic-gate 		if ((fptr = mptr->map_file) == NULL)
2912*0Sstevel@tonic-gate 			object_name = NULL;
2913*0Sstevel@tonic-gate 		else
2914*0Sstevel@tonic-gate 			object_name = fptr->file_lname;
2915*0Sstevel@tonic-gate 		if ((rc = func(cd, &mptr->map_pmap, object_name)) != 0)
2916*0Sstevel@tonic-gate 			return (rc);
2917*0Sstevel@tonic-gate 	}
2918*0Sstevel@tonic-gate 	return (0);
2919*0Sstevel@tonic-gate }
2920*0Sstevel@tonic-gate 
2921*0Sstevel@tonic-gate /*
2922*0Sstevel@tonic-gate  * Iterate over the process's mapped objects.
2923*0Sstevel@tonic-gate  */
2924*0Sstevel@tonic-gate int
2925*0Sstevel@tonic-gate Pobject_iter(struct ps_prochandle *P, proc_map_f *func, void *cd)
2926*0Sstevel@tonic-gate {
2927*0Sstevel@tonic-gate 	map_info_t *mptr;
2928*0Sstevel@tonic-gate 	file_info_t *fptr;
2929*0Sstevel@tonic-gate 	uint_t cnt;
2930*0Sstevel@tonic-gate 	int rc = 0;
2931*0Sstevel@tonic-gate 
2932*0Sstevel@tonic-gate 	(void) Prd_agent(P); /* create file_info_t's for all the mappings */
2933*0Sstevel@tonic-gate 	Pupdate_maps(P);
2934*0Sstevel@tonic-gate 
2935*0Sstevel@tonic-gate 	for (cnt = P->num_files, fptr = list_next(&P->file_head);
2936*0Sstevel@tonic-gate 	    cnt; cnt--, fptr = list_next(fptr)) {
2937*0Sstevel@tonic-gate 
2938*0Sstevel@tonic-gate 		const char *lname = fptr->file_lname ? fptr->file_lname : "";
2939*0Sstevel@tonic-gate 
2940*0Sstevel@tonic-gate 		if ((mptr = fptr->file_map) == NULL)
2941*0Sstevel@tonic-gate 			continue;
2942*0Sstevel@tonic-gate 
2943*0Sstevel@tonic-gate 		if ((rc = func(cd, &mptr->map_pmap, lname)) != 0)
2944*0Sstevel@tonic-gate 			return (rc);
2945*0Sstevel@tonic-gate 	}
2946*0Sstevel@tonic-gate 	return (0);
2947*0Sstevel@tonic-gate }
2948*0Sstevel@tonic-gate 
2949*0Sstevel@tonic-gate /*
2950*0Sstevel@tonic-gate  * Given a virtual address, return the name of the underlying
2951*0Sstevel@tonic-gate  * mapped object (file), as provided by the dynamic linker.
2952*0Sstevel@tonic-gate  * Return NULL on failure (no underlying shared library).
2953*0Sstevel@tonic-gate  */
2954*0Sstevel@tonic-gate char *
2955*0Sstevel@tonic-gate Pobjname(struct ps_prochandle *P, uintptr_t addr,
2956*0Sstevel@tonic-gate 	char *buffer, size_t bufsize)
2957*0Sstevel@tonic-gate {
2958*0Sstevel@tonic-gate 	map_info_t *mptr;
2959*0Sstevel@tonic-gate 	file_info_t *fptr;
2960*0Sstevel@tonic-gate 
2961*0Sstevel@tonic-gate 	/* create all the file_info_t's for all the mappings */
2962*0Sstevel@tonic-gate 	(void) Prd_agent(P);
2963*0Sstevel@tonic-gate 
2964*0Sstevel@tonic-gate 	if ((mptr = Paddr2mptr(P, addr)) != NULL &&
2965*0Sstevel@tonic-gate 	    (fptr = mptr->map_file) != NULL &&
2966*0Sstevel@tonic-gate 	    fptr->file_lname != NULL) {
2967*0Sstevel@tonic-gate 		(void) strncpy(buffer, fptr->file_lname, bufsize);
2968*0Sstevel@tonic-gate 		if (strlen(fptr->file_lname) >= bufsize)
2969*0Sstevel@tonic-gate 			buffer[bufsize-1] = '\0';
2970*0Sstevel@tonic-gate 		return (buffer);
2971*0Sstevel@tonic-gate 	}
2972*0Sstevel@tonic-gate 	return (NULL);
2973*0Sstevel@tonic-gate }
2974*0Sstevel@tonic-gate 
2975*0Sstevel@tonic-gate /*
2976*0Sstevel@tonic-gate  * Given a virtual address, return the link map id of the underlying mapped
2977*0Sstevel@tonic-gate  * object (file), as provided by the dynamic linker.  Return -1 on failure.
2978*0Sstevel@tonic-gate  */
2979*0Sstevel@tonic-gate int
2980*0Sstevel@tonic-gate Plmid(struct ps_prochandle *P, uintptr_t addr, Lmid_t *lmidp)
2981*0Sstevel@tonic-gate {
2982*0Sstevel@tonic-gate 	map_info_t *mptr;
2983*0Sstevel@tonic-gate 	file_info_t *fptr;
2984*0Sstevel@tonic-gate 
2985*0Sstevel@tonic-gate 	/* create all the file_info_t's for all the mappings */
2986*0Sstevel@tonic-gate 	(void) Prd_agent(P);
2987*0Sstevel@tonic-gate 
2988*0Sstevel@tonic-gate 	if ((mptr = Paddr2mptr(P, addr)) != NULL &&
2989*0Sstevel@tonic-gate 	    (fptr = mptr->map_file) != NULL && fptr->file_lo != NULL) {
2990*0Sstevel@tonic-gate 		*lmidp = fptr->file_lo->rl_lmident;
2991*0Sstevel@tonic-gate 		return (0);
2992*0Sstevel@tonic-gate 	}
2993*0Sstevel@tonic-gate 
2994*0Sstevel@tonic-gate 	return (-1);
2995*0Sstevel@tonic-gate }
2996*0Sstevel@tonic-gate 
2997*0Sstevel@tonic-gate /*
2998*0Sstevel@tonic-gate  * Given an object name and optional lmid, iterate over the object's symbols.
2999*0Sstevel@tonic-gate  * If which == PR_SYMTAB, search the normal symbol table.
3000*0Sstevel@tonic-gate  * If which == PR_DYNSYM, search the dynamic symbol table.
3001*0Sstevel@tonic-gate  */
3002*0Sstevel@tonic-gate static int
3003*0Sstevel@tonic-gate Psymbol_iter_com(struct ps_prochandle *P, Lmid_t lmid, const char *object_name,
3004*0Sstevel@tonic-gate     int which, int mask, pr_order_t order, proc_xsym_f *func, void *cd)
3005*0Sstevel@tonic-gate {
3006*0Sstevel@tonic-gate 	GElf_Sym sym;
3007*0Sstevel@tonic-gate 	map_info_t *mptr;
3008*0Sstevel@tonic-gate 	file_info_t *fptr;
3009*0Sstevel@tonic-gate 	sym_tbl_t *symtab;
3010*0Sstevel@tonic-gate 	Elf_Data *data;
3011*0Sstevel@tonic-gate 	size_t symn;
3012*0Sstevel@tonic-gate 	const char *strs;
3013*0Sstevel@tonic-gate 	size_t strsz;
3014*0Sstevel@tonic-gate 	prsyminfo_t si;
3015*0Sstevel@tonic-gate 	int rv;
3016*0Sstevel@tonic-gate 	uint_t *map, i, count, ndx;
3017*0Sstevel@tonic-gate 
3018*0Sstevel@tonic-gate 	if ((mptr = object_name_to_map(P, lmid, object_name)) == NULL)
3019*0Sstevel@tonic-gate 		return (-1);
3020*0Sstevel@tonic-gate 
3021*0Sstevel@tonic-gate 	if ((fptr = build_map_symtab(P, mptr)) == NULL || /* no mapped file */
3022*0Sstevel@tonic-gate 	    fptr->file_elf == NULL)			/* not an ELF file */
3023*0Sstevel@tonic-gate 		return (-1);
3024*0Sstevel@tonic-gate 
3025*0Sstevel@tonic-gate 	/*
3026*0Sstevel@tonic-gate 	 * Search the specified symbol table.
3027*0Sstevel@tonic-gate 	 */
3028*0Sstevel@tonic-gate 	switch (which) {
3029*0Sstevel@tonic-gate 	case PR_SYMTAB:
3030*0Sstevel@tonic-gate 		symtab = &fptr->file_symtab;
3031*0Sstevel@tonic-gate 		si.prs_table = PR_SYMTAB;
3032*0Sstevel@tonic-gate 		break;
3033*0Sstevel@tonic-gate 	case PR_DYNSYM:
3034*0Sstevel@tonic-gate 		symtab = &fptr->file_dynsym;
3035*0Sstevel@tonic-gate 		si.prs_table = PR_DYNSYM;
3036*0Sstevel@tonic-gate 		break;
3037*0Sstevel@tonic-gate 	default:
3038*0Sstevel@tonic-gate 		return (-1);
3039*0Sstevel@tonic-gate 	}
3040*0Sstevel@tonic-gate 
3041*0Sstevel@tonic-gate 	si.prs_object = object_name;
3042*0Sstevel@tonic-gate 	si.prs_lmid = fptr->file_lo == NULL ?
3043*0Sstevel@tonic-gate 	    LM_ID_BASE : fptr->file_lo->rl_lmident;
3044*0Sstevel@tonic-gate 
3045*0Sstevel@tonic-gate 	data = symtab->sym_data;
3046*0Sstevel@tonic-gate 	symn = symtab->sym_symn;
3047*0Sstevel@tonic-gate 	strs = symtab->sym_strs;
3048*0Sstevel@tonic-gate 	strsz = symtab->sym_strsz;
3049*0Sstevel@tonic-gate 
3050*0Sstevel@tonic-gate 	if (data == NULL || strs == NULL)
3051*0Sstevel@tonic-gate 		return (-1);
3052*0Sstevel@tonic-gate 
3053*0Sstevel@tonic-gate 	switch (order) {
3054*0Sstevel@tonic-gate 	case PRO_NATURAL:
3055*0Sstevel@tonic-gate 		map = NULL;
3056*0Sstevel@tonic-gate 		count = symn;
3057*0Sstevel@tonic-gate 		break;
3058*0Sstevel@tonic-gate 	case PRO_BYNAME:
3059*0Sstevel@tonic-gate 		map = symtab->sym_byname;
3060*0Sstevel@tonic-gate 		count = symtab->sym_count;
3061*0Sstevel@tonic-gate 		break;
3062*0Sstevel@tonic-gate 	case PRO_BYADDR:
3063*0Sstevel@tonic-gate 		map = symtab->sym_byaddr;
3064*0Sstevel@tonic-gate 		count = symtab->sym_count;
3065*0Sstevel@tonic-gate 		break;
3066*0Sstevel@tonic-gate 	default:
3067*0Sstevel@tonic-gate 		return (-1);
3068*0Sstevel@tonic-gate 	}
3069*0Sstevel@tonic-gate 
3070*0Sstevel@tonic-gate 	rv = 0;
3071*0Sstevel@tonic-gate 
3072*0Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
3073*0Sstevel@tonic-gate 		ndx = map == NULL ? i : map[i];
3074*0Sstevel@tonic-gate 		if (gelf_getsym(data, ndx, &sym) != NULL) {
3075*0Sstevel@tonic-gate 			uint_t s_bind, s_type, type;
3076*0Sstevel@tonic-gate 
3077*0Sstevel@tonic-gate 			if (sym.st_name >= strsz)	/* invalid st_name */
3078*0Sstevel@tonic-gate 				continue;
3079*0Sstevel@tonic-gate 
3080*0Sstevel@tonic-gate 			s_bind = GELF_ST_BIND(sym.st_info);
3081*0Sstevel@tonic-gate 			s_type = GELF_ST_TYPE(sym.st_info);
3082*0Sstevel@tonic-gate 
3083*0Sstevel@tonic-gate 			/*
3084*0Sstevel@tonic-gate 			 * In case you haven't already guessed, this relies on
3085*0Sstevel@tonic-gate 			 * the bitmask used in <libproc.h> for encoding symbol
3086*0Sstevel@tonic-gate 			 * type and binding matching the order of STB and STT
3087*0Sstevel@tonic-gate 			 * constants in <sys/elf.h>.  ELF can't change without
3088*0Sstevel@tonic-gate 			 * breaking binary compatibility, so I think this is
3089*0Sstevel@tonic-gate 			 * reasonably fair game.
3090*0Sstevel@tonic-gate 			 */
3091*0Sstevel@tonic-gate 			if (s_bind < STB_NUM && s_type < STT_NUM) {
3092*0Sstevel@tonic-gate 				type = (1 << (s_type + 8)) | (1 << s_bind);
3093*0Sstevel@tonic-gate 				if ((type & ~mask) != 0)
3094*0Sstevel@tonic-gate 					continue;
3095*0Sstevel@tonic-gate 			} else
3096*0Sstevel@tonic-gate 				continue; /* Invalid type or binding */
3097*0Sstevel@tonic-gate 
3098*0Sstevel@tonic-gate 			if (GELF_ST_TYPE(sym.st_info) != STT_TLS)
3099*0Sstevel@tonic-gate 				sym.st_value += fptr->file_dyn_base;
3100*0Sstevel@tonic-gate 
3101*0Sstevel@tonic-gate 			si.prs_name = strs + sym.st_name;
3102*0Sstevel@tonic-gate 			si.prs_id = ndx;
3103*0Sstevel@tonic-gate 			if ((rv = func(cd, &sym, strs + sym.st_name, &si)) != 0)
3104*0Sstevel@tonic-gate 				break;
3105*0Sstevel@tonic-gate 		}
3106*0Sstevel@tonic-gate 	}
3107*0Sstevel@tonic-gate 
3108*0Sstevel@tonic-gate 	return (rv);
3109*0Sstevel@tonic-gate }
3110*0Sstevel@tonic-gate 
3111*0Sstevel@tonic-gate int
3112*0Sstevel@tonic-gate Pxsymbol_iter(struct ps_prochandle *P, Lmid_t lmid, const char *object_name,
3113*0Sstevel@tonic-gate     int which, int mask, proc_xsym_f *func, void *cd)
3114*0Sstevel@tonic-gate {
3115*0Sstevel@tonic-gate 	return (Psymbol_iter_com(P, lmid, object_name, which, mask,
3116*0Sstevel@tonic-gate 	    PRO_NATURAL, func, cd));
3117*0Sstevel@tonic-gate }
3118*0Sstevel@tonic-gate 
3119*0Sstevel@tonic-gate int
3120*0Sstevel@tonic-gate Psymbol_iter_by_lmid(struct ps_prochandle *P, Lmid_t lmid,
3121*0Sstevel@tonic-gate     const char *object_name, int which, int mask, proc_sym_f *func, void *cd)
3122*0Sstevel@tonic-gate {
3123*0Sstevel@tonic-gate 	return (Psymbol_iter_com(P, lmid, object_name, which, mask,
3124*0Sstevel@tonic-gate 	    PRO_NATURAL, (proc_xsym_f *)func, cd));
3125*0Sstevel@tonic-gate }
3126*0Sstevel@tonic-gate 
3127*0Sstevel@tonic-gate int
3128*0Sstevel@tonic-gate Psymbol_iter(struct ps_prochandle *P,
3129*0Sstevel@tonic-gate     const char *object_name, int which, int mask, proc_sym_f *func, void *cd)
3130*0Sstevel@tonic-gate {
3131*0Sstevel@tonic-gate 	return (Psymbol_iter_com(P, PR_LMID_EVERY, object_name, which, mask,
3132*0Sstevel@tonic-gate 	    PRO_NATURAL, (proc_xsym_f *)func, cd));
3133*0Sstevel@tonic-gate }
3134*0Sstevel@tonic-gate 
3135*0Sstevel@tonic-gate int
3136*0Sstevel@tonic-gate Psymbol_iter_by_addr(struct ps_prochandle *P,
3137*0Sstevel@tonic-gate     const char *object_name, int which, int mask, proc_sym_f *func, void *cd)
3138*0Sstevel@tonic-gate {
3139*0Sstevel@tonic-gate 	return (Psymbol_iter_com(P, PR_LMID_EVERY, object_name, which, mask,
3140*0Sstevel@tonic-gate 	    PRO_BYADDR, (proc_xsym_f *)func, cd));
3141*0Sstevel@tonic-gate }
3142*0Sstevel@tonic-gate 
3143*0Sstevel@tonic-gate int
3144*0Sstevel@tonic-gate Psymbol_iter_by_name(struct ps_prochandle *P,
3145*0Sstevel@tonic-gate     const char *object_name, int which, int mask, proc_sym_f *func, void *cd)
3146*0Sstevel@tonic-gate {
3147*0Sstevel@tonic-gate 	return (Psymbol_iter_com(P, PR_LMID_EVERY, object_name, which, mask,
3148*0Sstevel@tonic-gate 	    PRO_BYNAME, (proc_xsym_f *)func, cd));
3149*0Sstevel@tonic-gate }
3150*0Sstevel@tonic-gate 
3151*0Sstevel@tonic-gate /*
3152*0Sstevel@tonic-gate  * Get the platform string from the core file if we have it;
3153*0Sstevel@tonic-gate  * just perform the system call for the caller if this is a live process.
3154*0Sstevel@tonic-gate  */
3155*0Sstevel@tonic-gate char *
3156*0Sstevel@tonic-gate Pplatform(struct ps_prochandle *P, char *s, size_t n)
3157*0Sstevel@tonic-gate {
3158*0Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
3159*0Sstevel@tonic-gate 		errno = ENODATA;
3160*0Sstevel@tonic-gate 		return (NULL);
3161*0Sstevel@tonic-gate 	}
3162*0Sstevel@tonic-gate 
3163*0Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
3164*0Sstevel@tonic-gate 		if (P->core->core_platform == NULL) {
3165*0Sstevel@tonic-gate 			errno = ENODATA;
3166*0Sstevel@tonic-gate 			return (NULL);
3167*0Sstevel@tonic-gate 		}
3168*0Sstevel@tonic-gate 		(void) strncpy(s, P->core->core_platform, n - 1);
3169*0Sstevel@tonic-gate 		s[n - 1] = '\0';
3170*0Sstevel@tonic-gate 
3171*0Sstevel@tonic-gate 	} else if (sysinfo(SI_PLATFORM, s, n) == -1)
3172*0Sstevel@tonic-gate 		return (NULL);
3173*0Sstevel@tonic-gate 
3174*0Sstevel@tonic-gate 	return (s);
3175*0Sstevel@tonic-gate }
3176*0Sstevel@tonic-gate 
3177*0Sstevel@tonic-gate /*
3178*0Sstevel@tonic-gate  * Get the uname(2) information from the core file if we have it;
3179*0Sstevel@tonic-gate  * just perform the system call for the caller if this is a live process.
3180*0Sstevel@tonic-gate  */
3181*0Sstevel@tonic-gate int
3182*0Sstevel@tonic-gate Puname(struct ps_prochandle *P, struct utsname *u)
3183*0Sstevel@tonic-gate {
3184*0Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
3185*0Sstevel@tonic-gate 		errno = ENODATA;
3186*0Sstevel@tonic-gate 		return (-1);
3187*0Sstevel@tonic-gate 	}
3188*0Sstevel@tonic-gate 
3189*0Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
3190*0Sstevel@tonic-gate 		if (P->core->core_uts == NULL) {
3191*0Sstevel@tonic-gate 			errno = ENODATA;
3192*0Sstevel@tonic-gate 			return (-1);
3193*0Sstevel@tonic-gate 		}
3194*0Sstevel@tonic-gate 		(void) memcpy(u, P->core->core_uts, sizeof (struct utsname));
3195*0Sstevel@tonic-gate 		return (0);
3196*0Sstevel@tonic-gate 	}
3197*0Sstevel@tonic-gate 	return (uname(u));
3198*0Sstevel@tonic-gate }
3199*0Sstevel@tonic-gate 
3200*0Sstevel@tonic-gate /*
3201*0Sstevel@tonic-gate  * Get the zone name from the core file if we have it; look up the
3202*0Sstevel@tonic-gate  * name based on the zone id if this is a live process.
3203*0Sstevel@tonic-gate  */
3204*0Sstevel@tonic-gate char *
3205*0Sstevel@tonic-gate Pzonename(struct ps_prochandle *P, char *s, size_t n)
3206*0Sstevel@tonic-gate {
3207*0Sstevel@tonic-gate 	if (P->state == PS_IDLE) {
3208*0Sstevel@tonic-gate 		errno = ENODATA;
3209*0Sstevel@tonic-gate 		return (NULL);
3210*0Sstevel@tonic-gate 	}
3211*0Sstevel@tonic-gate 
3212*0Sstevel@tonic-gate 	if (P->state == PS_DEAD) {
3213*0Sstevel@tonic-gate 		if (P->core->core_zonename == NULL) {
3214*0Sstevel@tonic-gate 			errno = ENODATA;
3215*0Sstevel@tonic-gate 			return (NULL);
3216*0Sstevel@tonic-gate 		}
3217*0Sstevel@tonic-gate 		(void) strlcpy(s, P->core->core_zonename, n);
3218*0Sstevel@tonic-gate 	} else {
3219*0Sstevel@tonic-gate 		if (getzonenamebyid(P->status.pr_zoneid, s, n) < 0)
3220*0Sstevel@tonic-gate 			return (NULL);
3221*0Sstevel@tonic-gate 		s[n - 1] = '\0';
3222*0Sstevel@tonic-gate 	}
3223*0Sstevel@tonic-gate 	return (s);
3224*0Sstevel@tonic-gate }
3225*0Sstevel@tonic-gate 
3226*0Sstevel@tonic-gate /*
3227*0Sstevel@tonic-gate  * Called from Pcreate(), Pgrab(), and Pfgrab_core() to initialize
3228*0Sstevel@tonic-gate  * the symbol table heads in the new ps_prochandle.
3229*0Sstevel@tonic-gate  */
3230*0Sstevel@tonic-gate void
3231*0Sstevel@tonic-gate Pinitsym(struct ps_prochandle *P)
3232*0Sstevel@tonic-gate {
3233*0Sstevel@tonic-gate 	P->num_files = 0;
3234*0Sstevel@tonic-gate 	list_link(&P->file_head, NULL);
3235*0Sstevel@tonic-gate }
3236*0Sstevel@tonic-gate 
3237*0Sstevel@tonic-gate /*
3238*0Sstevel@tonic-gate  * Called from Prelease() to destroy the symbol tables.
3239*0Sstevel@tonic-gate  * Must be called by the client after an exec() in the victim process.
3240*0Sstevel@tonic-gate  */
3241*0Sstevel@tonic-gate void
3242*0Sstevel@tonic-gate Preset_maps(struct ps_prochandle *P)
3243*0Sstevel@tonic-gate {
3244*0Sstevel@tonic-gate 	int i;
3245*0Sstevel@tonic-gate 
3246*0Sstevel@tonic-gate 	if (P->rap != NULL) {
3247*0Sstevel@tonic-gate 		rd_delete(P->rap);
3248*0Sstevel@tonic-gate 		P->rap = NULL;
3249*0Sstevel@tonic-gate 	}
3250*0Sstevel@tonic-gate 
3251*0Sstevel@tonic-gate 	if (P->execname != NULL) {
3252*0Sstevel@tonic-gate 		free(P->execname);
3253*0Sstevel@tonic-gate 		P->execname = NULL;
3254*0Sstevel@tonic-gate 	}
3255*0Sstevel@tonic-gate 
3256*0Sstevel@tonic-gate 	if (P->auxv != NULL) {
3257*0Sstevel@tonic-gate 		free(P->auxv);
3258*0Sstevel@tonic-gate 		P->auxv = NULL;
3259*0Sstevel@tonic-gate 		P->nauxv = 0;
3260*0Sstevel@tonic-gate 	}
3261*0Sstevel@tonic-gate 
3262*0Sstevel@tonic-gate 	for (i = 0; i < P->map_count; i++)
3263*0Sstevel@tonic-gate 		map_info_free(P, &P->mappings[i]);
3264*0Sstevel@tonic-gate 
3265*0Sstevel@tonic-gate 	if (P->mappings != NULL) {
3266*0Sstevel@tonic-gate 		free(P->mappings);
3267*0Sstevel@tonic-gate 		P->mappings = NULL;
3268*0Sstevel@tonic-gate 	}
3269*0Sstevel@tonic-gate 	P->map_count = P->map_alloc = 0;
3270*0Sstevel@tonic-gate 
3271*0Sstevel@tonic-gate 	P->info_valid = 0;
3272*0Sstevel@tonic-gate }
3273*0Sstevel@tonic-gate 
3274*0Sstevel@tonic-gate typedef struct getenv_data {
3275*0Sstevel@tonic-gate 	char *buf;
3276*0Sstevel@tonic-gate 	size_t bufsize;
3277*0Sstevel@tonic-gate 	const char *search;
3278*0Sstevel@tonic-gate 	size_t searchlen;
3279*0Sstevel@tonic-gate } getenv_data_t;
3280*0Sstevel@tonic-gate 
3281*0Sstevel@tonic-gate /*ARGSUSED*/
3282*0Sstevel@tonic-gate static int
3283*0Sstevel@tonic-gate getenv_func(void *data, struct ps_prochandle *P, uintptr_t addr,
3284*0Sstevel@tonic-gate     const char *nameval)
3285*0Sstevel@tonic-gate {
3286*0Sstevel@tonic-gate 	getenv_data_t *d = data;
3287*0Sstevel@tonic-gate 	size_t len;
3288*0Sstevel@tonic-gate 
3289*0Sstevel@tonic-gate 	if (nameval == NULL)
3290*0Sstevel@tonic-gate 		return (0);
3291*0Sstevel@tonic-gate 
3292*0Sstevel@tonic-gate 	if (d->searchlen < strlen(nameval) &&
3293*0Sstevel@tonic-gate 	    strncmp(nameval, d->search, d->searchlen) == 0 &&
3294*0Sstevel@tonic-gate 	    nameval[d->searchlen] == '=') {
3295*0Sstevel@tonic-gate 		len = MIN(strlen(nameval), d->bufsize - 1);
3296*0Sstevel@tonic-gate 		(void) strncpy(d->buf, nameval, len);
3297*0Sstevel@tonic-gate 		d->buf[len] = '\0';
3298*0Sstevel@tonic-gate 		return (1);
3299*0Sstevel@tonic-gate 	}
3300*0Sstevel@tonic-gate 
3301*0Sstevel@tonic-gate 	return (0);
3302*0Sstevel@tonic-gate }
3303*0Sstevel@tonic-gate 
3304*0Sstevel@tonic-gate char *
3305*0Sstevel@tonic-gate Pgetenv(struct ps_prochandle *P, const char *name, char *buf, size_t buflen)
3306*0Sstevel@tonic-gate {
3307*0Sstevel@tonic-gate 	getenv_data_t d;
3308*0Sstevel@tonic-gate 
3309*0Sstevel@tonic-gate 	d.buf = buf;
3310*0Sstevel@tonic-gate 	d.bufsize = buflen;
3311*0Sstevel@tonic-gate 	d.search = name;
3312*0Sstevel@tonic-gate 	d.searchlen = strlen(name);
3313*0Sstevel@tonic-gate 
3314*0Sstevel@tonic-gate 	if (Penv_iter(P, getenv_func, &d) == 1) {
3315*0Sstevel@tonic-gate 		char *equals = strchr(d.buf, '=');
3316*0Sstevel@tonic-gate 
3317*0Sstevel@tonic-gate 		if (equals != NULL) {
3318*0Sstevel@tonic-gate 			(void) memmove(d.buf, equals + 1,
3319*0Sstevel@tonic-gate 			    d.buf + buflen - equals - 1);
3320*0Sstevel@tonic-gate 			d.buf[d.buf + buflen - equals] = '\0';
3321*0Sstevel@tonic-gate 
3322*0Sstevel@tonic-gate 			return (buf);
3323*0Sstevel@tonic-gate 		}
3324*0Sstevel@tonic-gate 	}
3325*0Sstevel@tonic-gate 
3326*0Sstevel@tonic-gate 	return (NULL);
3327*0Sstevel@tonic-gate }
3328*0Sstevel@tonic-gate 
3329*0Sstevel@tonic-gate /* number of argument or environment pointers to read all at once */
3330*0Sstevel@tonic-gate #define	NARG	100
3331*0Sstevel@tonic-gate 
3332*0Sstevel@tonic-gate int
3333*0Sstevel@tonic-gate Penv_iter(struct ps_prochandle *P, proc_env_f *func, void *data)
3334*0Sstevel@tonic-gate {
3335*0Sstevel@tonic-gate 	const psinfo_t *psp;
3336*0Sstevel@tonic-gate 	uintptr_t envpoff;
3337*0Sstevel@tonic-gate 	GElf_Sym sym;
3338*0Sstevel@tonic-gate 	int ret;
3339*0Sstevel@tonic-gate 	char *buf, *nameval;
3340*0Sstevel@tonic-gate 	size_t buflen;
3341*0Sstevel@tonic-gate 
3342*0Sstevel@tonic-gate 	int nenv = NARG;
3343*0Sstevel@tonic-gate 	long envp[NARG];
3344*0Sstevel@tonic-gate 
3345*0Sstevel@tonic-gate 	/*
3346*0Sstevel@tonic-gate 	 * Attempt to find the "_environ" variable in the process.
3347*0Sstevel@tonic-gate 	 * Failing that, use the original value provided by Ppsinfo().
3348*0Sstevel@tonic-gate 	 */
3349*0Sstevel@tonic-gate 	if ((psp = Ppsinfo(P)) == NULL)
3350*0Sstevel@tonic-gate 		return (-1);
3351*0Sstevel@tonic-gate 
3352*0Sstevel@tonic-gate 	envpoff = psp->pr_envp; /* Default if no _environ found */
3353*0Sstevel@tonic-gate 
3354*0Sstevel@tonic-gate 	if (Plookup_by_name(P, PR_OBJ_EXEC, "_environ", &sym) == 0) {
3355*0Sstevel@tonic-gate 		if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
3356*0Sstevel@tonic-gate 			if (Pread(P, &envpoff, sizeof (envpoff),
3357*0Sstevel@tonic-gate 			    sym.st_value) != sizeof (envpoff))
3358*0Sstevel@tonic-gate 				envpoff = psp->pr_envp;
3359*0Sstevel@tonic-gate 		} else if (P->status.pr_dmodel == PR_MODEL_ILP32) {
3360*0Sstevel@tonic-gate 			uint32_t envpoff32;
3361*0Sstevel@tonic-gate 
3362*0Sstevel@tonic-gate 			if (Pread(P, &envpoff32, sizeof (envpoff32),
3363*0Sstevel@tonic-gate 			    sym.st_value) != sizeof (envpoff32))
3364*0Sstevel@tonic-gate 				envpoff = psp->pr_envp;
3365*0Sstevel@tonic-gate 			else
3366*0Sstevel@tonic-gate 				envpoff = envpoff32;
3367*0Sstevel@tonic-gate 		}
3368*0Sstevel@tonic-gate 	}
3369*0Sstevel@tonic-gate 
3370*0Sstevel@tonic-gate 	buflen = 128;
3371*0Sstevel@tonic-gate 	buf = malloc(buflen);
3372*0Sstevel@tonic-gate 
3373*0Sstevel@tonic-gate 	ret = 0;
3374*0Sstevel@tonic-gate 	for (;;) {
3375*0Sstevel@tonic-gate 		uintptr_t envoff;
3376*0Sstevel@tonic-gate 
3377*0Sstevel@tonic-gate 		if (nenv == NARG) {
3378*0Sstevel@tonic-gate 			(void) memset(envp, 0, sizeof (envp));
3379*0Sstevel@tonic-gate 			if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
3380*0Sstevel@tonic-gate 				if (Pread(P, envp,
3381*0Sstevel@tonic-gate 				    sizeof (envp), envpoff) <= 0) {
3382*0Sstevel@tonic-gate 					ret = -1;
3383*0Sstevel@tonic-gate 					break;
3384*0Sstevel@tonic-gate 				}
3385*0Sstevel@tonic-gate 			} else if (P->status.pr_dmodel == PR_MODEL_ILP32) {
3386*0Sstevel@tonic-gate 				uint32_t e32[NARG];
3387*0Sstevel@tonic-gate 				int i;
3388*0Sstevel@tonic-gate 
3389*0Sstevel@tonic-gate 				(void) memset(e32, 0, sizeof (e32));
3390*0Sstevel@tonic-gate 				if (Pread(P, e32, sizeof (e32), envpoff) <= 0) {
3391*0Sstevel@tonic-gate 					ret = -1;
3392*0Sstevel@tonic-gate 					break;
3393*0Sstevel@tonic-gate 				}
3394*0Sstevel@tonic-gate 				for (i = 0; i < NARG; i++)
3395*0Sstevel@tonic-gate 					envp[i] = e32[i];
3396*0Sstevel@tonic-gate 			}
3397*0Sstevel@tonic-gate 			nenv = 0;
3398*0Sstevel@tonic-gate 		}
3399*0Sstevel@tonic-gate 
3400*0Sstevel@tonic-gate 		if ((envoff = envp[nenv++]) == NULL)
3401*0Sstevel@tonic-gate 			break;
3402*0Sstevel@tonic-gate 
3403*0Sstevel@tonic-gate 		/*
3404*0Sstevel@tonic-gate 		 * Attempt to read the string from the process.
3405*0Sstevel@tonic-gate 		 */
3406*0Sstevel@tonic-gate again:
3407*0Sstevel@tonic-gate 		ret = Pread_string(P, buf, buflen, envoff);
3408*0Sstevel@tonic-gate 
3409*0Sstevel@tonic-gate 		if (ret <= 0) {
3410*0Sstevel@tonic-gate 			nameval = NULL;
3411*0Sstevel@tonic-gate 		} else if (ret == buflen - 1) {
3412*0Sstevel@tonic-gate 			free(buf);
3413*0Sstevel@tonic-gate 			/*
3414*0Sstevel@tonic-gate 			 * Bail if we have a corrupted environment
3415*0Sstevel@tonic-gate 			 */
3416*0Sstevel@tonic-gate 			if (buflen >= ARG_MAX)
3417*0Sstevel@tonic-gate 				return (-1);
3418*0Sstevel@tonic-gate 			buflen *= 2;
3419*0Sstevel@tonic-gate 			buf = malloc(buflen);
3420*0Sstevel@tonic-gate 			goto again;
3421*0Sstevel@tonic-gate 		} else {
3422*0Sstevel@tonic-gate 			nameval = buf;
3423*0Sstevel@tonic-gate 		}
3424*0Sstevel@tonic-gate 
3425*0Sstevel@tonic-gate 		if ((ret = func(data, P, envoff, nameval)) != 0)
3426*0Sstevel@tonic-gate 			break;
3427*0Sstevel@tonic-gate 
3428*0Sstevel@tonic-gate 		envpoff += (P->status.pr_dmodel == PR_MODEL_LP64)? 8 : 4;
3429*0Sstevel@tonic-gate 	}
3430*0Sstevel@tonic-gate 
3431*0Sstevel@tonic-gate 	free(buf);
3432*0Sstevel@tonic-gate 
3433*0Sstevel@tonic-gate 	return (ret);
3434*0Sstevel@tonic-gate }
3435