xref: /freebsd/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c (revision 675cad71e76b959b01d1926739b632e3eae9182b)
1c7570492SJustin Hibbits /*
2c7570492SJustin Hibbits  * CDDL HEADER START
3c7570492SJustin Hibbits  *
4c7570492SJustin Hibbits  * The contents of this file are subject to the terms of the
5c7570492SJustin Hibbits  * Common Development and Distribution License, Version 1.0 only
6c7570492SJustin Hibbits  * (the "License").  You may not use this file except in compliance
7c7570492SJustin Hibbits  * with the License.
8c7570492SJustin Hibbits  *
9c7570492SJustin Hibbits  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10c7570492SJustin Hibbits  * or http://www.opensolaris.org/os/licensing.
11c7570492SJustin Hibbits  * See the License for the specific language governing permissions
12c7570492SJustin Hibbits  * and limitations under the License.
13c7570492SJustin Hibbits  *
14c7570492SJustin Hibbits  * When distributing Covered Code, include this CDDL HEADER in each
15c7570492SJustin Hibbits  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16c7570492SJustin Hibbits  * If applicable, add the following below this CDDL HEADER, with the
17c7570492SJustin Hibbits  * fields enclosed by brackets "[]" replaced with your own identifying
18c7570492SJustin Hibbits  * information: Portions Copyright [yyyy] [name of copyright owner]
19c7570492SJustin Hibbits  *
20c7570492SJustin Hibbits  * CDDL HEADER END
21c7570492SJustin Hibbits  *
227e7a9efdSJustin Hibbits  * Portions Copyright 2012,2013 Justin Hibbits <jhibbits@freebsd.org>
237e7a9efdSJustin Hibbits  *
24c7570492SJustin Hibbits  * $FreeBSD$
25c7570492SJustin Hibbits  */
26c7570492SJustin Hibbits /*
27c7570492SJustin Hibbits  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28c7570492SJustin Hibbits  * Use is subject to license terms.
29c7570492SJustin Hibbits  */
30c7570492SJustin Hibbits #include <sys/cdefs.h>
31c7570492SJustin Hibbits 
32c7570492SJustin Hibbits #include <sys/param.h>
33c7570492SJustin Hibbits #include <sys/systm.h>
34c7570492SJustin Hibbits #include <sys/kernel.h>
35c7570492SJustin Hibbits #include <sys/stack.h>
36c7570492SJustin Hibbits #include <sys/sysent.h>
37c7570492SJustin Hibbits #include <sys/pcpu.h>
38c7570492SJustin Hibbits 
39c7570492SJustin Hibbits #include <machine/frame.h>
40c7570492SJustin Hibbits #include <machine/md_var.h>
41*675cad71SJustin Hibbits #include <machine/psl.h>
42c7570492SJustin Hibbits #include <machine/reg.h>
43c7570492SJustin Hibbits #include <machine/stack.h>
44c7570492SJustin Hibbits 
45c7570492SJustin Hibbits #include <vm/vm.h>
46c7570492SJustin Hibbits #include <vm/vm_param.h>
47c7570492SJustin Hibbits #include <vm/pmap.h>
48c7570492SJustin Hibbits 
49c7570492SJustin Hibbits #include "regset.h"
50c7570492SJustin Hibbits 
51c7570492SJustin Hibbits /* Offset to the LR Save word (ppc32) */
52c7570492SJustin Hibbits #define RETURN_OFFSET	4
53594ce9adSJustin Hibbits /* Offset to LR Save word (ppc64).  CR Save area sits between back chain and LR */
54594ce9adSJustin Hibbits #define RETURN_OFFSET64	16
55c7570492SJustin Hibbits 
56e40a5cd3SJustin Hibbits #ifdef __powerpc64__
57e40a5cd3SJustin Hibbits #define OFFSET 4 /* Account for the TOC reload slot */
58*675cad71SJustin Hibbits #define	FRAME_OFFSET	48
59e40a5cd3SJustin Hibbits #else
60e40a5cd3SJustin Hibbits #define OFFSET 0
61*675cad71SJustin Hibbits #define	FRAME_OFFSET	8
62e40a5cd3SJustin Hibbits #endif
63e40a5cd3SJustin Hibbits 
64c7570492SJustin Hibbits #define INKERNEL(x)	((x) <= VM_MAX_KERNEL_ADDRESS && \
65c7570492SJustin Hibbits 		(x) >= VM_MIN_KERNEL_ADDRESS)
66c7570492SJustin Hibbits 
67e40a5cd3SJustin Hibbits static __inline int
68*675cad71SJustin Hibbits dtrace_sp_inkernel(uintptr_t sp)
69e40a5cd3SJustin Hibbits {
70*675cad71SJustin Hibbits 	struct trapframe *frame;
71e40a5cd3SJustin Hibbits 	vm_offset_t callpc;
72e40a5cd3SJustin Hibbits 
73e40a5cd3SJustin Hibbits #ifdef __powerpc64__
74e40a5cd3SJustin Hibbits 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
75e40a5cd3SJustin Hibbits #else
76e40a5cd3SJustin Hibbits 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
77e40a5cd3SJustin Hibbits #endif
78e40a5cd3SJustin Hibbits 	if ((callpc & 3) || (callpc < 0x100))
79e40a5cd3SJustin Hibbits 		return (0);
80e40a5cd3SJustin Hibbits 
81e40a5cd3SJustin Hibbits 	/*
82e40a5cd3SJustin Hibbits 	 * trapexit() and asttrapexit() are sentinels
83e40a5cd3SJustin Hibbits 	 * for kernel stack tracing.
84e40a5cd3SJustin Hibbits 	 */
85*675cad71SJustin Hibbits 	if (callpc + OFFSET == (vm_offset_t) &trapexit ||
86*675cad71SJustin Hibbits 	    callpc + OFFSET == (vm_offset_t) &asttrapexit) {
87*675cad71SJustin Hibbits 		if (sp == 0)
88e40a5cd3SJustin Hibbits 			return (0);
89*675cad71SJustin Hibbits 		frame = (struct trapframe *)(sp + FRAME_OFFSET);
90*675cad71SJustin Hibbits 
91*675cad71SJustin Hibbits 		return ((frame->srr1 & PSL_PR) == 0);
92*675cad71SJustin Hibbits 	}
93e40a5cd3SJustin Hibbits 
94e40a5cd3SJustin Hibbits 	return (1);
95e40a5cd3SJustin Hibbits }
96e40a5cd3SJustin Hibbits 
97e40a5cd3SJustin Hibbits static __inline uintptr_t
98e40a5cd3SJustin Hibbits dtrace_next_sp(uintptr_t sp)
99e40a5cd3SJustin Hibbits {
100e40a5cd3SJustin Hibbits 	vm_offset_t callpc;
101*675cad71SJustin Hibbits 	struct trapframe *frame;
102e40a5cd3SJustin Hibbits 
103e40a5cd3SJustin Hibbits #ifdef __powerpc64__
104e40a5cd3SJustin Hibbits 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
105e40a5cd3SJustin Hibbits #else
106e40a5cd3SJustin Hibbits 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
107e40a5cd3SJustin Hibbits #endif
108e40a5cd3SJustin Hibbits 
109e40a5cd3SJustin Hibbits 	/*
110e40a5cd3SJustin Hibbits 	 * trapexit() and asttrapexit() are sentinels
111e40a5cd3SJustin Hibbits 	 * for kernel stack tracing.
112e40a5cd3SJustin Hibbits 	 */
113e40a5cd3SJustin Hibbits 	if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
114*675cad71SJustin Hibbits 	    callpc + OFFSET == (vm_offset_t) &asttrapexit)) {
115e40a5cd3SJustin Hibbits 		/* Access the trap frame */
116*675cad71SJustin Hibbits 		frame = (struct trapframe *)(sp + FRAME_OFFSET);
117*675cad71SJustin Hibbits 		return (*(uintptr_t *)(frame->fixreg[1]));
118*675cad71SJustin Hibbits 	}
119e40a5cd3SJustin Hibbits 
120e40a5cd3SJustin Hibbits 	return (*(uintptr_t*)sp);
121e40a5cd3SJustin Hibbits }
122e40a5cd3SJustin Hibbits 
123e40a5cd3SJustin Hibbits static __inline uintptr_t
124e40a5cd3SJustin Hibbits dtrace_get_pc(uintptr_t sp)
125e40a5cd3SJustin Hibbits {
126*675cad71SJustin Hibbits 	struct trapframe *frame;
127e40a5cd3SJustin Hibbits 	vm_offset_t callpc;
128e40a5cd3SJustin Hibbits 
129e40a5cd3SJustin Hibbits #ifdef __powerpc64__
130e40a5cd3SJustin Hibbits 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
131e40a5cd3SJustin Hibbits #else
132e40a5cd3SJustin Hibbits 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
133e40a5cd3SJustin Hibbits #endif
134e40a5cd3SJustin Hibbits 
135e40a5cd3SJustin Hibbits 	/*
136e40a5cd3SJustin Hibbits 	 * trapexit() and asttrapexit() are sentinels
137e40a5cd3SJustin Hibbits 	 * for kernel stack tracing.
138e40a5cd3SJustin Hibbits 	 */
139e40a5cd3SJustin Hibbits 	if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
140*675cad71SJustin Hibbits 	    callpc + OFFSET == (vm_offset_t) &asttrapexit)) {
141e40a5cd3SJustin Hibbits 		/* Access the trap frame */
142*675cad71SJustin Hibbits 		frame = (struct trapframe *)(sp + FRAME_OFFSET);
143*675cad71SJustin Hibbits 		return (frame->srr0);
144*675cad71SJustin Hibbits 	}
145e40a5cd3SJustin Hibbits 
146e40a5cd3SJustin Hibbits 	return (callpc);
147e40a5cd3SJustin Hibbits }
148e40a5cd3SJustin Hibbits 
149c7570492SJustin Hibbits greg_t
150c7570492SJustin Hibbits dtrace_getfp(void)
151c7570492SJustin Hibbits {
152c7570492SJustin Hibbits 	return (greg_t)__builtin_frame_address(0);
153c7570492SJustin Hibbits }
154c7570492SJustin Hibbits 
155c7570492SJustin Hibbits void
156c7570492SJustin Hibbits dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
157c7570492SJustin Hibbits     uint32_t *intrpc)
158c7570492SJustin Hibbits {
159c7570492SJustin Hibbits 	int depth = 0;
160e40a5cd3SJustin Hibbits 	uintptr_t osp, sp;
161c7570492SJustin Hibbits 	vm_offset_t callpc;
162c7570492SJustin Hibbits 	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
163c7570492SJustin Hibbits 
164e40a5cd3SJustin Hibbits 	osp = PAGE_SIZE;
165c7570492SJustin Hibbits 	if (intrpc != 0)
166c7570492SJustin Hibbits 		pcstack[depth++] = (pc_t) intrpc;
167c7570492SJustin Hibbits 
168c7570492SJustin Hibbits 	aframes++;
169c7570492SJustin Hibbits 
170c7570492SJustin Hibbits 	sp = dtrace_getfp();
171c7570492SJustin Hibbits 
172c7570492SJustin Hibbits 	while (depth < pcstack_limit) {
173e40a5cd3SJustin Hibbits 		if (sp <= osp)
174c7570492SJustin Hibbits 			break;
175c7570492SJustin Hibbits 
176*675cad71SJustin Hibbits 		if (!dtrace_sp_inkernel(sp))
177c7570492SJustin Hibbits 			break;
178e40a5cd3SJustin Hibbits 		callpc = dtrace_get_pc(sp);
179c7570492SJustin Hibbits 
180c7570492SJustin Hibbits 		if (aframes > 0) {
181c7570492SJustin Hibbits 			aframes--;
182c7570492SJustin Hibbits 			if ((aframes == 0) && (caller != 0)) {
183c7570492SJustin Hibbits 				pcstack[depth++] = caller;
184c7570492SJustin Hibbits 			}
185c7570492SJustin Hibbits 		}
186c7570492SJustin Hibbits 		else {
187c7570492SJustin Hibbits 			pcstack[depth++] = callpc;
188c7570492SJustin Hibbits 		}
189c7570492SJustin Hibbits 
190e40a5cd3SJustin Hibbits 		osp = sp;
191e40a5cd3SJustin Hibbits 		sp = dtrace_next_sp(sp);
192c7570492SJustin Hibbits 	}
193c7570492SJustin Hibbits 
194c7570492SJustin Hibbits 	for (; depth < pcstack_limit; depth++) {
195c7570492SJustin Hibbits 		pcstack[depth] = 0;
196c7570492SJustin Hibbits 	}
197c7570492SJustin Hibbits }
198c7570492SJustin Hibbits 
199c7570492SJustin Hibbits static int
200c7570492SJustin Hibbits dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
201c7570492SJustin Hibbits     uintptr_t sp)
202c7570492SJustin Hibbits {
203c7570492SJustin Hibbits 	proc_t *p = curproc;
204c7570492SJustin Hibbits 	int ret = 0;
205c7570492SJustin Hibbits 
206c7570492SJustin Hibbits 	ASSERT(pcstack == NULL || pcstack_limit > 0);
207c7570492SJustin Hibbits 
208c7570492SJustin Hibbits 	while (pc != 0) {
209c7570492SJustin Hibbits 		ret++;
210c7570492SJustin Hibbits 		if (pcstack != NULL) {
211c7570492SJustin Hibbits 			*pcstack++ = (uint64_t)pc;
212c7570492SJustin Hibbits 			pcstack_limit--;
213c7570492SJustin Hibbits 			if (pcstack_limit <= 0)
214c7570492SJustin Hibbits 				break;
215c7570492SJustin Hibbits 		}
216c7570492SJustin Hibbits 
217c7570492SJustin Hibbits 		if (sp == 0)
218c7570492SJustin Hibbits 			break;
219c7570492SJustin Hibbits 
220c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
221c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
222c7570492SJustin Hibbits 			sp = dtrace_fuword32((void *)sp);
223c7570492SJustin Hibbits 		}
224c7570492SJustin Hibbits 		else {
225c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
226c7570492SJustin Hibbits 			sp = dtrace_fuword64((void *)sp);
227c7570492SJustin Hibbits 		}
228c7570492SJustin Hibbits 	}
229c7570492SJustin Hibbits 
230c7570492SJustin Hibbits 	return (ret);
231c7570492SJustin Hibbits }
232c7570492SJustin Hibbits 
233c7570492SJustin Hibbits void
234c7570492SJustin Hibbits dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
235c7570492SJustin Hibbits {
236c7570492SJustin Hibbits 	proc_t *p = curproc;
237c7570492SJustin Hibbits 	struct trapframe *tf;
238c7570492SJustin Hibbits 	uintptr_t pc, sp;
239c7570492SJustin Hibbits 	volatile uint16_t *flags =
240c7570492SJustin Hibbits 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
241c7570492SJustin Hibbits 	int n;
242c7570492SJustin Hibbits 
243c7570492SJustin Hibbits 	if (*flags & CPU_DTRACE_FAULT)
244c7570492SJustin Hibbits 		return;
245c7570492SJustin Hibbits 
246c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
247c7570492SJustin Hibbits 		return;
248c7570492SJustin Hibbits 
249c7570492SJustin Hibbits 	/*
250c7570492SJustin Hibbits 	 * If there's no user context we still need to zero the stack.
251c7570492SJustin Hibbits 	 */
252c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
253c7570492SJustin Hibbits 		goto zero;
254c7570492SJustin Hibbits 
255c7570492SJustin Hibbits 	*pcstack++ = (uint64_t)p->p_pid;
256c7570492SJustin Hibbits 	pcstack_limit--;
257c7570492SJustin Hibbits 
258c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
259c7570492SJustin Hibbits 		return;
260c7570492SJustin Hibbits 
261c7570492SJustin Hibbits 	pc = tf->srr0;
262c7570492SJustin Hibbits 	sp = tf->fixreg[1];
263c7570492SJustin Hibbits 
264c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
265c7570492SJustin Hibbits 		/*
266c7570492SJustin Hibbits 		 * In an entry probe.  The frame pointer has not yet been
267c7570492SJustin Hibbits 		 * pushed (that happens in the function prologue).  The
268c7570492SJustin Hibbits 		 * best approach is to add the current pc as a missing top
269c7570492SJustin Hibbits 		 * of stack and back the pc up to the caller, which is stored
270c7570492SJustin Hibbits 		 * at the current stack pointer address since the call
271c7570492SJustin Hibbits 		 * instruction puts it there right before the branch.
272c7570492SJustin Hibbits 		 */
273c7570492SJustin Hibbits 
274c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
275c7570492SJustin Hibbits 		pcstack_limit--;
276c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
277c7570492SJustin Hibbits 			return;
278c7570492SJustin Hibbits 
279c7570492SJustin Hibbits 		pc = tf->lr;
280c7570492SJustin Hibbits 	}
281c7570492SJustin Hibbits 
282c7570492SJustin Hibbits 	n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
283c7570492SJustin Hibbits 	ASSERT(n >= 0);
284c7570492SJustin Hibbits 	ASSERT(n <= pcstack_limit);
285c7570492SJustin Hibbits 
286c7570492SJustin Hibbits 	pcstack += n;
287c7570492SJustin Hibbits 	pcstack_limit -= n;
288c7570492SJustin Hibbits 
289c7570492SJustin Hibbits zero:
290c7570492SJustin Hibbits 	while (pcstack_limit-- > 0)
291c7570492SJustin Hibbits 		*pcstack++ = 0;
292c7570492SJustin Hibbits }
293c7570492SJustin Hibbits 
294c7570492SJustin Hibbits int
295c7570492SJustin Hibbits dtrace_getustackdepth(void)
296c7570492SJustin Hibbits {
297c7570492SJustin Hibbits 	proc_t *p = curproc;
298c7570492SJustin Hibbits 	struct trapframe *tf;
299c7570492SJustin Hibbits 	uintptr_t pc, sp;
300c7570492SJustin Hibbits 	int n = 0;
301c7570492SJustin Hibbits 
302c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
303c7570492SJustin Hibbits 		return (0);
304c7570492SJustin Hibbits 
305c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
306c7570492SJustin Hibbits 		return (-1);
307c7570492SJustin Hibbits 
308c7570492SJustin Hibbits 	pc = tf->srr0;
309c7570492SJustin Hibbits 	sp = tf->fixreg[1];
310c7570492SJustin Hibbits 
311c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
312c7570492SJustin Hibbits 		/*
313c7570492SJustin Hibbits 		 * In an entry probe.  The frame pointer has not yet been
314c7570492SJustin Hibbits 		 * pushed (that happens in the function prologue).  The
315c7570492SJustin Hibbits 		 * best approach is to add the current pc as a missing top
316c7570492SJustin Hibbits 		 * of stack and back the pc up to the caller, which is stored
317c7570492SJustin Hibbits 		 * at the current stack pointer address since the call
318c7570492SJustin Hibbits 		 * instruction puts it there right before the branch.
319c7570492SJustin Hibbits 		 */
320c7570492SJustin Hibbits 
321c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
322c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *) sp);
323c7570492SJustin Hibbits 		}
324c7570492SJustin Hibbits 		else
325c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *) sp);
326c7570492SJustin Hibbits 		n++;
327c7570492SJustin Hibbits 	}
328c7570492SJustin Hibbits 
329c7570492SJustin Hibbits 	n += dtrace_getustack_common(NULL, 0, pc, sp);
330c7570492SJustin Hibbits 
331c7570492SJustin Hibbits 	return (n);
332c7570492SJustin Hibbits }
333c7570492SJustin Hibbits 
334c7570492SJustin Hibbits void
335c7570492SJustin Hibbits dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
336c7570492SJustin Hibbits {
337c7570492SJustin Hibbits 	proc_t *p = curproc;
338c7570492SJustin Hibbits 	struct trapframe *tf;
339c7570492SJustin Hibbits 	uintptr_t pc, sp;
340c7570492SJustin Hibbits 	volatile uint16_t *flags =
341c7570492SJustin Hibbits 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
342c7570492SJustin Hibbits #ifdef notyet	/* XXX signal stack */
343c7570492SJustin Hibbits 	uintptr_t oldcontext;
344c7570492SJustin Hibbits 	size_t s1, s2;
345c7570492SJustin Hibbits #endif
346c7570492SJustin Hibbits 
347c7570492SJustin Hibbits 	if (*flags & CPU_DTRACE_FAULT)
348c7570492SJustin Hibbits 		return;
349c7570492SJustin Hibbits 
350c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
351c7570492SJustin Hibbits 		return;
352c7570492SJustin Hibbits 
353c7570492SJustin Hibbits 	/*
354c7570492SJustin Hibbits 	 * If there's no user context we still need to zero the stack.
355c7570492SJustin Hibbits 	 */
356c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
357c7570492SJustin Hibbits 		goto zero;
358c7570492SJustin Hibbits 
359c7570492SJustin Hibbits 	*pcstack++ = (uint64_t)p->p_pid;
360c7570492SJustin Hibbits 	pcstack_limit--;
361c7570492SJustin Hibbits 
362c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
363c7570492SJustin Hibbits 		return;
364c7570492SJustin Hibbits 
365c7570492SJustin Hibbits 	pc = tf->srr0;
366c7570492SJustin Hibbits 	sp = tf->fixreg[1];
367c7570492SJustin Hibbits 
368c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */
369c7570492SJustin Hibbits 	oldcontext = lwp->lwp_oldcontext;
370c7570492SJustin Hibbits 	s1 = sizeof (struct xframe) + 2 * sizeof (long);
371c7570492SJustin Hibbits 	s2 = s1 + sizeof (siginfo_t);
372c7570492SJustin Hibbits #endif
373c7570492SJustin Hibbits 
374c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
375c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
376c7570492SJustin Hibbits 		*fpstack++ = 0;
377c7570492SJustin Hibbits 		pcstack_limit--;
378c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
379c7570492SJustin Hibbits 			return;
380c7570492SJustin Hibbits 
381c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
382c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *)sp);
383c7570492SJustin Hibbits 		}
384c7570492SJustin Hibbits 		else {
385c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *)sp);
386c7570492SJustin Hibbits 		}
387c7570492SJustin Hibbits 	}
388c7570492SJustin Hibbits 
389c7570492SJustin Hibbits 	while (pc != 0) {
390c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
391c7570492SJustin Hibbits 		*fpstack++ = sp;
392c7570492SJustin Hibbits 		pcstack_limit--;
393c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
394c7570492SJustin Hibbits 			break;
395c7570492SJustin Hibbits 
396c7570492SJustin Hibbits 		if (sp == 0)
397c7570492SJustin Hibbits 			break;
398c7570492SJustin Hibbits 
399c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */
400c7570492SJustin Hibbits 		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
401c7570492SJustin Hibbits 			ucontext_t *ucp = (ucontext_t *)oldcontext;
402c7570492SJustin Hibbits 			greg_t *gregs = ucp->uc_mcontext.gregs;
403c7570492SJustin Hibbits 
404c7570492SJustin Hibbits 			sp = dtrace_fulword(&gregs[REG_FP]);
405c7570492SJustin Hibbits 			pc = dtrace_fulword(&gregs[REG_PC]);
406c7570492SJustin Hibbits 
407c7570492SJustin Hibbits 			oldcontext = dtrace_fulword(&ucp->uc_link);
408c7570492SJustin Hibbits 		} else
409c7570492SJustin Hibbits #endif /* XXX */
410c7570492SJustin Hibbits 		{
411c7570492SJustin Hibbits 			if (SV_PROC_FLAG(p, SV_ILP32)) {
412c7570492SJustin Hibbits 				pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
413c7570492SJustin Hibbits 				sp = dtrace_fuword32((void *)sp);
414c7570492SJustin Hibbits 			}
415c7570492SJustin Hibbits 			else {
416c7570492SJustin Hibbits 				pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
417c7570492SJustin Hibbits 				sp = dtrace_fuword64((void *)sp);
418c7570492SJustin Hibbits 			}
419c7570492SJustin Hibbits 		}
420c7570492SJustin Hibbits 
421c7570492SJustin Hibbits 		/*
422c7570492SJustin Hibbits 		 * This is totally bogus:  if we faulted, we're going to clear
423c7570492SJustin Hibbits 		 * the fault and break.  This is to deal with the apparently
424c7570492SJustin Hibbits 		 * broken Java stacks on x86.
425c7570492SJustin Hibbits 		 */
426c7570492SJustin Hibbits 		if (*flags & CPU_DTRACE_FAULT) {
427c7570492SJustin Hibbits 			*flags &= ~CPU_DTRACE_FAULT;
428c7570492SJustin Hibbits 			break;
429c7570492SJustin Hibbits 		}
430c7570492SJustin Hibbits 	}
431c7570492SJustin Hibbits 
432c7570492SJustin Hibbits zero:
433c7570492SJustin Hibbits 	while (pcstack_limit-- > 0)
434c7570492SJustin Hibbits 		*pcstack++ = 0;
435c7570492SJustin Hibbits }
436c7570492SJustin Hibbits 
437c7570492SJustin Hibbits /*ARGSUSED*/
438c7570492SJustin Hibbits uint64_t
439c7570492SJustin Hibbits dtrace_getarg(int arg, int aframes)
440c7570492SJustin Hibbits {
441f0bd82a1SJustin Hibbits 	uintptr_t val;
442f0bd82a1SJustin Hibbits 	uintptr_t *fp = (uintptr_t *)dtrace_getfp();
443f0bd82a1SJustin Hibbits 	uintptr_t *stack;
444f0bd82a1SJustin Hibbits 	int i;
445f0bd82a1SJustin Hibbits 
446f0bd82a1SJustin Hibbits 	/*
447f0bd82a1SJustin Hibbits 	 * A total of 8 arguments are passed via registers; any argument with
448f0bd82a1SJustin Hibbits 	 * index of 7 or lower is therefore in a register.
449f0bd82a1SJustin Hibbits 	 */
450f0bd82a1SJustin Hibbits 	int inreg = 7;
451f0bd82a1SJustin Hibbits 
452f0bd82a1SJustin Hibbits 	for (i = 1; i <= aframes; i++) {
453f0bd82a1SJustin Hibbits 		fp = (uintptr_t *)*fp;
454f0bd82a1SJustin Hibbits 
455f0bd82a1SJustin Hibbits 		/*
456f0bd82a1SJustin Hibbits 		 * On ppc32 AIM, and booke, trapexit() is the immediately following
457f0bd82a1SJustin Hibbits 		 * label.  On ppc64 AIM trapexit() follows a nop.
458f0bd82a1SJustin Hibbits 		 */
459e40a5cd3SJustin Hibbits #ifdef __powerpc64__
460e40a5cd3SJustin Hibbits 		if ((long)(fp[2]) + 4 == (long)trapexit) {
461e40a5cd3SJustin Hibbits #else
462e40a5cd3SJustin Hibbits 		if ((long)(fp[1]) == (long)trapexit) {
463e40a5cd3SJustin Hibbits #endif
464f0bd82a1SJustin Hibbits 			/*
465f0bd82a1SJustin Hibbits 			 * In the case of powerpc, we will use the pointer to the regs
466f0bd82a1SJustin Hibbits 			 * structure that was pushed when we took the trap.  To get this
467f0bd82a1SJustin Hibbits 			 * structure, we must increment beyond the frame structure.  If the
468f0bd82a1SJustin Hibbits 			 * argument that we're seeking is passed on the stack, we'll pull
469f0bd82a1SJustin Hibbits 			 * the true stack pointer out of the saved registers and decrement
470f0bd82a1SJustin Hibbits 			 * our argument by the number of arguments passed in registers; if
471f0bd82a1SJustin Hibbits 			 * the argument we're seeking is passed in regsiters, we can just
472f0bd82a1SJustin Hibbits 			 * load it directly.
473f0bd82a1SJustin Hibbits 			 */
474f0bd82a1SJustin Hibbits #ifdef __powerpc64__
475f0bd82a1SJustin Hibbits 			struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48);
476f0bd82a1SJustin Hibbits #else
477f0bd82a1SJustin Hibbits 			struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8);
478f0bd82a1SJustin Hibbits #endif
479f0bd82a1SJustin Hibbits 
480f0bd82a1SJustin Hibbits 			if (arg <= inreg) {
481f0bd82a1SJustin Hibbits 				stack = &rp->fixreg[3];
482f0bd82a1SJustin Hibbits 			} else {
483f0bd82a1SJustin Hibbits 				stack = (uintptr_t *)(rp->fixreg[1]);
484f0bd82a1SJustin Hibbits 				arg -= inreg;
485f0bd82a1SJustin Hibbits 			}
486f0bd82a1SJustin Hibbits 			goto load;
487f0bd82a1SJustin Hibbits 		}
488f0bd82a1SJustin Hibbits 
489f0bd82a1SJustin Hibbits 	}
490f0bd82a1SJustin Hibbits 
491f0bd82a1SJustin Hibbits 	/*
492f0bd82a1SJustin Hibbits 	 * We know that we did not come through a trap to get into
493f0bd82a1SJustin Hibbits 	 * dtrace_probe() -- the provider simply called dtrace_probe()
494f0bd82a1SJustin Hibbits 	 * directly.  As this is the case, we need to shift the argument
495f0bd82a1SJustin Hibbits 	 * that we're looking for:  the probe ID is the first argument to
496f0bd82a1SJustin Hibbits 	 * dtrace_probe(), so the argument n will actually be found where
497f0bd82a1SJustin Hibbits 	 * one would expect to find argument (n + 1).
498f0bd82a1SJustin Hibbits 	 */
499f0bd82a1SJustin Hibbits 	arg++;
500f0bd82a1SJustin Hibbits 
501f0bd82a1SJustin Hibbits 	if (arg <= inreg) {
502f0bd82a1SJustin Hibbits 		/*
503f0bd82a1SJustin Hibbits 		 * This shouldn't happen.  If the argument is passed in a
504f0bd82a1SJustin Hibbits 		 * register then it should have been, well, passed in a
505f0bd82a1SJustin Hibbits 		 * register...
506f0bd82a1SJustin Hibbits 		 */
507f0bd82a1SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
508c7570492SJustin Hibbits 		return (0);
509c7570492SJustin Hibbits 	}
510c7570492SJustin Hibbits 
511f0bd82a1SJustin Hibbits 	arg -= (inreg + 1);
512f0bd82a1SJustin Hibbits 	stack = fp + 2;
513c7570492SJustin Hibbits 
514f0bd82a1SJustin Hibbits load:
515f0bd82a1SJustin Hibbits 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
516f0bd82a1SJustin Hibbits 	val = stack[arg];
517f0bd82a1SJustin Hibbits 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
518c7570492SJustin Hibbits 
519f0bd82a1SJustin Hibbits 	return (val);
520c7570492SJustin Hibbits }
521c7570492SJustin Hibbits 
522c7570492SJustin Hibbits int
523c7570492SJustin Hibbits dtrace_getstackdepth(int aframes)
524c7570492SJustin Hibbits {
525c7570492SJustin Hibbits 	int depth = 0;
526e40a5cd3SJustin Hibbits 	uintptr_t osp, sp;
527e40a5cd3SJustin Hibbits 	vm_offset_t callpc;
528c7570492SJustin Hibbits 
529e40a5cd3SJustin Hibbits 	osp = PAGE_SIZE;
530c7570492SJustin Hibbits 	aframes++;
531c7570492SJustin Hibbits 	sp = dtrace_getfp();
532c7570492SJustin Hibbits 	depth++;
533c7570492SJustin Hibbits 	for(;;) {
534e40a5cd3SJustin Hibbits 		if (sp <= osp)
535c7570492SJustin Hibbits 			break;
536e40a5cd3SJustin Hibbits 
537*675cad71SJustin Hibbits 		if (!dtrace_sp_inkernel(sp))
538c7570492SJustin Hibbits 			break;
539e40a5cd3SJustin Hibbits 
540e40a5cd3SJustin Hibbits 		if (aframes == 0)
541c7570492SJustin Hibbits 			depth++;
542e40a5cd3SJustin Hibbits 		else
543e40a5cd3SJustin Hibbits 			aframes--;
544e40a5cd3SJustin Hibbits 		osp = sp;
545161c4151SJustin Hibbits 		sp = dtrace_next_sp(sp);
546c7570492SJustin Hibbits 	}
547c7570492SJustin Hibbits 	if (depth < aframes)
548e40a5cd3SJustin Hibbits 		return (0);
549e40a5cd3SJustin Hibbits 
550e40a5cd3SJustin Hibbits 	return (depth);
551c7570492SJustin Hibbits }
552c7570492SJustin Hibbits 
553c7570492SJustin Hibbits ulong_t
554c7570492SJustin Hibbits dtrace_getreg(struct trapframe *rp, uint_t reg)
555c7570492SJustin Hibbits {
556c7570492SJustin Hibbits 	if (reg < 32)
557c7570492SJustin Hibbits 		return (rp->fixreg[reg]);
558c7570492SJustin Hibbits 
559c7570492SJustin Hibbits 	switch (reg) {
560c7570492SJustin Hibbits 	case 33:
561c7570492SJustin Hibbits 		return (rp->lr);
562c7570492SJustin Hibbits 	case 34:
563c7570492SJustin Hibbits 		return (rp->cr);
564c7570492SJustin Hibbits 	case 35:
565c7570492SJustin Hibbits 		return (rp->xer);
566c7570492SJustin Hibbits 	case 36:
567c7570492SJustin Hibbits 		return (rp->ctr);
568c7570492SJustin Hibbits 	case 37:
569c7570492SJustin Hibbits 		return (rp->srr0);
570c7570492SJustin Hibbits 	case 38:
571c7570492SJustin Hibbits 		return (rp->srr1);
572c7570492SJustin Hibbits 	case 39:
573c7570492SJustin Hibbits 		return (rp->exc);
574c7570492SJustin Hibbits 	default:
575c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
576c7570492SJustin Hibbits 		return (0);
577c7570492SJustin Hibbits 	}
578c7570492SJustin Hibbits }
579c7570492SJustin Hibbits 
580c7570492SJustin Hibbits static int
581c7570492SJustin Hibbits dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
582c7570492SJustin Hibbits {
583c7570492SJustin Hibbits 	ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
584c7570492SJustin Hibbits 
585c7570492SJustin Hibbits 	if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
586c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
587c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
588c7570492SJustin Hibbits 		return (0);
589c7570492SJustin Hibbits 	}
590c7570492SJustin Hibbits 
591c7570492SJustin Hibbits 	return (1);
592c7570492SJustin Hibbits }
593c7570492SJustin Hibbits 
594c7570492SJustin Hibbits void
595c7570492SJustin Hibbits dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
596c7570492SJustin Hibbits     volatile uint16_t *flags)
597c7570492SJustin Hibbits {
598c7570492SJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size))
5997e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)kaddr, size)) {
6007e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
6017e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
6027e7a9efdSJustin Hibbits 		}
603c7570492SJustin Hibbits }
604c7570492SJustin Hibbits 
605c7570492SJustin Hibbits void
606c7570492SJustin Hibbits dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
607c7570492SJustin Hibbits     volatile uint16_t *flags)
608c7570492SJustin Hibbits {
6097e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
6107e7a9efdSJustin Hibbits 		if (copyout((const void *)kaddr, (void *)uaddr, size)) {
6117e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
6127e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
6137e7a9efdSJustin Hibbits 		}
6147e7a9efdSJustin Hibbits 	}
615c7570492SJustin Hibbits }
616c7570492SJustin Hibbits 
617c7570492SJustin Hibbits void
618c7570492SJustin Hibbits dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
619c7570492SJustin Hibbits     volatile uint16_t *flags)
620c7570492SJustin Hibbits {
6217e7a9efdSJustin Hibbits 	size_t actual;
6227e7a9efdSJustin Hibbits 	int    error;
6237e7a9efdSJustin Hibbits 
6247e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
6257e7a9efdSJustin Hibbits 		error = copyinstr((const void *)uaddr, (void *)kaddr,
6267e7a9efdSJustin Hibbits 		    size, &actual);
6277e7a9efdSJustin Hibbits 
6287e7a9efdSJustin Hibbits 		/* ENAMETOOLONG is not a fault condition. */
6297e7a9efdSJustin Hibbits 		if (error && error != ENAMETOOLONG) {
6307e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
6317e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
6327e7a9efdSJustin Hibbits 		}
6337e7a9efdSJustin Hibbits 	}
634c7570492SJustin Hibbits }
635c7570492SJustin Hibbits 
6367e7a9efdSJustin Hibbits /*
6377e7a9efdSJustin Hibbits  * The bulk of this function could be replaced to match dtrace_copyinstr()
6387e7a9efdSJustin Hibbits  * if we ever implement a copyoutstr().
6397e7a9efdSJustin Hibbits  */
640c7570492SJustin Hibbits void
641c7570492SJustin Hibbits dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
642c7570492SJustin Hibbits     volatile uint16_t *flags)
643c7570492SJustin Hibbits {
6447e7a9efdSJustin Hibbits 	size_t len;
6457e7a9efdSJustin Hibbits 
6467e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
6477e7a9efdSJustin Hibbits 		len = strlen((const char *)kaddr);
6487e7a9efdSJustin Hibbits 		if (len > size)
6497e7a9efdSJustin Hibbits 			len = size;
6507e7a9efdSJustin Hibbits 
6517e7a9efdSJustin Hibbits 		if (copyout((const void *)kaddr, (void *)uaddr, len)) {
6527e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
6537e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
6547e7a9efdSJustin Hibbits 		}
6557e7a9efdSJustin Hibbits 	}
656c7570492SJustin Hibbits }
657c7570492SJustin Hibbits 
658c7570492SJustin Hibbits uint8_t
659c7570492SJustin Hibbits dtrace_fuword8(void *uaddr)
660c7570492SJustin Hibbits {
661c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
662c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
663c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
664c7570492SJustin Hibbits 		return (0);
665c7570492SJustin Hibbits 	}
6667e7a9efdSJustin Hibbits 	return (fubyte(uaddr));
667c7570492SJustin Hibbits }
668c7570492SJustin Hibbits 
669c7570492SJustin Hibbits uint16_t
670c7570492SJustin Hibbits dtrace_fuword16(void *uaddr)
671c7570492SJustin Hibbits {
6727e7a9efdSJustin Hibbits 	uint16_t ret = 0;
6737e7a9efdSJustin Hibbits 
6747e7a9efdSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
6757e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
676c7570492SJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
677c7570492SJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
678c7570492SJustin Hibbits 		}
6797e7a9efdSJustin Hibbits 	}
6807e7a9efdSJustin Hibbits 	return ret;
681c7570492SJustin Hibbits }
682c7570492SJustin Hibbits 
683c7570492SJustin Hibbits uint32_t
684c7570492SJustin Hibbits dtrace_fuword32(void *uaddr)
685c7570492SJustin Hibbits {
686c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
687c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
688c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
689c7570492SJustin Hibbits 		return (0);
690c7570492SJustin Hibbits 	}
6917e7a9efdSJustin Hibbits 	return (fuword32(uaddr));
692c7570492SJustin Hibbits }
693c7570492SJustin Hibbits 
694c7570492SJustin Hibbits uint64_t
695c7570492SJustin Hibbits dtrace_fuword64(void *uaddr)
696c7570492SJustin Hibbits {
6977e7a9efdSJustin Hibbits 	uint64_t ret = 0;
6987e7a9efdSJustin Hibbits 
6997e7a9efdSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
7007e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
701c7570492SJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
702c7570492SJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
703c7570492SJustin Hibbits 		}
7047e7a9efdSJustin Hibbits 	}
7057e7a9efdSJustin Hibbits 	return ret;
706c7570492SJustin Hibbits }
70780a5635cSJustin Hibbits 
70880a5635cSJustin Hibbits uintptr_t
70980a5635cSJustin Hibbits dtrace_fulword(void *uaddr)
71080a5635cSJustin Hibbits {
71180a5635cSJustin Hibbits 	uintptr_t ret = 0;
71280a5635cSJustin Hibbits 
71380a5635cSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
71480a5635cSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
71580a5635cSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
71680a5635cSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
71780a5635cSJustin Hibbits 		}
71880a5635cSJustin Hibbits 	}
71980a5635cSJustin Hibbits 	return ret;
72080a5635cSJustin Hibbits }
721