xref: /freebsd/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c (revision c757049235edc6ecca32c6c584f7d5582aaeb74a)
1*c7570492SJustin Hibbits /*
2*c7570492SJustin Hibbits  * CDDL HEADER START
3*c7570492SJustin Hibbits  *
4*c7570492SJustin Hibbits  * The contents of this file are subject to the terms of the
5*c7570492SJustin Hibbits  * Common Development and Distribution License, Version 1.0 only
6*c7570492SJustin Hibbits  * (the "License").  You may not use this file except in compliance
7*c7570492SJustin Hibbits  * with the License.
8*c7570492SJustin Hibbits  *
9*c7570492SJustin Hibbits  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*c7570492SJustin Hibbits  * or http://www.opensolaris.org/os/licensing.
11*c7570492SJustin Hibbits  * See the License for the specific language governing permissions
12*c7570492SJustin Hibbits  * and limitations under the License.
13*c7570492SJustin Hibbits  *
14*c7570492SJustin Hibbits  * When distributing Covered Code, include this CDDL HEADER in each
15*c7570492SJustin Hibbits  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*c7570492SJustin Hibbits  * If applicable, add the following below this CDDL HEADER, with the
17*c7570492SJustin Hibbits  * fields enclosed by brackets "[]" replaced with your own identifying
18*c7570492SJustin Hibbits  * information: Portions Copyright [yyyy] [name of copyright owner]
19*c7570492SJustin Hibbits  *
20*c7570492SJustin Hibbits  * CDDL HEADER END
21*c7570492SJustin Hibbits  *
22*c7570492SJustin Hibbits  * $FreeBSD$
23*c7570492SJustin Hibbits  */
24*c7570492SJustin Hibbits /*
25*c7570492SJustin Hibbits  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26*c7570492SJustin Hibbits  * Use is subject to license terms.
27*c7570492SJustin Hibbits  */
28*c7570492SJustin Hibbits #include <sys/cdefs.h>
29*c7570492SJustin Hibbits 
30*c7570492SJustin Hibbits #include <sys/param.h>
31*c7570492SJustin Hibbits #include <sys/systm.h>
32*c7570492SJustin Hibbits #include <sys/kernel.h>
33*c7570492SJustin Hibbits #include <sys/stack.h>
34*c7570492SJustin Hibbits #include <sys/sysent.h>
35*c7570492SJustin Hibbits #include <sys/pcpu.h>
36*c7570492SJustin Hibbits 
37*c7570492SJustin Hibbits #include <machine/frame.h>
38*c7570492SJustin Hibbits #include <machine/md_var.h>
39*c7570492SJustin Hibbits #include <machine/reg.h>
40*c7570492SJustin Hibbits #include <machine/stack.h>
41*c7570492SJustin Hibbits 
42*c7570492SJustin Hibbits #include <vm/vm.h>
43*c7570492SJustin Hibbits #include <vm/vm_param.h>
44*c7570492SJustin Hibbits #include <vm/pmap.h>
45*c7570492SJustin Hibbits 
46*c7570492SJustin Hibbits #include "regset.h"
47*c7570492SJustin Hibbits 
48*c7570492SJustin Hibbits uint8_t dtrace_fuword8_nocheck(void *);
49*c7570492SJustin Hibbits uint16_t dtrace_fuword16_nocheck(void *);
50*c7570492SJustin Hibbits uint32_t dtrace_fuword32_nocheck(void *);
51*c7570492SJustin Hibbits uint64_t dtrace_fuword64_nocheck(void *);
52*c7570492SJustin Hibbits 
53*c7570492SJustin Hibbits /* Offset to the LR Save word (ppc32) */
54*c7570492SJustin Hibbits #define RETURN_OFFSET	4
55*c7570492SJustin Hibbits #define RETURN_OFFSET64	8
56*c7570492SJustin Hibbits 
57*c7570492SJustin Hibbits #define INKERNEL(x)	((x) <= VM_MAX_KERNEL_ADDRESS && \
58*c7570492SJustin Hibbits 		(x) >= VM_MIN_KERNEL_ADDRESS)
59*c7570492SJustin Hibbits 
60*c7570492SJustin Hibbits greg_t
61*c7570492SJustin Hibbits dtrace_getfp(void)
62*c7570492SJustin Hibbits {
63*c7570492SJustin Hibbits 	return (greg_t)__builtin_frame_address(0);
64*c7570492SJustin Hibbits }
65*c7570492SJustin Hibbits 
66*c7570492SJustin Hibbits void
67*c7570492SJustin Hibbits dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
68*c7570492SJustin Hibbits     uint32_t *intrpc)
69*c7570492SJustin Hibbits {
70*c7570492SJustin Hibbits 	int depth = 0;
71*c7570492SJustin Hibbits 	register_t sp;
72*c7570492SJustin Hibbits 	vm_offset_t callpc;
73*c7570492SJustin Hibbits 	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
74*c7570492SJustin Hibbits 
75*c7570492SJustin Hibbits 	if (intrpc != 0)
76*c7570492SJustin Hibbits 		pcstack[depth++] = (pc_t) intrpc;
77*c7570492SJustin Hibbits 
78*c7570492SJustin Hibbits 	aframes++;
79*c7570492SJustin Hibbits 
80*c7570492SJustin Hibbits 	sp = dtrace_getfp();
81*c7570492SJustin Hibbits 
82*c7570492SJustin Hibbits 	while (depth < pcstack_limit) {
83*c7570492SJustin Hibbits 		if (!INKERNEL((long) sp))
84*c7570492SJustin Hibbits 			break;
85*c7570492SJustin Hibbits 
86*c7570492SJustin Hibbits 		callpc = *(uintptr_t *)(sp + RETURN_OFFSET);
87*c7570492SJustin Hibbits 
88*c7570492SJustin Hibbits 		if (!INKERNEL(callpc))
89*c7570492SJustin Hibbits 			break;
90*c7570492SJustin Hibbits 
91*c7570492SJustin Hibbits 		if (aframes > 0) {
92*c7570492SJustin Hibbits 			aframes--;
93*c7570492SJustin Hibbits 			if ((aframes == 0) && (caller != 0)) {
94*c7570492SJustin Hibbits 				pcstack[depth++] = caller;
95*c7570492SJustin Hibbits 			}
96*c7570492SJustin Hibbits 		}
97*c7570492SJustin Hibbits 		else {
98*c7570492SJustin Hibbits 			pcstack[depth++] = callpc;
99*c7570492SJustin Hibbits 		}
100*c7570492SJustin Hibbits 
101*c7570492SJustin Hibbits 		sp = *(uintptr_t*)sp;
102*c7570492SJustin Hibbits 	}
103*c7570492SJustin Hibbits 
104*c7570492SJustin Hibbits 	for (; depth < pcstack_limit; depth++) {
105*c7570492SJustin Hibbits 		pcstack[depth] = 0;
106*c7570492SJustin Hibbits 	}
107*c7570492SJustin Hibbits }
108*c7570492SJustin Hibbits 
109*c7570492SJustin Hibbits static int
110*c7570492SJustin Hibbits dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
111*c7570492SJustin Hibbits     uintptr_t sp)
112*c7570492SJustin Hibbits {
113*c7570492SJustin Hibbits 	proc_t *p = curproc;
114*c7570492SJustin Hibbits 	int ret = 0;
115*c7570492SJustin Hibbits 
116*c7570492SJustin Hibbits 	ASSERT(pcstack == NULL || pcstack_limit > 0);
117*c7570492SJustin Hibbits 
118*c7570492SJustin Hibbits 	while (pc != 0) {
119*c7570492SJustin Hibbits 		ret++;
120*c7570492SJustin Hibbits 		if (pcstack != NULL) {
121*c7570492SJustin Hibbits 			*pcstack++ = (uint64_t)pc;
122*c7570492SJustin Hibbits 			pcstack_limit--;
123*c7570492SJustin Hibbits 			if (pcstack_limit <= 0)
124*c7570492SJustin Hibbits 				break;
125*c7570492SJustin Hibbits 		}
126*c7570492SJustin Hibbits 
127*c7570492SJustin Hibbits 		if (sp == 0)
128*c7570492SJustin Hibbits 			break;
129*c7570492SJustin Hibbits 
130*c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
131*c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
132*c7570492SJustin Hibbits 			sp = dtrace_fuword32((void *)sp);
133*c7570492SJustin Hibbits 		}
134*c7570492SJustin Hibbits 		else {
135*c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
136*c7570492SJustin Hibbits 			sp = dtrace_fuword64((void *)sp);
137*c7570492SJustin Hibbits 		}
138*c7570492SJustin Hibbits 	}
139*c7570492SJustin Hibbits 
140*c7570492SJustin Hibbits 	return (ret);
141*c7570492SJustin Hibbits }
142*c7570492SJustin Hibbits 
143*c7570492SJustin Hibbits void
144*c7570492SJustin Hibbits dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
145*c7570492SJustin Hibbits {
146*c7570492SJustin Hibbits 	proc_t *p = curproc;
147*c7570492SJustin Hibbits 	struct trapframe *tf;
148*c7570492SJustin Hibbits 	uintptr_t pc, sp;
149*c7570492SJustin Hibbits 	volatile uint16_t *flags =
150*c7570492SJustin Hibbits 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
151*c7570492SJustin Hibbits 	int n;
152*c7570492SJustin Hibbits 
153*c7570492SJustin Hibbits 	if (*flags & CPU_DTRACE_FAULT)
154*c7570492SJustin Hibbits 		return;
155*c7570492SJustin Hibbits 
156*c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
157*c7570492SJustin Hibbits 		return;
158*c7570492SJustin Hibbits 
159*c7570492SJustin Hibbits 	/*
160*c7570492SJustin Hibbits 	 * If there's no user context we still need to zero the stack.
161*c7570492SJustin Hibbits 	 */
162*c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
163*c7570492SJustin Hibbits 		goto zero;
164*c7570492SJustin Hibbits 
165*c7570492SJustin Hibbits 	*pcstack++ = (uint64_t)p->p_pid;
166*c7570492SJustin Hibbits 	pcstack_limit--;
167*c7570492SJustin Hibbits 
168*c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
169*c7570492SJustin Hibbits 		return;
170*c7570492SJustin Hibbits 
171*c7570492SJustin Hibbits 	pc = tf->srr0;
172*c7570492SJustin Hibbits 	sp = tf->fixreg[1];
173*c7570492SJustin Hibbits 
174*c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
175*c7570492SJustin Hibbits 		/*
176*c7570492SJustin Hibbits 		 * In an entry probe.  The frame pointer has not yet been
177*c7570492SJustin Hibbits 		 * pushed (that happens in the function prologue).  The
178*c7570492SJustin Hibbits 		 * best approach is to add the current pc as a missing top
179*c7570492SJustin Hibbits 		 * of stack and back the pc up to the caller, which is stored
180*c7570492SJustin Hibbits 		 * at the current stack pointer address since the call
181*c7570492SJustin Hibbits 		 * instruction puts it there right before the branch.
182*c7570492SJustin Hibbits 		 */
183*c7570492SJustin Hibbits 
184*c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
185*c7570492SJustin Hibbits 		pcstack_limit--;
186*c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
187*c7570492SJustin Hibbits 			return;
188*c7570492SJustin Hibbits 
189*c7570492SJustin Hibbits 		pc = tf->lr;
190*c7570492SJustin Hibbits 	}
191*c7570492SJustin Hibbits 
192*c7570492SJustin Hibbits 	n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
193*c7570492SJustin Hibbits 	ASSERT(n >= 0);
194*c7570492SJustin Hibbits 	ASSERT(n <= pcstack_limit);
195*c7570492SJustin Hibbits 
196*c7570492SJustin Hibbits 	pcstack += n;
197*c7570492SJustin Hibbits 	pcstack_limit -= n;
198*c7570492SJustin Hibbits 
199*c7570492SJustin Hibbits zero:
200*c7570492SJustin Hibbits 	while (pcstack_limit-- > 0)
201*c7570492SJustin Hibbits 		*pcstack++ = 0;
202*c7570492SJustin Hibbits }
203*c7570492SJustin Hibbits 
204*c7570492SJustin Hibbits int
205*c7570492SJustin Hibbits dtrace_getustackdepth(void)
206*c7570492SJustin Hibbits {
207*c7570492SJustin Hibbits 	proc_t *p = curproc;
208*c7570492SJustin Hibbits 	struct trapframe *tf;
209*c7570492SJustin Hibbits 	uintptr_t pc, sp;
210*c7570492SJustin Hibbits 	int n = 0;
211*c7570492SJustin Hibbits 
212*c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
213*c7570492SJustin Hibbits 		return (0);
214*c7570492SJustin Hibbits 
215*c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
216*c7570492SJustin Hibbits 		return (-1);
217*c7570492SJustin Hibbits 
218*c7570492SJustin Hibbits 	pc = tf->srr0;
219*c7570492SJustin Hibbits 	sp = tf->fixreg[1];
220*c7570492SJustin Hibbits 
221*c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
222*c7570492SJustin Hibbits 		/*
223*c7570492SJustin Hibbits 		 * In an entry probe.  The frame pointer has not yet been
224*c7570492SJustin Hibbits 		 * pushed (that happens in the function prologue).  The
225*c7570492SJustin Hibbits 		 * best approach is to add the current pc as a missing top
226*c7570492SJustin Hibbits 		 * of stack and back the pc up to the caller, which is stored
227*c7570492SJustin Hibbits 		 * at the current stack pointer address since the call
228*c7570492SJustin Hibbits 		 * instruction puts it there right before the branch.
229*c7570492SJustin Hibbits 		 */
230*c7570492SJustin Hibbits 
231*c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
232*c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *) sp);
233*c7570492SJustin Hibbits 		}
234*c7570492SJustin Hibbits 		else
235*c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *) sp);
236*c7570492SJustin Hibbits 		n++;
237*c7570492SJustin Hibbits 	}
238*c7570492SJustin Hibbits 
239*c7570492SJustin Hibbits 	n += dtrace_getustack_common(NULL, 0, pc, sp);
240*c7570492SJustin Hibbits 
241*c7570492SJustin Hibbits 	return (n);
242*c7570492SJustin Hibbits }
243*c7570492SJustin Hibbits 
244*c7570492SJustin Hibbits void
245*c7570492SJustin Hibbits dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
246*c7570492SJustin Hibbits {
247*c7570492SJustin Hibbits 	proc_t *p = curproc;
248*c7570492SJustin Hibbits 	struct trapframe *tf;
249*c7570492SJustin Hibbits 	uintptr_t pc, sp;
250*c7570492SJustin Hibbits 	volatile uint16_t *flags =
251*c7570492SJustin Hibbits 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
252*c7570492SJustin Hibbits #ifdef notyet	/* XXX signal stack */
253*c7570492SJustin Hibbits 	uintptr_t oldcontext;
254*c7570492SJustin Hibbits 	size_t s1, s2;
255*c7570492SJustin Hibbits #endif
256*c7570492SJustin Hibbits 
257*c7570492SJustin Hibbits 	if (*flags & CPU_DTRACE_FAULT)
258*c7570492SJustin Hibbits 		return;
259*c7570492SJustin Hibbits 
260*c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
261*c7570492SJustin Hibbits 		return;
262*c7570492SJustin Hibbits 
263*c7570492SJustin Hibbits 	/*
264*c7570492SJustin Hibbits 	 * If there's no user context we still need to zero the stack.
265*c7570492SJustin Hibbits 	 */
266*c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
267*c7570492SJustin Hibbits 		goto zero;
268*c7570492SJustin Hibbits 
269*c7570492SJustin Hibbits 	*pcstack++ = (uint64_t)p->p_pid;
270*c7570492SJustin Hibbits 	pcstack_limit--;
271*c7570492SJustin Hibbits 
272*c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
273*c7570492SJustin Hibbits 		return;
274*c7570492SJustin Hibbits 
275*c7570492SJustin Hibbits 	pc = tf->srr0;
276*c7570492SJustin Hibbits 	sp = tf->fixreg[1];
277*c7570492SJustin Hibbits 
278*c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */
279*c7570492SJustin Hibbits 	oldcontext = lwp->lwp_oldcontext;
280*c7570492SJustin Hibbits 	s1 = sizeof (struct xframe) + 2 * sizeof (long);
281*c7570492SJustin Hibbits 	s2 = s1 + sizeof (siginfo_t);
282*c7570492SJustin Hibbits #endif
283*c7570492SJustin Hibbits 
284*c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
285*c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
286*c7570492SJustin Hibbits 		*fpstack++ = 0;
287*c7570492SJustin Hibbits 		pcstack_limit--;
288*c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
289*c7570492SJustin Hibbits 			return;
290*c7570492SJustin Hibbits 
291*c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
292*c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *)sp);
293*c7570492SJustin Hibbits 		}
294*c7570492SJustin Hibbits 		else {
295*c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *)sp);
296*c7570492SJustin Hibbits 		}
297*c7570492SJustin Hibbits 	}
298*c7570492SJustin Hibbits 
299*c7570492SJustin Hibbits 	while (pc != 0) {
300*c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
301*c7570492SJustin Hibbits 		*fpstack++ = sp;
302*c7570492SJustin Hibbits 		pcstack_limit--;
303*c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
304*c7570492SJustin Hibbits 			break;
305*c7570492SJustin Hibbits 
306*c7570492SJustin Hibbits 		if (sp == 0)
307*c7570492SJustin Hibbits 			break;
308*c7570492SJustin Hibbits 
309*c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */
310*c7570492SJustin Hibbits 		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
311*c7570492SJustin Hibbits 			ucontext_t *ucp = (ucontext_t *)oldcontext;
312*c7570492SJustin Hibbits 			greg_t *gregs = ucp->uc_mcontext.gregs;
313*c7570492SJustin Hibbits 
314*c7570492SJustin Hibbits 			sp = dtrace_fulword(&gregs[REG_FP]);
315*c7570492SJustin Hibbits 			pc = dtrace_fulword(&gregs[REG_PC]);
316*c7570492SJustin Hibbits 
317*c7570492SJustin Hibbits 			oldcontext = dtrace_fulword(&ucp->uc_link);
318*c7570492SJustin Hibbits 		} else
319*c7570492SJustin Hibbits #endif /* XXX */
320*c7570492SJustin Hibbits 		{
321*c7570492SJustin Hibbits 			if (SV_PROC_FLAG(p, SV_ILP32)) {
322*c7570492SJustin Hibbits 				pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
323*c7570492SJustin Hibbits 				sp = dtrace_fuword32((void *)sp);
324*c7570492SJustin Hibbits 			}
325*c7570492SJustin Hibbits 			else {
326*c7570492SJustin Hibbits 				pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
327*c7570492SJustin Hibbits 				sp = dtrace_fuword64((void *)sp);
328*c7570492SJustin Hibbits 			}
329*c7570492SJustin Hibbits 		}
330*c7570492SJustin Hibbits 
331*c7570492SJustin Hibbits 		/*
332*c7570492SJustin Hibbits 		 * This is totally bogus:  if we faulted, we're going to clear
333*c7570492SJustin Hibbits 		 * the fault and break.  This is to deal with the apparently
334*c7570492SJustin Hibbits 		 * broken Java stacks on x86.
335*c7570492SJustin Hibbits 		 */
336*c7570492SJustin Hibbits 		if (*flags & CPU_DTRACE_FAULT) {
337*c7570492SJustin Hibbits 			*flags &= ~CPU_DTRACE_FAULT;
338*c7570492SJustin Hibbits 			break;
339*c7570492SJustin Hibbits 		}
340*c7570492SJustin Hibbits 	}
341*c7570492SJustin Hibbits 
342*c7570492SJustin Hibbits zero:
343*c7570492SJustin Hibbits 	while (pcstack_limit-- > 0)
344*c7570492SJustin Hibbits 		*pcstack++ = 0;
345*c7570492SJustin Hibbits }
346*c7570492SJustin Hibbits 
347*c7570492SJustin Hibbits /*ARGSUSED*/
348*c7570492SJustin Hibbits uint64_t
349*c7570492SJustin Hibbits dtrace_getarg(int arg, int aframes)
350*c7570492SJustin Hibbits {
351*c7570492SJustin Hibbits 	return (0);
352*c7570492SJustin Hibbits }
353*c7570492SJustin Hibbits 
354*c7570492SJustin Hibbits #ifdef notyet
355*c7570492SJustin Hibbits {
356*c7570492SJustin Hibbits 	int depth = 0;
357*c7570492SJustin Hibbits 	register_t sp;
358*c7570492SJustin Hibbits 	vm_offset_t callpc;
359*c7570492SJustin Hibbits 	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
360*c7570492SJustin Hibbits 
361*c7570492SJustin Hibbits 	if (intrpc != 0)
362*c7570492SJustin Hibbits 		pcstack[depth++] = (pc_t) intrpc;
363*c7570492SJustin Hibbits 
364*c7570492SJustin Hibbits 	aframes++;
365*c7570492SJustin Hibbits 
366*c7570492SJustin Hibbits 	sp = dtrace_getfp();
367*c7570492SJustin Hibbits 
368*c7570492SJustin Hibbits 	while (depth < pcstack_limit) {
369*c7570492SJustin Hibbits 		if (!INKERNEL((long) frame))
370*c7570492SJustin Hibbits 			break;
371*c7570492SJustin Hibbits 
372*c7570492SJustin Hibbits 		callpc = *(void **)(sp + RETURN_OFFSET);
373*c7570492SJustin Hibbits 
374*c7570492SJustin Hibbits 		if (!INKERNEL(callpc))
375*c7570492SJustin Hibbits 			break;
376*c7570492SJustin Hibbits 
377*c7570492SJustin Hibbits 		if (aframes > 0) {
378*c7570492SJustin Hibbits 			aframes--;
379*c7570492SJustin Hibbits 			if ((aframes == 0) && (caller != 0)) {
380*c7570492SJustin Hibbits 				pcstack[depth++] = caller;
381*c7570492SJustin Hibbits 			}
382*c7570492SJustin Hibbits 		}
383*c7570492SJustin Hibbits 		else {
384*c7570492SJustin Hibbits 			pcstack[depth++] = callpc;
385*c7570492SJustin Hibbits 		}
386*c7570492SJustin Hibbits 
387*c7570492SJustin Hibbits 		sp = *(void **)sp;
388*c7570492SJustin Hibbits 	}
389*c7570492SJustin Hibbits 
390*c7570492SJustin Hibbits 	for (; depth < pcstack_limit; depth++) {
391*c7570492SJustin Hibbits 		pcstack[depth] = 0;
392*c7570492SJustin Hibbits 	}
393*c7570492SJustin Hibbits }
394*c7570492SJustin Hibbits #endif
395*c7570492SJustin Hibbits 
396*c7570492SJustin Hibbits int
397*c7570492SJustin Hibbits dtrace_getstackdepth(int aframes)
398*c7570492SJustin Hibbits {
399*c7570492SJustin Hibbits 	int depth = 0;
400*c7570492SJustin Hibbits 	register_t sp;
401*c7570492SJustin Hibbits 
402*c7570492SJustin Hibbits 	aframes++;
403*c7570492SJustin Hibbits 	sp = dtrace_getfp();
404*c7570492SJustin Hibbits 	depth++;
405*c7570492SJustin Hibbits 	for(;;) {
406*c7570492SJustin Hibbits 		if (!INKERNEL((long) sp))
407*c7570492SJustin Hibbits 			break;
408*c7570492SJustin Hibbits 		if (!INKERNEL((long) *(void **)sp))
409*c7570492SJustin Hibbits 			break;
410*c7570492SJustin Hibbits 		depth++;
411*c7570492SJustin Hibbits 		sp = *(uintptr_t *)sp;
412*c7570492SJustin Hibbits 	}
413*c7570492SJustin Hibbits 	if (depth < aframes)
414*c7570492SJustin Hibbits 		return 0;
415*c7570492SJustin Hibbits 	else
416*c7570492SJustin Hibbits 		return depth - aframes;
417*c7570492SJustin Hibbits }
418*c7570492SJustin Hibbits 
419*c7570492SJustin Hibbits ulong_t
420*c7570492SJustin Hibbits dtrace_getreg(struct trapframe *rp, uint_t reg)
421*c7570492SJustin Hibbits {
422*c7570492SJustin Hibbits 	if (reg < 32)
423*c7570492SJustin Hibbits 		return (rp->fixreg[reg]);
424*c7570492SJustin Hibbits 
425*c7570492SJustin Hibbits 	switch (reg) {
426*c7570492SJustin Hibbits 	case 33:
427*c7570492SJustin Hibbits 		return (rp->lr);
428*c7570492SJustin Hibbits 	case 34:
429*c7570492SJustin Hibbits 		return (rp->cr);
430*c7570492SJustin Hibbits 	case 35:
431*c7570492SJustin Hibbits 		return (rp->xer);
432*c7570492SJustin Hibbits 	case 36:
433*c7570492SJustin Hibbits 		return (rp->ctr);
434*c7570492SJustin Hibbits 	case 37:
435*c7570492SJustin Hibbits 		return (rp->srr0);
436*c7570492SJustin Hibbits 	case 38:
437*c7570492SJustin Hibbits 		return (rp->srr1);
438*c7570492SJustin Hibbits 	case 39:
439*c7570492SJustin Hibbits 		return (rp->exc);
440*c7570492SJustin Hibbits 	default:
441*c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
442*c7570492SJustin Hibbits 		return (0);
443*c7570492SJustin Hibbits 	}
444*c7570492SJustin Hibbits }
445*c7570492SJustin Hibbits 
446*c7570492SJustin Hibbits static int
447*c7570492SJustin Hibbits dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
448*c7570492SJustin Hibbits {
449*c7570492SJustin Hibbits 	ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
450*c7570492SJustin Hibbits 
451*c7570492SJustin Hibbits 	if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
452*c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
453*c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
454*c7570492SJustin Hibbits 		return (0);
455*c7570492SJustin Hibbits 	}
456*c7570492SJustin Hibbits 
457*c7570492SJustin Hibbits 	return (1);
458*c7570492SJustin Hibbits }
459*c7570492SJustin Hibbits 
460*c7570492SJustin Hibbits void
461*c7570492SJustin Hibbits dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
462*c7570492SJustin Hibbits     volatile uint16_t *flags)
463*c7570492SJustin Hibbits {
464*c7570492SJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size))
465*c7570492SJustin Hibbits 		dtrace_copy(uaddr, kaddr, size);
466*c7570492SJustin Hibbits }
467*c7570492SJustin Hibbits 
468*c7570492SJustin Hibbits void
469*c7570492SJustin Hibbits dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
470*c7570492SJustin Hibbits     volatile uint16_t *flags)
471*c7570492SJustin Hibbits {
472*c7570492SJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size))
473*c7570492SJustin Hibbits 		dtrace_copy(kaddr, uaddr, size);
474*c7570492SJustin Hibbits }
475*c7570492SJustin Hibbits 
476*c7570492SJustin Hibbits void
477*c7570492SJustin Hibbits dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
478*c7570492SJustin Hibbits     volatile uint16_t *flags)
479*c7570492SJustin Hibbits {
480*c7570492SJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size))
481*c7570492SJustin Hibbits 		dtrace_copystr(uaddr, kaddr, size, flags);
482*c7570492SJustin Hibbits }
483*c7570492SJustin Hibbits 
484*c7570492SJustin Hibbits void
485*c7570492SJustin Hibbits dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
486*c7570492SJustin Hibbits     volatile uint16_t *flags)
487*c7570492SJustin Hibbits {
488*c7570492SJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size))
489*c7570492SJustin Hibbits 		dtrace_copystr(kaddr, uaddr, size, flags);
490*c7570492SJustin Hibbits }
491*c7570492SJustin Hibbits 
492*c7570492SJustin Hibbits uint8_t
493*c7570492SJustin Hibbits dtrace_fuword8(void *uaddr)
494*c7570492SJustin Hibbits {
495*c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
496*c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
497*c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
498*c7570492SJustin Hibbits 		return (0);
499*c7570492SJustin Hibbits 	}
500*c7570492SJustin Hibbits 	return (dtrace_fuword8_nocheck(uaddr));
501*c7570492SJustin Hibbits }
502*c7570492SJustin Hibbits 
503*c7570492SJustin Hibbits uint16_t
504*c7570492SJustin Hibbits dtrace_fuword16(void *uaddr)
505*c7570492SJustin Hibbits {
506*c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
507*c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
508*c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
509*c7570492SJustin Hibbits 		return (0);
510*c7570492SJustin Hibbits 	}
511*c7570492SJustin Hibbits 	return (dtrace_fuword16_nocheck(uaddr));
512*c7570492SJustin Hibbits }
513*c7570492SJustin Hibbits 
514*c7570492SJustin Hibbits uint32_t
515*c7570492SJustin Hibbits dtrace_fuword32(void *uaddr)
516*c7570492SJustin Hibbits {
517*c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
518*c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
519*c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
520*c7570492SJustin Hibbits 		return (0);
521*c7570492SJustin Hibbits 	}
522*c7570492SJustin Hibbits 	return (dtrace_fuword32_nocheck(uaddr));
523*c7570492SJustin Hibbits }
524*c7570492SJustin Hibbits 
525*c7570492SJustin Hibbits uint64_t
526*c7570492SJustin Hibbits dtrace_fuword64(void *uaddr)
527*c7570492SJustin Hibbits {
528*c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
529*c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
530*c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
531*c7570492SJustin Hibbits 		return (0);
532*c7570492SJustin Hibbits 	}
533*c7570492SJustin Hibbits 	return (dtrace_fuword64_nocheck(uaddr));
534*c7570492SJustin Hibbits }
535