xref: /titanic_50/usr/src/lib/libproc/amd64/Pisadep.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/stack.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/regset.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/frame.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/trap.h>
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
36*7c478bd9Sstevel@tonic-gate #include <unistd.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
38*7c478bd9Sstevel@tonic-gate #include <errno.h>
39*7c478bd9Sstevel@tonic-gate #include <string.h>
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #include "Pcontrol.h"
42*7c478bd9Sstevel@tonic-gate #include "Pstack.h"
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #define	M_PLT_NRSV		1	/* reserved PLT entries */
45*7c478bd9Sstevel@tonic-gate #define	M_PLT_ENTSIZE		16	/* size of each PLT entry */
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate static uchar_t int_syscall_instr[] = { 0xCD, T_SYSCALLINT };
48*7c478bd9Sstevel@tonic-gate static uchar_t syscall_instr[] = { 0x0f, 0x05 };
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate const char *
51*7c478bd9Sstevel@tonic-gate Ppltdest(struct ps_prochandle *P, uintptr_t pltaddr)
52*7c478bd9Sstevel@tonic-gate {
53*7c478bd9Sstevel@tonic-gate 	map_info_t *mp = Paddr2mptr(P, pltaddr);
54*7c478bd9Sstevel@tonic-gate 	file_info_t *fp;
55*7c478bd9Sstevel@tonic-gate 	size_t i;
56*7c478bd9Sstevel@tonic-gate 	uintptr_t r_addr;
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate 	if (mp == NULL || (fp = mp->map_file) == NULL ||
59*7c478bd9Sstevel@tonic-gate 	    fp->file_plt_base == 0 ||
60*7c478bd9Sstevel@tonic-gate 	    pltaddr - fp->file_plt_base >= fp->file_plt_size) {
61*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
62*7c478bd9Sstevel@tonic-gate 		return (NULL);
63*7c478bd9Sstevel@tonic-gate 	}
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate 	i = (pltaddr - fp->file_plt_base) / M_PLT_ENTSIZE - M_PLT_NRSV;
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_LP64) {
68*7c478bd9Sstevel@tonic-gate 		Elf64_Rela r;
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate 		r_addr = fp->file_jmp_rel + i * sizeof (r);
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate 		if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) &&
73*7c478bd9Sstevel@tonic-gate 		    (i = ELF64_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) {
74*7c478bd9Sstevel@tonic-gate 			Elf_Data *data = fp->file_dynsym.sym_data;
75*7c478bd9Sstevel@tonic-gate 			Elf64_Sym *symp = &(((Elf64_Sym *)data->d_buf)[i]);
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate 			return (fp->file_dynsym.sym_strs + symp->st_name);
78*7c478bd9Sstevel@tonic-gate 		}
79*7c478bd9Sstevel@tonic-gate 	} else {
80*7c478bd9Sstevel@tonic-gate 		Elf32_Rel r;
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate 		r_addr = fp->file_jmp_rel + i * sizeof (r);
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate 		if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) &&
85*7c478bd9Sstevel@tonic-gate 		    (i = ELF32_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) {
86*7c478bd9Sstevel@tonic-gate 			Elf_Data *data = fp->file_dynsym.sym_data;
87*7c478bd9Sstevel@tonic-gate 			Elf32_Sym *symp = &(((Elf32_Sym *)data->d_buf)[i]);
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 			return (fp->file_dynsym.sym_strs + symp->st_name);
90*7c478bd9Sstevel@tonic-gate 		}
91*7c478bd9Sstevel@tonic-gate 	}
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	return (NULL);
94*7c478bd9Sstevel@tonic-gate }
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate int
97*7c478bd9Sstevel@tonic-gate Pissyscall(struct ps_prochandle *P, uintptr_t addr)
98*7c478bd9Sstevel@tonic-gate {
99*7c478bd9Sstevel@tonic-gate 	uchar_t instr[16];
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_LP64) {
102*7c478bd9Sstevel@tonic-gate 		if (Pread(P, instr, sizeof (syscall_instr), addr) !=
103*7c478bd9Sstevel@tonic-gate 		    sizeof (syscall_instr) ||
104*7c478bd9Sstevel@tonic-gate 		    memcmp(instr, syscall_instr, sizeof (syscall_instr)) != 0)
105*7c478bd9Sstevel@tonic-gate 			return (0);
106*7c478bd9Sstevel@tonic-gate 		else
107*7c478bd9Sstevel@tonic-gate 			return (1);
108*7c478bd9Sstevel@tonic-gate 	}
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	if (Pread(P, instr, sizeof (int_syscall_instr), addr) !=
111*7c478bd9Sstevel@tonic-gate 	    sizeof (int_syscall_instr))
112*7c478bd9Sstevel@tonic-gate 		return (0);
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate 	if (memcmp(instr, int_syscall_instr, sizeof (int_syscall_instr)) == 0)
115*7c478bd9Sstevel@tonic-gate 		return (1);
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	return (0);
118*7c478bd9Sstevel@tonic-gate }
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate int
121*7c478bd9Sstevel@tonic-gate Pissyscall_prev(struct ps_prochandle *P, uintptr_t addr, uintptr_t *dst)
122*7c478bd9Sstevel@tonic-gate {
123*7c478bd9Sstevel@tonic-gate 	int ret;
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_LP64) {
126*7c478bd9Sstevel@tonic-gate 		if (Pissyscall(P, addr - sizeof (syscall_instr))) {
127*7c478bd9Sstevel@tonic-gate 			if (dst)
128*7c478bd9Sstevel@tonic-gate 				*dst = addr - sizeof (syscall_instr);
129*7c478bd9Sstevel@tonic-gate 			return (1);
130*7c478bd9Sstevel@tonic-gate 		}
131*7c478bd9Sstevel@tonic-gate 		return (0);
132*7c478bd9Sstevel@tonic-gate 	}
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	if ((ret = Pissyscall(P, addr - sizeof (int_syscall_instr))) != 0) {
135*7c478bd9Sstevel@tonic-gate 		if (dst)
136*7c478bd9Sstevel@tonic-gate 			*dst = addr - sizeof (int_syscall_instr);
137*7c478bd9Sstevel@tonic-gate 		return (ret);
138*7c478bd9Sstevel@tonic-gate 	}
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	return (0);
141*7c478bd9Sstevel@tonic-gate }
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate int
144*7c478bd9Sstevel@tonic-gate Pissyscall_text(struct ps_prochandle *P, const void *buf, size_t buflen)
145*7c478bd9Sstevel@tonic-gate {
146*7c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_LP64) {
147*7c478bd9Sstevel@tonic-gate 		if (buflen >= sizeof (syscall_instr) &&
148*7c478bd9Sstevel@tonic-gate 		    memcmp(buf, syscall_instr, sizeof (syscall_instr)) == 0)
149*7c478bd9Sstevel@tonic-gate 			return (1);
150*7c478bd9Sstevel@tonic-gate 		else
151*7c478bd9Sstevel@tonic-gate 			return (0);
152*7c478bd9Sstevel@tonic-gate 	}
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	if (buflen < sizeof (int_syscall_instr))
155*7c478bd9Sstevel@tonic-gate 		return (0);
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	if (memcmp(buf, int_syscall_instr, sizeof (int_syscall_instr)) == 0)
158*7c478bd9Sstevel@tonic-gate 		return (1);
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	return (0);
161*7c478bd9Sstevel@tonic-gate }
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate #define	TR_ARG_MAX 6	/* Max args to print, same as SPARC */
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate /*
166*7c478bd9Sstevel@tonic-gate  * Given a return address, determine the likely number of arguments
167*7c478bd9Sstevel@tonic-gate  * that were pushed on the stack prior to its execution.  We do this by
168*7c478bd9Sstevel@tonic-gate  * expecting that a typical call sequence consists of pushing arguments on
169*7c478bd9Sstevel@tonic-gate  * the stack, executing a call instruction, and then performing an add
170*7c478bd9Sstevel@tonic-gate  * on %esp to restore it to the value prior to pushing the arguments for
171*7c478bd9Sstevel@tonic-gate  * the call.  We attempt to detect such an add, and divide the addend
172*7c478bd9Sstevel@tonic-gate  * by the size of a word to determine the number of pushed arguments.
173*7c478bd9Sstevel@tonic-gate  *
174*7c478bd9Sstevel@tonic-gate  * If we do not find such an add, this does not necessarily imply that the
175*7c478bd9Sstevel@tonic-gate  * function took no arguments. It is not possible to reliably detect such a
176*7c478bd9Sstevel@tonic-gate  * void function because hand-coded assembler does not always perform an add
177*7c478bd9Sstevel@tonic-gate  * to %esp immediately after the "call" instruction (eg. _sys_call()).
178*7c478bd9Sstevel@tonic-gate  * Because of this, we default to returning MIN(sz, TR_ARG_MAX) instead of 0
179*7c478bd9Sstevel@tonic-gate  * in the absence of an add to %esp.
180*7c478bd9Sstevel@tonic-gate  */
181*7c478bd9Sstevel@tonic-gate static ulong_t
182*7c478bd9Sstevel@tonic-gate argcount(struct ps_prochandle *P, uint32_t pc, ssize_t sz)
183*7c478bd9Sstevel@tonic-gate {
184*7c478bd9Sstevel@tonic-gate 	uchar_t instr[6];
185*7c478bd9Sstevel@tonic-gate 	ulong_t count, max;
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	max = MIN(sz / sizeof (uint32_t), TR_ARG_MAX);
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	/*
190*7c478bd9Sstevel@tonic-gate 	 * Read the instruction at the return location.
191*7c478bd9Sstevel@tonic-gate 	 */
192*7c478bd9Sstevel@tonic-gate 	if (Pread(P, instr, sizeof (instr), (uintptr_t)pc) != sizeof (instr))
193*7c478bd9Sstevel@tonic-gate 		return (max);
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	if (instr[1] != 0xc4)
196*7c478bd9Sstevel@tonic-gate 		return (max);
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	switch (instr[0]) {
199*7c478bd9Sstevel@tonic-gate 	case 0x81:	/* count is a longword */
200*7c478bd9Sstevel@tonic-gate 		count = instr[2]+(instr[3]<<8)+(instr[4]<<16)+(instr[5]<<24);
201*7c478bd9Sstevel@tonic-gate 		break;
202*7c478bd9Sstevel@tonic-gate 	case 0x83:	/* count is a byte */
203*7c478bd9Sstevel@tonic-gate 		count = instr[2];
204*7c478bd9Sstevel@tonic-gate 		break;
205*7c478bd9Sstevel@tonic-gate 	default:
206*7c478bd9Sstevel@tonic-gate 		return (max);
207*7c478bd9Sstevel@tonic-gate 	}
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	count /= sizeof (uint32_t);
210*7c478bd9Sstevel@tonic-gate 	return (MIN(count, max));
211*7c478bd9Sstevel@tonic-gate }
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate static void
214*7c478bd9Sstevel@tonic-gate ucontext_32_to_prgregs(const ucontext32_t *uc, prgregset_t dst)
215*7c478bd9Sstevel@tonic-gate {
216*7c478bd9Sstevel@tonic-gate 	const greg32_t *src = &uc->uc_mcontext.gregs[0];
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	dst[REG_DS] = (uint16_t)src[DS];
219*7c478bd9Sstevel@tonic-gate 	dst[REG_ES] = (uint16_t)src[ES];
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	dst[REG_GS] = (uint16_t)src[GS];
222*7c478bd9Sstevel@tonic-gate 	dst[REG_FS] = (uint16_t)src[FS];
223*7c478bd9Sstevel@tonic-gate 	dst[REG_SS] = (uint16_t)src[SS];
224*7c478bd9Sstevel@tonic-gate 	dst[REG_RSP] = (uint32_t)src[UESP];
225*7c478bd9Sstevel@tonic-gate 	dst[REG_RFL] = src[EFL];
226*7c478bd9Sstevel@tonic-gate 	dst[REG_CS] = (uint16_t)src[CS];
227*7c478bd9Sstevel@tonic-gate 	dst[REG_RIP] = (uint32_t)src[EIP];
228*7c478bd9Sstevel@tonic-gate 	dst[REG_ERR] = (uint32_t)src[ERR];
229*7c478bd9Sstevel@tonic-gate 	dst[REG_TRAPNO] = (uint32_t)src[TRAPNO];
230*7c478bd9Sstevel@tonic-gate 	dst[REG_RAX] = (uint32_t)src[EAX];
231*7c478bd9Sstevel@tonic-gate 	dst[REG_RCX] = (uint32_t)src[ECX];
232*7c478bd9Sstevel@tonic-gate 	dst[REG_RDX] = (uint32_t)src[EDX];
233*7c478bd9Sstevel@tonic-gate 	dst[REG_RBX] = (uint32_t)src[EBX];
234*7c478bd9Sstevel@tonic-gate 	dst[REG_RBP] = (uint32_t)src[EBP];
235*7c478bd9Sstevel@tonic-gate 	dst[REG_RSI] = (uint32_t)src[ESI];
236*7c478bd9Sstevel@tonic-gate 	dst[REG_RDI] = (uint32_t)src[EDI];
237*7c478bd9Sstevel@tonic-gate }
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate static int
240*7c478bd9Sstevel@tonic-gate Pstack_iter32(struct ps_prochandle *P, const prgregset_t regs,
241*7c478bd9Sstevel@tonic-gate     proc_stack_f *func, void *arg)
242*7c478bd9Sstevel@tonic-gate {
243*7c478bd9Sstevel@tonic-gate 	prgreg_t *prevfp = NULL;
244*7c478bd9Sstevel@tonic-gate 	uint_t pfpsize = 0;
245*7c478bd9Sstevel@tonic-gate 	int nfp = 0;
246*7c478bd9Sstevel@tonic-gate 	struct {
247*7c478bd9Sstevel@tonic-gate 		prgreg32_t fp;
248*7c478bd9Sstevel@tonic-gate 		prgreg32_t pc;
249*7c478bd9Sstevel@tonic-gate 		prgreg32_t args[32];
250*7c478bd9Sstevel@tonic-gate 	} frame;
251*7c478bd9Sstevel@tonic-gate 	uint_t argc;
252*7c478bd9Sstevel@tonic-gate 	ssize_t sz;
253*7c478bd9Sstevel@tonic-gate 	prgregset_t gregs;
254*7c478bd9Sstevel@tonic-gate 	uint32_t fp, pfp, pc;
255*7c478bd9Sstevel@tonic-gate 	long args[32];
256*7c478bd9Sstevel@tonic-gate 	int rv;
257*7c478bd9Sstevel@tonic-gate 	int i;
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	/*
260*7c478bd9Sstevel@tonic-gate 	 * Type definition for a structure corresponding to an IA32
261*7c478bd9Sstevel@tonic-gate 	 * signal frame.  Refer to the comments in Pstack.c for more info
262*7c478bd9Sstevel@tonic-gate 	 */
263*7c478bd9Sstevel@tonic-gate 	typedef struct {
264*7c478bd9Sstevel@tonic-gate 		prgreg32_t fp;
265*7c478bd9Sstevel@tonic-gate 		prgreg32_t pc;
266*7c478bd9Sstevel@tonic-gate 		int signo;
267*7c478bd9Sstevel@tonic-gate 		caddr32_t ucp;
268*7c478bd9Sstevel@tonic-gate 		caddr32_t sip;
269*7c478bd9Sstevel@tonic-gate 	} sf_t;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	uclist_t ucl;
272*7c478bd9Sstevel@tonic-gate 	ucontext32_t uc;
273*7c478bd9Sstevel@tonic-gate 	uintptr_t uc_addr;
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	init_uclist(&ucl, P);
276*7c478bd9Sstevel@tonic-gate 	(void) memcpy(gregs, regs, sizeof (gregs));
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	fp = regs[R_FP];
279*7c478bd9Sstevel@tonic-gate 	pc = regs[R_PC];
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	while (fp != 0 || pc != 0) {
282*7c478bd9Sstevel@tonic-gate 		if (stack_loop(fp, &prevfp, &nfp, &pfpsize))
283*7c478bd9Sstevel@tonic-gate 			break;
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 		if (fp != 0 &&
286*7c478bd9Sstevel@tonic-gate 		    (sz = Pread(P, &frame, sizeof (frame), (uintptr_t)fp)
287*7c478bd9Sstevel@tonic-gate 		    >= (ssize_t)(2* sizeof (uint32_t)))) {
288*7c478bd9Sstevel@tonic-gate 			/*
289*7c478bd9Sstevel@tonic-gate 			 * One more trick for signal frames: the kernel sets
290*7c478bd9Sstevel@tonic-gate 			 * the return pc of the signal frame to 0xffffffff on
291*7c478bd9Sstevel@tonic-gate 			 * Intel IA32, so argcount won't work.
292*7c478bd9Sstevel@tonic-gate 			 */
293*7c478bd9Sstevel@tonic-gate 			if (frame.pc != -1L) {
294*7c478bd9Sstevel@tonic-gate 				sz -= 2* sizeof (uint32_t);
295*7c478bd9Sstevel@tonic-gate 				argc = argcount(P, (uint32_t)frame.pc, sz);
296*7c478bd9Sstevel@tonic-gate 			} else
297*7c478bd9Sstevel@tonic-gate 				argc = 3; /* sighandler(signo, sip, ucp) */
298*7c478bd9Sstevel@tonic-gate 		} else {
299*7c478bd9Sstevel@tonic-gate 			(void) memset(&frame, 0, sizeof (frame));
300*7c478bd9Sstevel@tonic-gate 			argc = 0;
301*7c478bd9Sstevel@tonic-gate 		}
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 		gregs[R_FP] = fp;
304*7c478bd9Sstevel@tonic-gate 		gregs[R_PC] = pc;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < argc; i++)
307*7c478bd9Sstevel@tonic-gate 			args[i] = (uint32_t)frame.args[i];
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 		if ((rv = func(arg, gregs, argc, args)) != 0)
310*7c478bd9Sstevel@tonic-gate 			break;
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 		/*
313*7c478bd9Sstevel@tonic-gate 		 * In order to allow iteration over java frames (which can have
314*7c478bd9Sstevel@tonic-gate 		 * their own frame pointers), we allow the iterator to change
315*7c478bd9Sstevel@tonic-gate 		 * the contents of gregs.  If we detect a change, then we assume
316*7c478bd9Sstevel@tonic-gate 		 * that the new values point to the next frame.
317*7c478bd9Sstevel@tonic-gate 		 */
318*7c478bd9Sstevel@tonic-gate 		if (gregs[R_FP] != fp || gregs[R_PC] != pc) {
319*7c478bd9Sstevel@tonic-gate 			fp = gregs[R_FP];
320*7c478bd9Sstevel@tonic-gate 			pc = gregs[R_PC];
321*7c478bd9Sstevel@tonic-gate 			continue;
322*7c478bd9Sstevel@tonic-gate 		}
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 		pfp = fp;
325*7c478bd9Sstevel@tonic-gate 		fp = frame.fp;
326*7c478bd9Sstevel@tonic-gate 		pc = frame.pc;
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 		if (find_uclink(&ucl, pfp + sizeof (sf_t)))
329*7c478bd9Sstevel@tonic-gate 			uc_addr = pfp + sizeof (sf_t);
330*7c478bd9Sstevel@tonic-gate 		else
331*7c478bd9Sstevel@tonic-gate 			uc_addr = NULL;
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 		if (uc_addr != NULL &&
334*7c478bd9Sstevel@tonic-gate 		    Pread(P, &uc, sizeof (uc), uc_addr) == sizeof (uc)) {
335*7c478bd9Sstevel@tonic-gate 			ucontext_32_to_prgregs(&uc, gregs);
336*7c478bd9Sstevel@tonic-gate 			fp = gregs[R_FP];
337*7c478bd9Sstevel@tonic-gate 			pc = gregs[R_PC];
338*7c478bd9Sstevel@tonic-gate 		}
339*7c478bd9Sstevel@tonic-gate 	}
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	if (prevfp)
342*7c478bd9Sstevel@tonic-gate 		free(prevfp);
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	free_uclist(&ucl);
345*7c478bd9Sstevel@tonic-gate 	return (rv);
346*7c478bd9Sstevel@tonic-gate }
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate static void
349*7c478bd9Sstevel@tonic-gate ucontext_n_to_prgregs(const ucontext_t *src, prgregset_t dst)
350*7c478bd9Sstevel@tonic-gate {
351*7c478bd9Sstevel@tonic-gate 	(void) memcpy(dst, src->uc_mcontext.gregs, sizeof (gregset_t));
352*7c478bd9Sstevel@tonic-gate }
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate int
356*7c478bd9Sstevel@tonic-gate Pstack_iter(struct ps_prochandle *P, const prgregset_t regs,
357*7c478bd9Sstevel@tonic-gate 	proc_stack_f *func, void *arg)
358*7c478bd9Sstevel@tonic-gate {
359*7c478bd9Sstevel@tonic-gate 	struct {
360*7c478bd9Sstevel@tonic-gate 		uintptr_t fp;
361*7c478bd9Sstevel@tonic-gate 		uintptr_t pc;
362*7c478bd9Sstevel@tonic-gate 	} frame;
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 	uint_t pfpsize = 0;
365*7c478bd9Sstevel@tonic-gate 	prgreg_t *prevfp = NULL;
366*7c478bd9Sstevel@tonic-gate 	prgreg_t fp, pfp;
367*7c478bd9Sstevel@tonic-gate 	prgreg_t pc;
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	prgregset_t gregs;
370*7c478bd9Sstevel@tonic-gate 	int nfp = 0;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	uclist_t ucl;
373*7c478bd9Sstevel@tonic-gate 	int rv = 0;
374*7c478bd9Sstevel@tonic-gate 	int argc;
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	uintptr_t uc_addr;
377*7c478bd9Sstevel@tonic-gate 	ucontext_t uc;
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	/*
380*7c478bd9Sstevel@tonic-gate 	 * Type definition for a structure corresponding to an IA32
381*7c478bd9Sstevel@tonic-gate 	 * signal frame.  Refer to the comments in Pstack.c for more info
382*7c478bd9Sstevel@tonic-gate 	 */
383*7c478bd9Sstevel@tonic-gate 	typedef struct {
384*7c478bd9Sstevel@tonic-gate 		prgreg_t fp;
385*7c478bd9Sstevel@tonic-gate 		prgreg_t pc;
386*7c478bd9Sstevel@tonic-gate 		prgreg_t signo;
387*7c478bd9Sstevel@tonic-gate 		siginfo_t *sip;
388*7c478bd9Sstevel@tonic-gate 	} sigframe_t;
389*7c478bd9Sstevel@tonic-gate 	prgreg_t args[32];
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel != PR_MODEL_LP64)
392*7c478bd9Sstevel@tonic-gate 		return (Pstack_iter32(P, regs, func, arg));
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	init_uclist(&ucl, P);
395*7c478bd9Sstevel@tonic-gate 	(void) memcpy(gregs, regs, sizeof (gregs));
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 	fp = gregs[R_FP];
398*7c478bd9Sstevel@tonic-gate 	pc = gregs[R_PC];
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	while (fp != 0 || pc != 0) {
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 		if (stack_loop(fp, &prevfp, &nfp, &pfpsize))
403*7c478bd9Sstevel@tonic-gate 			break;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 		if (fp != 0 &&
406*7c478bd9Sstevel@tonic-gate 		    Pread(P, &frame, sizeof (frame), (uintptr_t)fp) ==
407*7c478bd9Sstevel@tonic-gate 		    sizeof (frame)) {
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 			if (frame.pc != -1) {
410*7c478bd9Sstevel@tonic-gate 				/*
411*7c478bd9Sstevel@tonic-gate 				 * Function arguments are not available on
412*7c478bd9Sstevel@tonic-gate 				 * amd64 without extensive DWARF processing.
413*7c478bd9Sstevel@tonic-gate 				 */
414*7c478bd9Sstevel@tonic-gate 				argc = 0;
415*7c478bd9Sstevel@tonic-gate 			} else {
416*7c478bd9Sstevel@tonic-gate 				argc = 3;
417*7c478bd9Sstevel@tonic-gate 				args[2] = fp + sizeof (sigframe_t);
418*7c478bd9Sstevel@tonic-gate 				if (Pread(P, &args, 2 * sizeof (prgreg_t),
419*7c478bd9Sstevel@tonic-gate 				    fp + 2 * sizeof (prgreg_t)) !=
420*7c478bd9Sstevel@tonic-gate 				    2 * sizeof (prgreg_t))
421*7c478bd9Sstevel@tonic-gate 					argc = 0;
422*7c478bd9Sstevel@tonic-gate 			}
423*7c478bd9Sstevel@tonic-gate 		} else {
424*7c478bd9Sstevel@tonic-gate 			(void) memset(&frame, 0, sizeof (frame));
425*7c478bd9Sstevel@tonic-gate 			argc = 0;
426*7c478bd9Sstevel@tonic-gate 		}
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 		gregs[R_FP] = fp;
429*7c478bd9Sstevel@tonic-gate 		gregs[R_PC] = pc;
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 		if ((rv = func(arg, gregs, argc, args)) != 0)
432*7c478bd9Sstevel@tonic-gate 			break;
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 		pfp = fp;
435*7c478bd9Sstevel@tonic-gate 		fp = frame.fp;
436*7c478bd9Sstevel@tonic-gate 		pc = frame.pc;
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 		if (pc == -1 && find_uclink(&ucl, pfp + sizeof (sigframe_t))) {
439*7c478bd9Sstevel@tonic-gate 			uc_addr = pfp + sizeof (sigframe_t);
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 			if (Pread(P, &uc, sizeof (uc), uc_addr)
442*7c478bd9Sstevel@tonic-gate 			    == sizeof (uc)) {
443*7c478bd9Sstevel@tonic-gate 				ucontext_n_to_prgregs(&uc, gregs);
444*7c478bd9Sstevel@tonic-gate 				fp = gregs[R_FP];
445*7c478bd9Sstevel@tonic-gate 				pc = gregs[R_PC];
446*7c478bd9Sstevel@tonic-gate 			}
447*7c478bd9Sstevel@tonic-gate 		}
448*7c478bd9Sstevel@tonic-gate 	}
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	if (prevfp)
451*7c478bd9Sstevel@tonic-gate 		free(prevfp);
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	free_uclist(&ucl);
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	return (rv);
456*7c478bd9Sstevel@tonic-gate }
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate uintptr_t
459*7c478bd9Sstevel@tonic-gate Psyscall_setup(struct ps_prochandle *P, int nargs, int sysindex, uintptr_t sp)
460*7c478bd9Sstevel@tonic-gate {
461*7c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
462*7c478bd9Sstevel@tonic-gate 		sp -= sizeof (int) * (nargs+2);
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 		P->status.pr_lwp.pr_reg[REG_RAX] = sysindex;
465*7c478bd9Sstevel@tonic-gate 		P->status.pr_lwp.pr_reg[REG_RSP] = sp;
466*7c478bd9Sstevel@tonic-gate 		P->status.pr_lwp.pr_reg[REG_RIP] = P->sysaddr;
467*7c478bd9Sstevel@tonic-gate 	} else {
468*7c478bd9Sstevel@tonic-gate 		int pusharg = (nargs > 6) ? nargs - 6: 0;
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 		sp -= sizeof (int64_t) * (pusharg+2);
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 		P->status.pr_lwp.pr_reg[REG_RAX] = sysindex;
473*7c478bd9Sstevel@tonic-gate 		P->status.pr_lwp.pr_reg[REG_RSP] = sp;
474*7c478bd9Sstevel@tonic-gate 		P->status.pr_lwp.pr_reg[REG_RIP] = P->sysaddr;
475*7c478bd9Sstevel@tonic-gate 	}
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	return (sp);
478*7c478bd9Sstevel@tonic-gate }
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate int
481*7c478bd9Sstevel@tonic-gate Psyscall_copyinargs(struct ps_prochandle *P, int nargs, argdes_t *argp,
482*7c478bd9Sstevel@tonic-gate     uintptr_t ap)
483*7c478bd9Sstevel@tonic-gate {
484*7c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
485*7c478bd9Sstevel@tonic-gate 		int32_t arglist[MAXARGS+2];
486*7c478bd9Sstevel@tonic-gate 		int i;
487*7c478bd9Sstevel@tonic-gate 		argdes_t *adp;
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 		for (i = 0, adp = argp; i < nargs; i++, adp++)
490*7c478bd9Sstevel@tonic-gate 			arglist[1 + i] = (int32_t)adp->arg_value;
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 		arglist[0] = P->status.pr_lwp.pr_reg[REG_RIP];
493*7c478bd9Sstevel@tonic-gate 		if (Pwrite(P, &arglist[0], sizeof (int) * (nargs+1),
494*7c478bd9Sstevel@tonic-gate 		    (uintptr_t)ap) != sizeof (int) * (nargs+1))
495*7c478bd9Sstevel@tonic-gate 			return (-1);
496*7c478bd9Sstevel@tonic-gate 	} else {
497*7c478bd9Sstevel@tonic-gate 		int64_t arglist[MAXARGS+2];
498*7c478bd9Sstevel@tonic-gate 		int i;
499*7c478bd9Sstevel@tonic-gate 		argdes_t *adp;
500*7c478bd9Sstevel@tonic-gate 		int pusharg = (nargs > 6) ? nargs - 6: 0;
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 		for (i = 0, adp = argp; i < nargs; i++, adp++) {
503*7c478bd9Sstevel@tonic-gate 			switch (i) {
504*7c478bd9Sstevel@tonic-gate 			case 0:
505*7c478bd9Sstevel@tonic-gate 				(void) Pputareg(P, REG_RDI, adp->arg_value);
506*7c478bd9Sstevel@tonic-gate 				break;
507*7c478bd9Sstevel@tonic-gate 			case 1:
508*7c478bd9Sstevel@tonic-gate 				(void) Pputareg(P, REG_RSI, adp->arg_value);
509*7c478bd9Sstevel@tonic-gate 				break;
510*7c478bd9Sstevel@tonic-gate 			case 2:
511*7c478bd9Sstevel@tonic-gate 				(void) Pputareg(P, REG_RDX, adp->arg_value);
512*7c478bd9Sstevel@tonic-gate 				break;
513*7c478bd9Sstevel@tonic-gate 			case 3:
514*7c478bd9Sstevel@tonic-gate 				(void) Pputareg(P, REG_RCX, adp->arg_value);
515*7c478bd9Sstevel@tonic-gate 				break;
516*7c478bd9Sstevel@tonic-gate 			case 4:
517*7c478bd9Sstevel@tonic-gate 				(void) Pputareg(P, REG_R8, adp->arg_value);
518*7c478bd9Sstevel@tonic-gate 				break;
519*7c478bd9Sstevel@tonic-gate 			case 5:
520*7c478bd9Sstevel@tonic-gate 				(void) Pputareg(P, REG_R9, adp->arg_value);
521*7c478bd9Sstevel@tonic-gate 				break;
522*7c478bd9Sstevel@tonic-gate 			default:
523*7c478bd9Sstevel@tonic-gate 				arglist[i - 5] = (uint64_t)adp->arg_value;
524*7c478bd9Sstevel@tonic-gate 				break;
525*7c478bd9Sstevel@tonic-gate 			}
526*7c478bd9Sstevel@tonic-gate 		}
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 		arglist[0] = P->status.pr_lwp.pr_reg[REG_RIP];
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 		if (Pwrite(P, &arglist[0],
531*7c478bd9Sstevel@tonic-gate 		    sizeof (int64_t) * (pusharg + 1), ap) !=
532*7c478bd9Sstevel@tonic-gate 		    sizeof (int64_t) * (pusharg + 1))
533*7c478bd9Sstevel@tonic-gate 			return (-1);
534*7c478bd9Sstevel@tonic-gate 	}
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	return (0);
537*7c478bd9Sstevel@tonic-gate }
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate int
540*7c478bd9Sstevel@tonic-gate Psyscall_copyoutargs(struct ps_prochandle *P, int nargs, argdes_t *argp,
541*7c478bd9Sstevel@tonic-gate     uintptr_t ap)
542*7c478bd9Sstevel@tonic-gate {
543*7c478bd9Sstevel@tonic-gate 	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
544*7c478bd9Sstevel@tonic-gate 		uint32_t arglist[MAXARGS + 2];
545*7c478bd9Sstevel@tonic-gate 		int i;
546*7c478bd9Sstevel@tonic-gate 		argdes_t *adp;
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 		if (Pread(P, &arglist[0], sizeof (int) * (nargs+1),
549*7c478bd9Sstevel@tonic-gate 		    (uintptr_t)ap) != sizeof (int) * (nargs+1))
550*7c478bd9Sstevel@tonic-gate 			return (-1);
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 		for (i = 0, adp = argp; i < nargs; i++, adp++)
553*7c478bd9Sstevel@tonic-gate 			adp->arg_value = arglist[i];
554*7c478bd9Sstevel@tonic-gate 	} else {
555*7c478bd9Sstevel@tonic-gate 		int pusharg = (nargs > 6) ? nargs - 6: 0;
556*7c478bd9Sstevel@tonic-gate 		int64_t arglist[MAXARGS+2];
557*7c478bd9Sstevel@tonic-gate 		int i;
558*7c478bd9Sstevel@tonic-gate 		argdes_t *adp;
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 		if (pusharg  > 0 &&
561*7c478bd9Sstevel@tonic-gate 		    Pread(P, &arglist[0], sizeof (int64_t) * (pusharg + 1),
562*7c478bd9Sstevel@tonic-gate 		    ap) != sizeof (int64_t) * (pusharg + 1))
563*7c478bd9Sstevel@tonic-gate 			return (-1);
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 		for (i = 0, adp = argp; i < nargs; i++, adp++) {
566*7c478bd9Sstevel@tonic-gate 			switch (i) {
567*7c478bd9Sstevel@tonic-gate 			case 0:
568*7c478bd9Sstevel@tonic-gate 				adp->arg_value =
569*7c478bd9Sstevel@tonic-gate 				    P->status.pr_lwp.pr_reg[REG_RDI];
570*7c478bd9Sstevel@tonic-gate 				break;
571*7c478bd9Sstevel@tonic-gate 			case 1:
572*7c478bd9Sstevel@tonic-gate 				adp->arg_value =
573*7c478bd9Sstevel@tonic-gate 				    P->status.pr_lwp.pr_reg[REG_RSI];
574*7c478bd9Sstevel@tonic-gate 				break;
575*7c478bd9Sstevel@tonic-gate 			case 2:
576*7c478bd9Sstevel@tonic-gate 				adp->arg_value =
577*7c478bd9Sstevel@tonic-gate 				    P->status.pr_lwp.pr_reg[REG_RDX];
578*7c478bd9Sstevel@tonic-gate 				break;
579*7c478bd9Sstevel@tonic-gate 			case 3:
580*7c478bd9Sstevel@tonic-gate 				adp->arg_value =
581*7c478bd9Sstevel@tonic-gate 				    P->status.pr_lwp.pr_reg[REG_RCX];
582*7c478bd9Sstevel@tonic-gate 				break;
583*7c478bd9Sstevel@tonic-gate 			case 4:
584*7c478bd9Sstevel@tonic-gate 				adp->arg_value =
585*7c478bd9Sstevel@tonic-gate 				    P->status.pr_lwp.pr_reg[REG_R8];
586*7c478bd9Sstevel@tonic-gate 				break;
587*7c478bd9Sstevel@tonic-gate 			case 5:
588*7c478bd9Sstevel@tonic-gate 				adp->arg_value =
589*7c478bd9Sstevel@tonic-gate 				    P->status.pr_lwp.pr_reg[REG_R9];
590*7c478bd9Sstevel@tonic-gate 				break;
591*7c478bd9Sstevel@tonic-gate 			default:
592*7c478bd9Sstevel@tonic-gate 				adp->arg_value = arglist[i - 6];
593*7c478bd9Sstevel@tonic-gate 				break;
594*7c478bd9Sstevel@tonic-gate 			}
595*7c478bd9Sstevel@tonic-gate 		}
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 		return (0);
598*7c478bd9Sstevel@tonic-gate 	}
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	return (0);
601*7c478bd9Sstevel@tonic-gate }
602