xref: /freebsd/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c (revision e9aae3496e9cb06ce6fb9be571097053d530278e)
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>
41675cad71SJustin 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 */
58675cad71SJustin Hibbits #define	FRAME_OFFSET	48
59e40a5cd3SJustin Hibbits #else
60e40a5cd3SJustin Hibbits #define OFFSET 0
61675cad71SJustin 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
68675cad71SJustin Hibbits dtrace_sp_inkernel(uintptr_t sp)
69e40a5cd3SJustin Hibbits {
70675cad71SJustin 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 	 */
85675cad71SJustin Hibbits 	if (callpc + OFFSET == (vm_offset_t) &trapexit ||
86675cad71SJustin Hibbits 	    callpc + OFFSET == (vm_offset_t) &asttrapexit) {
87675cad71SJustin Hibbits 		if (sp == 0)
88e40a5cd3SJustin Hibbits 			return (0);
89675cad71SJustin Hibbits 		frame = (struct trapframe *)(sp + FRAME_OFFSET);
90675cad71SJustin Hibbits 
91675cad71SJustin Hibbits 		return ((frame->srr1 & PSL_PR) == 0);
92675cad71SJustin Hibbits 	}
93e40a5cd3SJustin Hibbits 
94e40a5cd3SJustin Hibbits 	return (1);
95e40a5cd3SJustin Hibbits }
96e40a5cd3SJustin Hibbits 
97*e9aae349SJustin Hibbits static __inline void
98*e9aae349SJustin Hibbits dtrace_next_sp_pc(uintptr_t sp, uintptr_t *nsp, uintptr_t *pc)
99e40a5cd3SJustin Hibbits {
100e40a5cd3SJustin Hibbits 	vm_offset_t callpc;
101675cad71SJustin 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 ||
114675cad71SJustin Hibbits 	    callpc + OFFSET == (vm_offset_t) &asttrapexit)) {
115e40a5cd3SJustin Hibbits 		/* Access the trap frame */
116675cad71SJustin Hibbits 		frame = (struct trapframe *)(sp + FRAME_OFFSET);
117*e9aae349SJustin Hibbits 
118*e9aae349SJustin Hibbits 		if (nsp != NULL)
119*e9aae349SJustin Hibbits 			*nsp = frame->fixreg[1];
120*e9aae349SJustin Hibbits 		if (pc != NULL)
121*e9aae349SJustin Hibbits 			*pc = frame->srr0;
122675cad71SJustin Hibbits 	}
123e40a5cd3SJustin Hibbits 
124*e9aae349SJustin Hibbits 	if (nsp != NULL)
125*e9aae349SJustin Hibbits 		*nsp = *(uintptr_t *)sp;
126*e9aae349SJustin Hibbits 	if (pc != NULL)
127*e9aae349SJustin Hibbits 		*pc = callpc;
128e40a5cd3SJustin Hibbits }
129e40a5cd3SJustin Hibbits 
130c7570492SJustin Hibbits greg_t
131c7570492SJustin Hibbits dtrace_getfp(void)
132c7570492SJustin Hibbits {
133c7570492SJustin Hibbits 	return (greg_t)__builtin_frame_address(0);
134c7570492SJustin Hibbits }
135c7570492SJustin Hibbits 
136c7570492SJustin Hibbits void
137c7570492SJustin Hibbits dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
138c7570492SJustin Hibbits     uint32_t *intrpc)
139c7570492SJustin Hibbits {
140c7570492SJustin Hibbits 	int depth = 0;
141e40a5cd3SJustin Hibbits 	uintptr_t osp, sp;
142c7570492SJustin Hibbits 	vm_offset_t callpc;
143c7570492SJustin Hibbits 	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
144c7570492SJustin Hibbits 
145e40a5cd3SJustin Hibbits 	osp = PAGE_SIZE;
146c7570492SJustin Hibbits 	if (intrpc != 0)
147c7570492SJustin Hibbits 		pcstack[depth++] = (pc_t) intrpc;
148c7570492SJustin Hibbits 
149c7570492SJustin Hibbits 	aframes++;
150c7570492SJustin Hibbits 
151c7570492SJustin Hibbits 	sp = dtrace_getfp();
152c7570492SJustin Hibbits 
153c7570492SJustin Hibbits 	while (depth < pcstack_limit) {
154e40a5cd3SJustin Hibbits 		if (sp <= osp)
155c7570492SJustin Hibbits 			break;
156c7570492SJustin Hibbits 
157675cad71SJustin Hibbits 		if (!dtrace_sp_inkernel(sp))
158c7570492SJustin Hibbits 			break;
159*e9aae349SJustin Hibbits 		osp = sp;
160*e9aae349SJustin Hibbits 		dtrace_next_sp_pc(osp, &sp, &callpc);
161c7570492SJustin Hibbits 
162c7570492SJustin Hibbits 		if (aframes > 0) {
163c7570492SJustin Hibbits 			aframes--;
164c7570492SJustin Hibbits 			if ((aframes == 0) && (caller != 0)) {
165c7570492SJustin Hibbits 				pcstack[depth++] = caller;
166c7570492SJustin Hibbits 			}
167c7570492SJustin Hibbits 		}
168c7570492SJustin Hibbits 		else {
169c7570492SJustin Hibbits 			pcstack[depth++] = callpc;
170c7570492SJustin Hibbits 		}
171c7570492SJustin Hibbits 	}
172c7570492SJustin Hibbits 
173c7570492SJustin Hibbits 	for (; depth < pcstack_limit; depth++) {
174c7570492SJustin Hibbits 		pcstack[depth] = 0;
175c7570492SJustin Hibbits 	}
176c7570492SJustin Hibbits }
177c7570492SJustin Hibbits 
178c7570492SJustin Hibbits static int
179c7570492SJustin Hibbits dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
180c7570492SJustin Hibbits     uintptr_t sp)
181c7570492SJustin Hibbits {
182c7570492SJustin Hibbits 	proc_t *p = curproc;
183c7570492SJustin Hibbits 	int ret = 0;
184c7570492SJustin Hibbits 
185c7570492SJustin Hibbits 	ASSERT(pcstack == NULL || pcstack_limit > 0);
186c7570492SJustin Hibbits 
187c7570492SJustin Hibbits 	while (pc != 0) {
188c7570492SJustin Hibbits 		ret++;
189c7570492SJustin Hibbits 		if (pcstack != NULL) {
190c7570492SJustin Hibbits 			*pcstack++ = (uint64_t)pc;
191c7570492SJustin Hibbits 			pcstack_limit--;
192c7570492SJustin Hibbits 			if (pcstack_limit <= 0)
193c7570492SJustin Hibbits 				break;
194c7570492SJustin Hibbits 		}
195c7570492SJustin Hibbits 
196c7570492SJustin Hibbits 		if (sp == 0)
197c7570492SJustin Hibbits 			break;
198c7570492SJustin Hibbits 
199c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
200c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
201c7570492SJustin Hibbits 			sp = dtrace_fuword32((void *)sp);
202c7570492SJustin Hibbits 		}
203c7570492SJustin Hibbits 		else {
204c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
205c7570492SJustin Hibbits 			sp = dtrace_fuword64((void *)sp);
206c7570492SJustin Hibbits 		}
207c7570492SJustin Hibbits 	}
208c7570492SJustin Hibbits 
209c7570492SJustin Hibbits 	return (ret);
210c7570492SJustin Hibbits }
211c7570492SJustin Hibbits 
212c7570492SJustin Hibbits void
213c7570492SJustin Hibbits dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
214c7570492SJustin Hibbits {
215c7570492SJustin Hibbits 	proc_t *p = curproc;
216c7570492SJustin Hibbits 	struct trapframe *tf;
217c7570492SJustin Hibbits 	uintptr_t pc, sp;
218c7570492SJustin Hibbits 	volatile uint16_t *flags =
219c7570492SJustin Hibbits 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
220c7570492SJustin Hibbits 	int n;
221c7570492SJustin Hibbits 
222c7570492SJustin Hibbits 	if (*flags & CPU_DTRACE_FAULT)
223c7570492SJustin Hibbits 		return;
224c7570492SJustin Hibbits 
225c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
226c7570492SJustin Hibbits 		return;
227c7570492SJustin Hibbits 
228c7570492SJustin Hibbits 	/*
229c7570492SJustin Hibbits 	 * If there's no user context we still need to zero the stack.
230c7570492SJustin Hibbits 	 */
231c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
232c7570492SJustin Hibbits 		goto zero;
233c7570492SJustin Hibbits 
234c7570492SJustin Hibbits 	*pcstack++ = (uint64_t)p->p_pid;
235c7570492SJustin Hibbits 	pcstack_limit--;
236c7570492SJustin Hibbits 
237c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
238c7570492SJustin Hibbits 		return;
239c7570492SJustin Hibbits 
240c7570492SJustin Hibbits 	pc = tf->srr0;
241c7570492SJustin Hibbits 	sp = tf->fixreg[1];
242c7570492SJustin Hibbits 
243c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
244c7570492SJustin Hibbits 		/*
245c7570492SJustin Hibbits 		 * In an entry probe.  The frame pointer has not yet been
246c7570492SJustin Hibbits 		 * pushed (that happens in the function prologue).  The
247c7570492SJustin Hibbits 		 * best approach is to add the current pc as a missing top
248c7570492SJustin Hibbits 		 * of stack and back the pc up to the caller, which is stored
249c7570492SJustin Hibbits 		 * at the current stack pointer address since the call
250c7570492SJustin Hibbits 		 * instruction puts it there right before the branch.
251c7570492SJustin Hibbits 		 */
252c7570492SJustin Hibbits 
253c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
254c7570492SJustin Hibbits 		pcstack_limit--;
255c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
256c7570492SJustin Hibbits 			return;
257c7570492SJustin Hibbits 
258c7570492SJustin Hibbits 		pc = tf->lr;
259c7570492SJustin Hibbits 	}
260c7570492SJustin Hibbits 
261c7570492SJustin Hibbits 	n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
262c7570492SJustin Hibbits 	ASSERT(n >= 0);
263c7570492SJustin Hibbits 	ASSERT(n <= pcstack_limit);
264c7570492SJustin Hibbits 
265c7570492SJustin Hibbits 	pcstack += n;
266c7570492SJustin Hibbits 	pcstack_limit -= n;
267c7570492SJustin Hibbits 
268c7570492SJustin Hibbits zero:
269c7570492SJustin Hibbits 	while (pcstack_limit-- > 0)
270c7570492SJustin Hibbits 		*pcstack++ = 0;
271c7570492SJustin Hibbits }
272c7570492SJustin Hibbits 
273c7570492SJustin Hibbits int
274c7570492SJustin Hibbits dtrace_getustackdepth(void)
275c7570492SJustin Hibbits {
276c7570492SJustin Hibbits 	proc_t *p = curproc;
277c7570492SJustin Hibbits 	struct trapframe *tf;
278c7570492SJustin Hibbits 	uintptr_t pc, sp;
279c7570492SJustin Hibbits 	int n = 0;
280c7570492SJustin Hibbits 
281c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
282c7570492SJustin Hibbits 		return (0);
283c7570492SJustin Hibbits 
284c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
285c7570492SJustin Hibbits 		return (-1);
286c7570492SJustin Hibbits 
287c7570492SJustin Hibbits 	pc = tf->srr0;
288c7570492SJustin Hibbits 	sp = tf->fixreg[1];
289c7570492SJustin Hibbits 
290c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
291c7570492SJustin Hibbits 		/*
292c7570492SJustin Hibbits 		 * In an entry probe.  The frame pointer has not yet been
293c7570492SJustin Hibbits 		 * pushed (that happens in the function prologue).  The
294c7570492SJustin Hibbits 		 * best approach is to add the current pc as a missing top
295c7570492SJustin Hibbits 		 * of stack and back the pc up to the caller, which is stored
296c7570492SJustin Hibbits 		 * at the current stack pointer address since the call
297c7570492SJustin Hibbits 		 * instruction puts it there right before the branch.
298c7570492SJustin Hibbits 		 */
299c7570492SJustin Hibbits 
300c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
301c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *) sp);
302c7570492SJustin Hibbits 		}
303c7570492SJustin Hibbits 		else
304c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *) sp);
305c7570492SJustin Hibbits 		n++;
306c7570492SJustin Hibbits 	}
307c7570492SJustin Hibbits 
308c7570492SJustin Hibbits 	n += dtrace_getustack_common(NULL, 0, pc, sp);
309c7570492SJustin Hibbits 
310c7570492SJustin Hibbits 	return (n);
311c7570492SJustin Hibbits }
312c7570492SJustin Hibbits 
313c7570492SJustin Hibbits void
314c7570492SJustin Hibbits dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
315c7570492SJustin Hibbits {
316c7570492SJustin Hibbits 	proc_t *p = curproc;
317c7570492SJustin Hibbits 	struct trapframe *tf;
318c7570492SJustin Hibbits 	uintptr_t pc, sp;
319c7570492SJustin Hibbits 	volatile uint16_t *flags =
320c7570492SJustin Hibbits 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
321c7570492SJustin Hibbits #ifdef notyet	/* XXX signal stack */
322c7570492SJustin Hibbits 	uintptr_t oldcontext;
323c7570492SJustin Hibbits 	size_t s1, s2;
324c7570492SJustin Hibbits #endif
325c7570492SJustin Hibbits 
326c7570492SJustin Hibbits 	if (*flags & CPU_DTRACE_FAULT)
327c7570492SJustin Hibbits 		return;
328c7570492SJustin Hibbits 
329c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
330c7570492SJustin Hibbits 		return;
331c7570492SJustin Hibbits 
332c7570492SJustin Hibbits 	/*
333c7570492SJustin Hibbits 	 * If there's no user context we still need to zero the stack.
334c7570492SJustin Hibbits 	 */
335c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
336c7570492SJustin Hibbits 		goto zero;
337c7570492SJustin Hibbits 
338c7570492SJustin Hibbits 	*pcstack++ = (uint64_t)p->p_pid;
339c7570492SJustin Hibbits 	pcstack_limit--;
340c7570492SJustin Hibbits 
341c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
342c7570492SJustin Hibbits 		return;
343c7570492SJustin Hibbits 
344c7570492SJustin Hibbits 	pc = tf->srr0;
345c7570492SJustin Hibbits 	sp = tf->fixreg[1];
346c7570492SJustin Hibbits 
347c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */
348c7570492SJustin Hibbits 	oldcontext = lwp->lwp_oldcontext;
349c7570492SJustin Hibbits 	s1 = sizeof (struct xframe) + 2 * sizeof (long);
350c7570492SJustin Hibbits 	s2 = s1 + sizeof (siginfo_t);
351c7570492SJustin Hibbits #endif
352c7570492SJustin Hibbits 
353c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
354c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
355c7570492SJustin Hibbits 		*fpstack++ = 0;
356c7570492SJustin Hibbits 		pcstack_limit--;
357c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
358c7570492SJustin Hibbits 			return;
359c7570492SJustin Hibbits 
360c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
361c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *)sp);
362c7570492SJustin Hibbits 		}
363c7570492SJustin Hibbits 		else {
364c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *)sp);
365c7570492SJustin Hibbits 		}
366c7570492SJustin Hibbits 	}
367c7570492SJustin Hibbits 
368c7570492SJustin Hibbits 	while (pc != 0) {
369c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
370c7570492SJustin Hibbits 		*fpstack++ = sp;
371c7570492SJustin Hibbits 		pcstack_limit--;
372c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
373c7570492SJustin Hibbits 			break;
374c7570492SJustin Hibbits 
375c7570492SJustin Hibbits 		if (sp == 0)
376c7570492SJustin Hibbits 			break;
377c7570492SJustin Hibbits 
378c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */
379c7570492SJustin Hibbits 		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
380c7570492SJustin Hibbits 			ucontext_t *ucp = (ucontext_t *)oldcontext;
381c7570492SJustin Hibbits 			greg_t *gregs = ucp->uc_mcontext.gregs;
382c7570492SJustin Hibbits 
383c7570492SJustin Hibbits 			sp = dtrace_fulword(&gregs[REG_FP]);
384c7570492SJustin Hibbits 			pc = dtrace_fulword(&gregs[REG_PC]);
385c7570492SJustin Hibbits 
386c7570492SJustin Hibbits 			oldcontext = dtrace_fulword(&ucp->uc_link);
387c7570492SJustin Hibbits 		} else
388c7570492SJustin Hibbits #endif /* XXX */
389c7570492SJustin Hibbits 		{
390c7570492SJustin Hibbits 			if (SV_PROC_FLAG(p, SV_ILP32)) {
391c7570492SJustin Hibbits 				pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
392c7570492SJustin Hibbits 				sp = dtrace_fuword32((void *)sp);
393c7570492SJustin Hibbits 			}
394c7570492SJustin Hibbits 			else {
395c7570492SJustin Hibbits 				pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
396c7570492SJustin Hibbits 				sp = dtrace_fuword64((void *)sp);
397c7570492SJustin Hibbits 			}
398c7570492SJustin Hibbits 		}
399c7570492SJustin Hibbits 
400c7570492SJustin Hibbits 		/*
401c7570492SJustin Hibbits 		 * This is totally bogus:  if we faulted, we're going to clear
402c7570492SJustin Hibbits 		 * the fault and break.  This is to deal with the apparently
403c7570492SJustin Hibbits 		 * broken Java stacks on x86.
404c7570492SJustin Hibbits 		 */
405c7570492SJustin Hibbits 		if (*flags & CPU_DTRACE_FAULT) {
406c7570492SJustin Hibbits 			*flags &= ~CPU_DTRACE_FAULT;
407c7570492SJustin Hibbits 			break;
408c7570492SJustin Hibbits 		}
409c7570492SJustin Hibbits 	}
410c7570492SJustin Hibbits 
411c7570492SJustin Hibbits zero:
412c7570492SJustin Hibbits 	while (pcstack_limit-- > 0)
413c7570492SJustin Hibbits 		*pcstack++ = 0;
414c7570492SJustin Hibbits }
415c7570492SJustin Hibbits 
416c7570492SJustin Hibbits /*ARGSUSED*/
417c7570492SJustin Hibbits uint64_t
418c7570492SJustin Hibbits dtrace_getarg(int arg, int aframes)
419c7570492SJustin Hibbits {
420f0bd82a1SJustin Hibbits 	uintptr_t val;
421f0bd82a1SJustin Hibbits 	uintptr_t *fp = (uintptr_t *)dtrace_getfp();
422f0bd82a1SJustin Hibbits 	uintptr_t *stack;
423f0bd82a1SJustin Hibbits 	int i;
424f0bd82a1SJustin Hibbits 
425f0bd82a1SJustin Hibbits 	/*
426f0bd82a1SJustin Hibbits 	 * A total of 8 arguments are passed via registers; any argument with
427f0bd82a1SJustin Hibbits 	 * index of 7 or lower is therefore in a register.
428f0bd82a1SJustin Hibbits 	 */
429f0bd82a1SJustin Hibbits 	int inreg = 7;
430f0bd82a1SJustin Hibbits 
431f0bd82a1SJustin Hibbits 	for (i = 1; i <= aframes; i++) {
432f0bd82a1SJustin Hibbits 		fp = (uintptr_t *)*fp;
433f0bd82a1SJustin Hibbits 
434f0bd82a1SJustin Hibbits 		/*
435f0bd82a1SJustin Hibbits 		 * On ppc32 AIM, and booke, trapexit() is the immediately following
436f0bd82a1SJustin Hibbits 		 * label.  On ppc64 AIM trapexit() follows a nop.
437f0bd82a1SJustin Hibbits 		 */
438e40a5cd3SJustin Hibbits #ifdef __powerpc64__
439e40a5cd3SJustin Hibbits 		if ((long)(fp[2]) + 4 == (long)trapexit) {
440e40a5cd3SJustin Hibbits #else
441e40a5cd3SJustin Hibbits 		if ((long)(fp[1]) == (long)trapexit) {
442e40a5cd3SJustin Hibbits #endif
443f0bd82a1SJustin Hibbits 			/*
444f0bd82a1SJustin Hibbits 			 * In the case of powerpc, we will use the pointer to the regs
445f0bd82a1SJustin Hibbits 			 * structure that was pushed when we took the trap.  To get this
446f0bd82a1SJustin Hibbits 			 * structure, we must increment beyond the frame structure.  If the
447f0bd82a1SJustin Hibbits 			 * argument that we're seeking is passed on the stack, we'll pull
448f0bd82a1SJustin Hibbits 			 * the true stack pointer out of the saved registers and decrement
449f0bd82a1SJustin Hibbits 			 * our argument by the number of arguments passed in registers; if
450f0bd82a1SJustin Hibbits 			 * the argument we're seeking is passed in regsiters, we can just
451f0bd82a1SJustin Hibbits 			 * load it directly.
452f0bd82a1SJustin Hibbits 			 */
453f0bd82a1SJustin Hibbits #ifdef __powerpc64__
454f0bd82a1SJustin Hibbits 			struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48);
455f0bd82a1SJustin Hibbits #else
456f0bd82a1SJustin Hibbits 			struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8);
457f0bd82a1SJustin Hibbits #endif
458f0bd82a1SJustin Hibbits 
459f0bd82a1SJustin Hibbits 			if (arg <= inreg) {
460f0bd82a1SJustin Hibbits 				stack = &rp->fixreg[3];
461f0bd82a1SJustin Hibbits 			} else {
462f0bd82a1SJustin Hibbits 				stack = (uintptr_t *)(rp->fixreg[1]);
463f0bd82a1SJustin Hibbits 				arg -= inreg;
464f0bd82a1SJustin Hibbits 			}
465f0bd82a1SJustin Hibbits 			goto load;
466f0bd82a1SJustin Hibbits 		}
467f0bd82a1SJustin Hibbits 
468f0bd82a1SJustin Hibbits 	}
469f0bd82a1SJustin Hibbits 
470f0bd82a1SJustin Hibbits 	/*
471f0bd82a1SJustin Hibbits 	 * We know that we did not come through a trap to get into
472f0bd82a1SJustin Hibbits 	 * dtrace_probe() -- the provider simply called dtrace_probe()
473f0bd82a1SJustin Hibbits 	 * directly.  As this is the case, we need to shift the argument
474f0bd82a1SJustin Hibbits 	 * that we're looking for:  the probe ID is the first argument to
475f0bd82a1SJustin Hibbits 	 * dtrace_probe(), so the argument n will actually be found where
476f0bd82a1SJustin Hibbits 	 * one would expect to find argument (n + 1).
477f0bd82a1SJustin Hibbits 	 */
478f0bd82a1SJustin Hibbits 	arg++;
479f0bd82a1SJustin Hibbits 
480f0bd82a1SJustin Hibbits 	if (arg <= inreg) {
481f0bd82a1SJustin Hibbits 		/*
482f0bd82a1SJustin Hibbits 		 * This shouldn't happen.  If the argument is passed in a
483f0bd82a1SJustin Hibbits 		 * register then it should have been, well, passed in a
484f0bd82a1SJustin Hibbits 		 * register...
485f0bd82a1SJustin Hibbits 		 */
486f0bd82a1SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
487c7570492SJustin Hibbits 		return (0);
488c7570492SJustin Hibbits 	}
489c7570492SJustin Hibbits 
490f0bd82a1SJustin Hibbits 	arg -= (inreg + 1);
491f0bd82a1SJustin Hibbits 	stack = fp + 2;
492c7570492SJustin Hibbits 
493f0bd82a1SJustin Hibbits load:
494f0bd82a1SJustin Hibbits 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
495f0bd82a1SJustin Hibbits 	val = stack[arg];
496f0bd82a1SJustin Hibbits 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
497c7570492SJustin Hibbits 
498f0bd82a1SJustin Hibbits 	return (val);
499c7570492SJustin Hibbits }
500c7570492SJustin Hibbits 
501c7570492SJustin Hibbits int
502c7570492SJustin Hibbits dtrace_getstackdepth(int aframes)
503c7570492SJustin Hibbits {
504c7570492SJustin Hibbits 	int depth = 0;
505e40a5cd3SJustin Hibbits 	uintptr_t osp, sp;
506e40a5cd3SJustin Hibbits 	vm_offset_t callpc;
507c7570492SJustin Hibbits 
508e40a5cd3SJustin Hibbits 	osp = PAGE_SIZE;
509c7570492SJustin Hibbits 	aframes++;
510c7570492SJustin Hibbits 	sp = dtrace_getfp();
511c7570492SJustin Hibbits 	depth++;
512c7570492SJustin Hibbits 	for(;;) {
513e40a5cd3SJustin Hibbits 		if (sp <= osp)
514c7570492SJustin Hibbits 			break;
515e40a5cd3SJustin Hibbits 
516675cad71SJustin Hibbits 		if (!dtrace_sp_inkernel(sp))
517c7570492SJustin Hibbits 			break;
518e40a5cd3SJustin Hibbits 
519e40a5cd3SJustin Hibbits 		if (aframes == 0)
520c7570492SJustin Hibbits 			depth++;
521e40a5cd3SJustin Hibbits 		else
522e40a5cd3SJustin Hibbits 			aframes--;
523e40a5cd3SJustin Hibbits 		osp = sp;
524*e9aae349SJustin Hibbits 		dtrace_next_sp_pc(sp, &sp, NULL);
525c7570492SJustin Hibbits 	}
526c7570492SJustin Hibbits 	if (depth < aframes)
527e40a5cd3SJustin Hibbits 		return (0);
528e40a5cd3SJustin Hibbits 
529e40a5cd3SJustin Hibbits 	return (depth);
530c7570492SJustin Hibbits }
531c7570492SJustin Hibbits 
532c7570492SJustin Hibbits ulong_t
533c7570492SJustin Hibbits dtrace_getreg(struct trapframe *rp, uint_t reg)
534c7570492SJustin Hibbits {
535c7570492SJustin Hibbits 	if (reg < 32)
536c7570492SJustin Hibbits 		return (rp->fixreg[reg]);
537c7570492SJustin Hibbits 
538c7570492SJustin Hibbits 	switch (reg) {
5397f0df9acSJustin Hibbits 	case 32:
540c7570492SJustin Hibbits 		return (rp->lr);
5417f0df9acSJustin Hibbits 	case 33:
542c7570492SJustin Hibbits 		return (rp->cr);
5437f0df9acSJustin Hibbits 	case 34:
544c7570492SJustin Hibbits 		return (rp->xer);
5457f0df9acSJustin Hibbits 	case 35:
546c7570492SJustin Hibbits 		return (rp->ctr);
5477f0df9acSJustin Hibbits 	case 36:
548c7570492SJustin Hibbits 		return (rp->srr0);
5497f0df9acSJustin Hibbits 	case 37:
550c7570492SJustin Hibbits 		return (rp->srr1);
5517f0df9acSJustin Hibbits 	case 38:
552c7570492SJustin Hibbits 		return (rp->exc);
553c7570492SJustin Hibbits 	default:
554c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
555c7570492SJustin Hibbits 		return (0);
556c7570492SJustin Hibbits 	}
557c7570492SJustin Hibbits }
558c7570492SJustin Hibbits 
559c7570492SJustin Hibbits static int
560c7570492SJustin Hibbits dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
561c7570492SJustin Hibbits {
562c7570492SJustin Hibbits 	ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
563c7570492SJustin Hibbits 
564c7570492SJustin Hibbits 	if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
565c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
566c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
567c7570492SJustin Hibbits 		return (0);
568c7570492SJustin Hibbits 	}
569c7570492SJustin Hibbits 
570c7570492SJustin Hibbits 	return (1);
571c7570492SJustin Hibbits }
572c7570492SJustin Hibbits 
573c7570492SJustin Hibbits void
574c7570492SJustin Hibbits dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
575c7570492SJustin Hibbits     volatile uint16_t *flags)
576c7570492SJustin Hibbits {
577c7570492SJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size))
5787e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)kaddr, size)) {
5797e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
5807e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
5817e7a9efdSJustin Hibbits 		}
582c7570492SJustin Hibbits }
583c7570492SJustin Hibbits 
584c7570492SJustin Hibbits void
585c7570492SJustin Hibbits dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
586c7570492SJustin Hibbits     volatile uint16_t *flags)
587c7570492SJustin Hibbits {
5887e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
5897e7a9efdSJustin Hibbits 		if (copyout((const void *)kaddr, (void *)uaddr, size)) {
5907e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
5917e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
5927e7a9efdSJustin Hibbits 		}
5937e7a9efdSJustin Hibbits 	}
594c7570492SJustin Hibbits }
595c7570492SJustin Hibbits 
596c7570492SJustin Hibbits void
597c7570492SJustin Hibbits dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
598c7570492SJustin Hibbits     volatile uint16_t *flags)
599c7570492SJustin Hibbits {
6007e7a9efdSJustin Hibbits 	size_t actual;
6017e7a9efdSJustin Hibbits 	int    error;
6027e7a9efdSJustin Hibbits 
6037e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
6047e7a9efdSJustin Hibbits 		error = copyinstr((const void *)uaddr, (void *)kaddr,
6057e7a9efdSJustin Hibbits 		    size, &actual);
6067e7a9efdSJustin Hibbits 
6077e7a9efdSJustin Hibbits 		/* ENAMETOOLONG is not a fault condition. */
6087e7a9efdSJustin Hibbits 		if (error && error != ENAMETOOLONG) {
6097e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
6107e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
6117e7a9efdSJustin Hibbits 		}
6127e7a9efdSJustin Hibbits 	}
613c7570492SJustin Hibbits }
614c7570492SJustin Hibbits 
6157e7a9efdSJustin Hibbits /*
6167e7a9efdSJustin Hibbits  * The bulk of this function could be replaced to match dtrace_copyinstr()
6177e7a9efdSJustin Hibbits  * if we ever implement a copyoutstr().
6187e7a9efdSJustin Hibbits  */
619c7570492SJustin Hibbits void
620c7570492SJustin Hibbits dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
621c7570492SJustin Hibbits     volatile uint16_t *flags)
622c7570492SJustin Hibbits {
6237e7a9efdSJustin Hibbits 	size_t len;
6247e7a9efdSJustin Hibbits 
6257e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
6267e7a9efdSJustin Hibbits 		len = strlen((const char *)kaddr);
6277e7a9efdSJustin Hibbits 		if (len > size)
6287e7a9efdSJustin Hibbits 			len = size;
6297e7a9efdSJustin Hibbits 
6307e7a9efdSJustin Hibbits 		if (copyout((const void *)kaddr, (void *)uaddr, len)) {
6317e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
6327e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
6337e7a9efdSJustin Hibbits 		}
6347e7a9efdSJustin Hibbits 	}
635c7570492SJustin Hibbits }
636c7570492SJustin Hibbits 
637c7570492SJustin Hibbits uint8_t
638c7570492SJustin Hibbits dtrace_fuword8(void *uaddr)
639c7570492SJustin Hibbits {
640c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
641c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
642c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
643c7570492SJustin Hibbits 		return (0);
644c7570492SJustin Hibbits 	}
6457e7a9efdSJustin Hibbits 	return (fubyte(uaddr));
646c7570492SJustin Hibbits }
647c7570492SJustin Hibbits 
648c7570492SJustin Hibbits uint16_t
649c7570492SJustin Hibbits dtrace_fuword16(void *uaddr)
650c7570492SJustin Hibbits {
6517e7a9efdSJustin Hibbits 	uint16_t ret = 0;
6527e7a9efdSJustin Hibbits 
6537e7a9efdSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
6547e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
655c7570492SJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
656c7570492SJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
657c7570492SJustin Hibbits 		}
6587e7a9efdSJustin Hibbits 	}
6597e7a9efdSJustin Hibbits 	return ret;
660c7570492SJustin Hibbits }
661c7570492SJustin Hibbits 
662c7570492SJustin Hibbits uint32_t
663c7570492SJustin Hibbits dtrace_fuword32(void *uaddr)
664c7570492SJustin Hibbits {
665c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
666c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
667c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
668c7570492SJustin Hibbits 		return (0);
669c7570492SJustin Hibbits 	}
6707e7a9efdSJustin Hibbits 	return (fuword32(uaddr));
671c7570492SJustin Hibbits }
672c7570492SJustin Hibbits 
673c7570492SJustin Hibbits uint64_t
674c7570492SJustin Hibbits dtrace_fuword64(void *uaddr)
675c7570492SJustin Hibbits {
6767e7a9efdSJustin Hibbits 	uint64_t ret = 0;
6777e7a9efdSJustin Hibbits 
6787e7a9efdSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
6797e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
680c7570492SJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
681c7570492SJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
682c7570492SJustin Hibbits 		}
6837e7a9efdSJustin Hibbits 	}
6847e7a9efdSJustin Hibbits 	return ret;
685c7570492SJustin Hibbits }
68680a5635cSJustin Hibbits 
68780a5635cSJustin Hibbits uintptr_t
68880a5635cSJustin Hibbits dtrace_fulword(void *uaddr)
68980a5635cSJustin Hibbits {
69080a5635cSJustin Hibbits 	uintptr_t ret = 0;
69180a5635cSJustin Hibbits 
69280a5635cSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
69380a5635cSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
69480a5635cSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
69580a5635cSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
69680a5635cSJustin Hibbits 		}
69780a5635cSJustin Hibbits 	}
69880a5635cSJustin Hibbits 	return ret;
69980a5635cSJustin Hibbits }
700