xref: /freebsd/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c (revision 80a5635c8b455eda90ed24b931f0bc8741b82a4a)
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>
41c7570492SJustin Hibbits #include <machine/reg.h>
42c7570492SJustin Hibbits #include <machine/stack.h>
43c7570492SJustin Hibbits 
44c7570492SJustin Hibbits #include <vm/vm.h>
45c7570492SJustin Hibbits #include <vm/vm_param.h>
46c7570492SJustin Hibbits #include <vm/pmap.h>
47c7570492SJustin Hibbits 
48c7570492SJustin Hibbits #include "regset.h"
49c7570492SJustin Hibbits 
50c7570492SJustin Hibbits /* Offset to the LR Save word (ppc32) */
51c7570492SJustin Hibbits #define RETURN_OFFSET	4
52c7570492SJustin Hibbits #define RETURN_OFFSET64	8
53c7570492SJustin Hibbits 
54c7570492SJustin Hibbits #define INKERNEL(x)	((x) <= VM_MAX_KERNEL_ADDRESS && \
55c7570492SJustin Hibbits 		(x) >= VM_MIN_KERNEL_ADDRESS)
56c7570492SJustin Hibbits 
57c7570492SJustin Hibbits greg_t
58c7570492SJustin Hibbits dtrace_getfp(void)
59c7570492SJustin Hibbits {
60c7570492SJustin Hibbits 	return (greg_t)__builtin_frame_address(0);
61c7570492SJustin Hibbits }
62c7570492SJustin Hibbits 
63c7570492SJustin Hibbits void
64c7570492SJustin Hibbits dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
65c7570492SJustin Hibbits     uint32_t *intrpc)
66c7570492SJustin Hibbits {
67c7570492SJustin Hibbits 	int depth = 0;
68c7570492SJustin Hibbits 	register_t sp;
69c7570492SJustin Hibbits 	vm_offset_t callpc;
70c7570492SJustin Hibbits 	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
71c7570492SJustin Hibbits 
72c7570492SJustin Hibbits 	if (intrpc != 0)
73c7570492SJustin Hibbits 		pcstack[depth++] = (pc_t) intrpc;
74c7570492SJustin Hibbits 
75c7570492SJustin Hibbits 	aframes++;
76c7570492SJustin Hibbits 
77c7570492SJustin Hibbits 	sp = dtrace_getfp();
78c7570492SJustin Hibbits 
79c7570492SJustin Hibbits 	while (depth < pcstack_limit) {
80c7570492SJustin Hibbits 		if (!INKERNEL((long) sp))
81c7570492SJustin Hibbits 			break;
82c7570492SJustin Hibbits 
83c7570492SJustin Hibbits 		callpc = *(uintptr_t *)(sp + RETURN_OFFSET);
84c7570492SJustin Hibbits 
85c7570492SJustin Hibbits 		if (!INKERNEL(callpc))
86c7570492SJustin Hibbits 			break;
87c7570492SJustin Hibbits 
88c7570492SJustin Hibbits 		if (aframes > 0) {
89c7570492SJustin Hibbits 			aframes--;
90c7570492SJustin Hibbits 			if ((aframes == 0) && (caller != 0)) {
91c7570492SJustin Hibbits 				pcstack[depth++] = caller;
92c7570492SJustin Hibbits 			}
93c7570492SJustin Hibbits 		}
94c7570492SJustin Hibbits 		else {
95c7570492SJustin Hibbits 			pcstack[depth++] = callpc;
96c7570492SJustin Hibbits 		}
97c7570492SJustin Hibbits 
98c7570492SJustin Hibbits 		sp = *(uintptr_t*)sp;
99c7570492SJustin Hibbits 	}
100c7570492SJustin Hibbits 
101c7570492SJustin Hibbits 	for (; depth < pcstack_limit; depth++) {
102c7570492SJustin Hibbits 		pcstack[depth] = 0;
103c7570492SJustin Hibbits 	}
104c7570492SJustin Hibbits }
105c7570492SJustin Hibbits 
106c7570492SJustin Hibbits static int
107c7570492SJustin Hibbits dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
108c7570492SJustin Hibbits     uintptr_t sp)
109c7570492SJustin Hibbits {
110c7570492SJustin Hibbits 	proc_t *p = curproc;
111c7570492SJustin Hibbits 	int ret = 0;
112c7570492SJustin Hibbits 
113c7570492SJustin Hibbits 	ASSERT(pcstack == NULL || pcstack_limit > 0);
114c7570492SJustin Hibbits 
115c7570492SJustin Hibbits 	while (pc != 0) {
116c7570492SJustin Hibbits 		ret++;
117c7570492SJustin Hibbits 		if (pcstack != NULL) {
118c7570492SJustin Hibbits 			*pcstack++ = (uint64_t)pc;
119c7570492SJustin Hibbits 			pcstack_limit--;
120c7570492SJustin Hibbits 			if (pcstack_limit <= 0)
121c7570492SJustin Hibbits 				break;
122c7570492SJustin Hibbits 		}
123c7570492SJustin Hibbits 
124c7570492SJustin Hibbits 		if (sp == 0)
125c7570492SJustin Hibbits 			break;
126c7570492SJustin Hibbits 
127c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
128c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
129c7570492SJustin Hibbits 			sp = dtrace_fuword32((void *)sp);
130c7570492SJustin Hibbits 		}
131c7570492SJustin Hibbits 		else {
132c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
133c7570492SJustin Hibbits 			sp = dtrace_fuword64((void *)sp);
134c7570492SJustin Hibbits 		}
135c7570492SJustin Hibbits 	}
136c7570492SJustin Hibbits 
137c7570492SJustin Hibbits 	return (ret);
138c7570492SJustin Hibbits }
139c7570492SJustin Hibbits 
140c7570492SJustin Hibbits void
141c7570492SJustin Hibbits dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
142c7570492SJustin Hibbits {
143c7570492SJustin Hibbits 	proc_t *p = curproc;
144c7570492SJustin Hibbits 	struct trapframe *tf;
145c7570492SJustin Hibbits 	uintptr_t pc, sp;
146c7570492SJustin Hibbits 	volatile uint16_t *flags =
147c7570492SJustin Hibbits 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
148c7570492SJustin Hibbits 	int n;
149c7570492SJustin Hibbits 
150c7570492SJustin Hibbits 	if (*flags & CPU_DTRACE_FAULT)
151c7570492SJustin Hibbits 		return;
152c7570492SJustin Hibbits 
153c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
154c7570492SJustin Hibbits 		return;
155c7570492SJustin Hibbits 
156c7570492SJustin Hibbits 	/*
157c7570492SJustin Hibbits 	 * If there's no user context we still need to zero the stack.
158c7570492SJustin Hibbits 	 */
159c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
160c7570492SJustin Hibbits 		goto zero;
161c7570492SJustin Hibbits 
162c7570492SJustin Hibbits 	*pcstack++ = (uint64_t)p->p_pid;
163c7570492SJustin Hibbits 	pcstack_limit--;
164c7570492SJustin Hibbits 
165c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
166c7570492SJustin Hibbits 		return;
167c7570492SJustin Hibbits 
168c7570492SJustin Hibbits 	pc = tf->srr0;
169c7570492SJustin Hibbits 	sp = tf->fixreg[1];
170c7570492SJustin Hibbits 
171c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
172c7570492SJustin Hibbits 		/*
173c7570492SJustin Hibbits 		 * In an entry probe.  The frame pointer has not yet been
174c7570492SJustin Hibbits 		 * pushed (that happens in the function prologue).  The
175c7570492SJustin Hibbits 		 * best approach is to add the current pc as a missing top
176c7570492SJustin Hibbits 		 * of stack and back the pc up to the caller, which is stored
177c7570492SJustin Hibbits 		 * at the current stack pointer address since the call
178c7570492SJustin Hibbits 		 * instruction puts it there right before the branch.
179c7570492SJustin Hibbits 		 */
180c7570492SJustin Hibbits 
181c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
182c7570492SJustin Hibbits 		pcstack_limit--;
183c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
184c7570492SJustin Hibbits 			return;
185c7570492SJustin Hibbits 
186c7570492SJustin Hibbits 		pc = tf->lr;
187c7570492SJustin Hibbits 	}
188c7570492SJustin Hibbits 
189c7570492SJustin Hibbits 	n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
190c7570492SJustin Hibbits 	ASSERT(n >= 0);
191c7570492SJustin Hibbits 	ASSERT(n <= pcstack_limit);
192c7570492SJustin Hibbits 
193c7570492SJustin Hibbits 	pcstack += n;
194c7570492SJustin Hibbits 	pcstack_limit -= n;
195c7570492SJustin Hibbits 
196c7570492SJustin Hibbits zero:
197c7570492SJustin Hibbits 	while (pcstack_limit-- > 0)
198c7570492SJustin Hibbits 		*pcstack++ = 0;
199c7570492SJustin Hibbits }
200c7570492SJustin Hibbits 
201c7570492SJustin Hibbits int
202c7570492SJustin Hibbits dtrace_getustackdepth(void)
203c7570492SJustin Hibbits {
204c7570492SJustin Hibbits 	proc_t *p = curproc;
205c7570492SJustin Hibbits 	struct trapframe *tf;
206c7570492SJustin Hibbits 	uintptr_t pc, sp;
207c7570492SJustin Hibbits 	int n = 0;
208c7570492SJustin Hibbits 
209c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
210c7570492SJustin Hibbits 		return (0);
211c7570492SJustin Hibbits 
212c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
213c7570492SJustin Hibbits 		return (-1);
214c7570492SJustin Hibbits 
215c7570492SJustin Hibbits 	pc = tf->srr0;
216c7570492SJustin Hibbits 	sp = tf->fixreg[1];
217c7570492SJustin Hibbits 
218c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
219c7570492SJustin Hibbits 		/*
220c7570492SJustin Hibbits 		 * In an entry probe.  The frame pointer has not yet been
221c7570492SJustin Hibbits 		 * pushed (that happens in the function prologue).  The
222c7570492SJustin Hibbits 		 * best approach is to add the current pc as a missing top
223c7570492SJustin Hibbits 		 * of stack and back the pc up to the caller, which is stored
224c7570492SJustin Hibbits 		 * at the current stack pointer address since the call
225c7570492SJustin Hibbits 		 * instruction puts it there right before the branch.
226c7570492SJustin Hibbits 		 */
227c7570492SJustin Hibbits 
228c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
229c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *) sp);
230c7570492SJustin Hibbits 		}
231c7570492SJustin Hibbits 		else
232c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *) sp);
233c7570492SJustin Hibbits 		n++;
234c7570492SJustin Hibbits 	}
235c7570492SJustin Hibbits 
236c7570492SJustin Hibbits 	n += dtrace_getustack_common(NULL, 0, pc, sp);
237c7570492SJustin Hibbits 
238c7570492SJustin Hibbits 	return (n);
239c7570492SJustin Hibbits }
240c7570492SJustin Hibbits 
241c7570492SJustin Hibbits void
242c7570492SJustin Hibbits dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
243c7570492SJustin Hibbits {
244c7570492SJustin Hibbits 	proc_t *p = curproc;
245c7570492SJustin Hibbits 	struct trapframe *tf;
246c7570492SJustin Hibbits 	uintptr_t pc, sp;
247c7570492SJustin Hibbits 	volatile uint16_t *flags =
248c7570492SJustin Hibbits 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
249c7570492SJustin Hibbits #ifdef notyet	/* XXX signal stack */
250c7570492SJustin Hibbits 	uintptr_t oldcontext;
251c7570492SJustin Hibbits 	size_t s1, s2;
252c7570492SJustin Hibbits #endif
253c7570492SJustin Hibbits 
254c7570492SJustin Hibbits 	if (*flags & CPU_DTRACE_FAULT)
255c7570492SJustin Hibbits 		return;
256c7570492SJustin Hibbits 
257c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
258c7570492SJustin Hibbits 		return;
259c7570492SJustin Hibbits 
260c7570492SJustin Hibbits 	/*
261c7570492SJustin Hibbits 	 * If there's no user context we still need to zero the stack.
262c7570492SJustin Hibbits 	 */
263c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
264c7570492SJustin Hibbits 		goto zero;
265c7570492SJustin Hibbits 
266c7570492SJustin Hibbits 	*pcstack++ = (uint64_t)p->p_pid;
267c7570492SJustin Hibbits 	pcstack_limit--;
268c7570492SJustin Hibbits 
269c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
270c7570492SJustin Hibbits 		return;
271c7570492SJustin Hibbits 
272c7570492SJustin Hibbits 	pc = tf->srr0;
273c7570492SJustin Hibbits 	sp = tf->fixreg[1];
274c7570492SJustin Hibbits 
275c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */
276c7570492SJustin Hibbits 	oldcontext = lwp->lwp_oldcontext;
277c7570492SJustin Hibbits 	s1 = sizeof (struct xframe) + 2 * sizeof (long);
278c7570492SJustin Hibbits 	s2 = s1 + sizeof (siginfo_t);
279c7570492SJustin Hibbits #endif
280c7570492SJustin Hibbits 
281c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
282c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
283c7570492SJustin Hibbits 		*fpstack++ = 0;
284c7570492SJustin Hibbits 		pcstack_limit--;
285c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
286c7570492SJustin Hibbits 			return;
287c7570492SJustin Hibbits 
288c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
289c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *)sp);
290c7570492SJustin Hibbits 		}
291c7570492SJustin Hibbits 		else {
292c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *)sp);
293c7570492SJustin Hibbits 		}
294c7570492SJustin Hibbits 	}
295c7570492SJustin Hibbits 
296c7570492SJustin Hibbits 	while (pc != 0) {
297c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
298c7570492SJustin Hibbits 		*fpstack++ = sp;
299c7570492SJustin Hibbits 		pcstack_limit--;
300c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
301c7570492SJustin Hibbits 			break;
302c7570492SJustin Hibbits 
303c7570492SJustin Hibbits 		if (sp == 0)
304c7570492SJustin Hibbits 			break;
305c7570492SJustin Hibbits 
306c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */
307c7570492SJustin Hibbits 		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
308c7570492SJustin Hibbits 			ucontext_t *ucp = (ucontext_t *)oldcontext;
309c7570492SJustin Hibbits 			greg_t *gregs = ucp->uc_mcontext.gregs;
310c7570492SJustin Hibbits 
311c7570492SJustin Hibbits 			sp = dtrace_fulword(&gregs[REG_FP]);
312c7570492SJustin Hibbits 			pc = dtrace_fulword(&gregs[REG_PC]);
313c7570492SJustin Hibbits 
314c7570492SJustin Hibbits 			oldcontext = dtrace_fulword(&ucp->uc_link);
315c7570492SJustin Hibbits 		} else
316c7570492SJustin Hibbits #endif /* XXX */
317c7570492SJustin Hibbits 		{
318c7570492SJustin Hibbits 			if (SV_PROC_FLAG(p, SV_ILP32)) {
319c7570492SJustin Hibbits 				pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
320c7570492SJustin Hibbits 				sp = dtrace_fuword32((void *)sp);
321c7570492SJustin Hibbits 			}
322c7570492SJustin Hibbits 			else {
323c7570492SJustin Hibbits 				pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
324c7570492SJustin Hibbits 				sp = dtrace_fuword64((void *)sp);
325c7570492SJustin Hibbits 			}
326c7570492SJustin Hibbits 		}
327c7570492SJustin Hibbits 
328c7570492SJustin Hibbits 		/*
329c7570492SJustin Hibbits 		 * This is totally bogus:  if we faulted, we're going to clear
330c7570492SJustin Hibbits 		 * the fault and break.  This is to deal with the apparently
331c7570492SJustin Hibbits 		 * broken Java stacks on x86.
332c7570492SJustin Hibbits 		 */
333c7570492SJustin Hibbits 		if (*flags & CPU_DTRACE_FAULT) {
334c7570492SJustin Hibbits 			*flags &= ~CPU_DTRACE_FAULT;
335c7570492SJustin Hibbits 			break;
336c7570492SJustin Hibbits 		}
337c7570492SJustin Hibbits 	}
338c7570492SJustin Hibbits 
339c7570492SJustin Hibbits zero:
340c7570492SJustin Hibbits 	while (pcstack_limit-- > 0)
341c7570492SJustin Hibbits 		*pcstack++ = 0;
342c7570492SJustin Hibbits }
343c7570492SJustin Hibbits 
344c7570492SJustin Hibbits /*ARGSUSED*/
345c7570492SJustin Hibbits uint64_t
346c7570492SJustin Hibbits dtrace_getarg(int arg, int aframes)
347c7570492SJustin Hibbits {
348c7570492SJustin Hibbits 	return (0);
349c7570492SJustin Hibbits }
350c7570492SJustin Hibbits 
351c7570492SJustin Hibbits #ifdef notyet
352c7570492SJustin Hibbits {
353c7570492SJustin Hibbits 	int depth = 0;
354c7570492SJustin Hibbits 	register_t sp;
355c7570492SJustin Hibbits 	vm_offset_t callpc;
356c7570492SJustin Hibbits 	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
357c7570492SJustin Hibbits 
358c7570492SJustin Hibbits 	if (intrpc != 0)
359c7570492SJustin Hibbits 		pcstack[depth++] = (pc_t) intrpc;
360c7570492SJustin Hibbits 
361c7570492SJustin Hibbits 	aframes++;
362c7570492SJustin Hibbits 
363c7570492SJustin Hibbits 	sp = dtrace_getfp();
364c7570492SJustin Hibbits 
365c7570492SJustin Hibbits 	while (depth < pcstack_limit) {
366c7570492SJustin Hibbits 		if (!INKERNEL((long) frame))
367c7570492SJustin Hibbits 			break;
368c7570492SJustin Hibbits 
369c7570492SJustin Hibbits 		callpc = *(void **)(sp + RETURN_OFFSET);
370c7570492SJustin Hibbits 
371c7570492SJustin Hibbits 		if (!INKERNEL(callpc))
372c7570492SJustin Hibbits 			break;
373c7570492SJustin Hibbits 
374c7570492SJustin Hibbits 		if (aframes > 0) {
375c7570492SJustin Hibbits 			aframes--;
376c7570492SJustin Hibbits 			if ((aframes == 0) && (caller != 0)) {
377c7570492SJustin Hibbits 				pcstack[depth++] = caller;
378c7570492SJustin Hibbits 			}
379c7570492SJustin Hibbits 		}
380c7570492SJustin Hibbits 		else {
381c7570492SJustin Hibbits 			pcstack[depth++] = callpc;
382c7570492SJustin Hibbits 		}
383c7570492SJustin Hibbits 
384c7570492SJustin Hibbits 		sp = *(void **)sp;
385c7570492SJustin Hibbits 	}
386c7570492SJustin Hibbits 
387c7570492SJustin Hibbits 	for (; depth < pcstack_limit; depth++) {
388c7570492SJustin Hibbits 		pcstack[depth] = 0;
389c7570492SJustin Hibbits 	}
390c7570492SJustin Hibbits }
391c7570492SJustin Hibbits #endif
392c7570492SJustin Hibbits 
393c7570492SJustin Hibbits int
394c7570492SJustin Hibbits dtrace_getstackdepth(int aframes)
395c7570492SJustin Hibbits {
396c7570492SJustin Hibbits 	int depth = 0;
397c7570492SJustin Hibbits 	register_t sp;
398c7570492SJustin Hibbits 
399c7570492SJustin Hibbits 	aframes++;
400c7570492SJustin Hibbits 	sp = dtrace_getfp();
401c7570492SJustin Hibbits 	depth++;
402c7570492SJustin Hibbits 	for(;;) {
403c7570492SJustin Hibbits 		if (!INKERNEL((long) sp))
404c7570492SJustin Hibbits 			break;
405c7570492SJustin Hibbits 		if (!INKERNEL((long) *(void **)sp))
406c7570492SJustin Hibbits 			break;
407c7570492SJustin Hibbits 		depth++;
408c7570492SJustin Hibbits 		sp = *(uintptr_t *)sp;
409c7570492SJustin Hibbits 	}
410c7570492SJustin Hibbits 	if (depth < aframes)
411c7570492SJustin Hibbits 		return 0;
412c7570492SJustin Hibbits 	else
413c7570492SJustin Hibbits 		return depth - aframes;
414c7570492SJustin Hibbits }
415c7570492SJustin Hibbits 
416c7570492SJustin Hibbits ulong_t
417c7570492SJustin Hibbits dtrace_getreg(struct trapframe *rp, uint_t reg)
418c7570492SJustin Hibbits {
419c7570492SJustin Hibbits 	if (reg < 32)
420c7570492SJustin Hibbits 		return (rp->fixreg[reg]);
421c7570492SJustin Hibbits 
422c7570492SJustin Hibbits 	switch (reg) {
423c7570492SJustin Hibbits 	case 33:
424c7570492SJustin Hibbits 		return (rp->lr);
425c7570492SJustin Hibbits 	case 34:
426c7570492SJustin Hibbits 		return (rp->cr);
427c7570492SJustin Hibbits 	case 35:
428c7570492SJustin Hibbits 		return (rp->xer);
429c7570492SJustin Hibbits 	case 36:
430c7570492SJustin Hibbits 		return (rp->ctr);
431c7570492SJustin Hibbits 	case 37:
432c7570492SJustin Hibbits 		return (rp->srr0);
433c7570492SJustin Hibbits 	case 38:
434c7570492SJustin Hibbits 		return (rp->srr1);
435c7570492SJustin Hibbits 	case 39:
436c7570492SJustin Hibbits 		return (rp->exc);
437c7570492SJustin Hibbits 	default:
438c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
439c7570492SJustin Hibbits 		return (0);
440c7570492SJustin Hibbits 	}
441c7570492SJustin Hibbits }
442c7570492SJustin Hibbits 
443c7570492SJustin Hibbits static int
444c7570492SJustin Hibbits dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
445c7570492SJustin Hibbits {
446c7570492SJustin Hibbits 	ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
447c7570492SJustin Hibbits 
448c7570492SJustin Hibbits 	if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
449c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
450c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
451c7570492SJustin Hibbits 		return (0);
452c7570492SJustin Hibbits 	}
453c7570492SJustin Hibbits 
454c7570492SJustin Hibbits 	return (1);
455c7570492SJustin Hibbits }
456c7570492SJustin Hibbits 
457c7570492SJustin Hibbits void
458c7570492SJustin Hibbits dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
459c7570492SJustin Hibbits     volatile uint16_t *flags)
460c7570492SJustin Hibbits {
461c7570492SJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size))
4627e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)kaddr, size)) {
4637e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
4647e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
4657e7a9efdSJustin Hibbits 		}
466c7570492SJustin Hibbits }
467c7570492SJustin Hibbits 
468c7570492SJustin Hibbits void
469c7570492SJustin Hibbits dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
470c7570492SJustin Hibbits     volatile uint16_t *flags)
471c7570492SJustin Hibbits {
4727e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
4737e7a9efdSJustin Hibbits 		if (copyout((const void *)kaddr, (void *)uaddr, size)) {
4747e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
4757e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
4767e7a9efdSJustin Hibbits 		}
4777e7a9efdSJustin Hibbits 	}
478c7570492SJustin Hibbits }
479c7570492SJustin Hibbits 
480c7570492SJustin Hibbits void
481c7570492SJustin Hibbits dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
482c7570492SJustin Hibbits     volatile uint16_t *flags)
483c7570492SJustin Hibbits {
4847e7a9efdSJustin Hibbits 	size_t actual;
4857e7a9efdSJustin Hibbits 	int    error;
4867e7a9efdSJustin Hibbits 
4877e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
4887e7a9efdSJustin Hibbits 		error = copyinstr((const void *)uaddr, (void *)kaddr,
4897e7a9efdSJustin Hibbits 		    size, &actual);
4907e7a9efdSJustin Hibbits 
4917e7a9efdSJustin Hibbits 		/* ENAMETOOLONG is not a fault condition. */
4927e7a9efdSJustin Hibbits 		if (error && error != ENAMETOOLONG) {
4937e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
4947e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
4957e7a9efdSJustin Hibbits 		}
4967e7a9efdSJustin Hibbits 	}
497c7570492SJustin Hibbits }
498c7570492SJustin Hibbits 
4997e7a9efdSJustin Hibbits /*
5007e7a9efdSJustin Hibbits  * The bulk of this function could be replaced to match dtrace_copyinstr()
5017e7a9efdSJustin Hibbits  * if we ever implement a copyoutstr().
5027e7a9efdSJustin Hibbits  */
503c7570492SJustin Hibbits void
504c7570492SJustin Hibbits dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
505c7570492SJustin Hibbits     volatile uint16_t *flags)
506c7570492SJustin Hibbits {
5077e7a9efdSJustin Hibbits 	size_t len;
5087e7a9efdSJustin Hibbits 
5097e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
5107e7a9efdSJustin Hibbits 		len = strlen((const char *)kaddr);
5117e7a9efdSJustin Hibbits 		if (len > size)
5127e7a9efdSJustin Hibbits 			len = size;
5137e7a9efdSJustin Hibbits 
5147e7a9efdSJustin Hibbits 		if (copyout((const void *)kaddr, (void *)uaddr, len)) {
5157e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
5167e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
5177e7a9efdSJustin Hibbits 		}
5187e7a9efdSJustin Hibbits 	}
519c7570492SJustin Hibbits }
520c7570492SJustin Hibbits 
521c7570492SJustin Hibbits uint8_t
522c7570492SJustin Hibbits dtrace_fuword8(void *uaddr)
523c7570492SJustin Hibbits {
524c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
525c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
526c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
527c7570492SJustin Hibbits 		return (0);
528c7570492SJustin Hibbits 	}
5297e7a9efdSJustin Hibbits 	return (fubyte(uaddr));
530c7570492SJustin Hibbits }
531c7570492SJustin Hibbits 
532c7570492SJustin Hibbits uint16_t
533c7570492SJustin Hibbits dtrace_fuword16(void *uaddr)
534c7570492SJustin Hibbits {
5357e7a9efdSJustin Hibbits 	uint16_t ret = 0;
5367e7a9efdSJustin Hibbits 
5377e7a9efdSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
5387e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
539c7570492SJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
540c7570492SJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
541c7570492SJustin Hibbits 		}
5427e7a9efdSJustin Hibbits 	}
5437e7a9efdSJustin Hibbits 	return ret;
544c7570492SJustin Hibbits }
545c7570492SJustin Hibbits 
546c7570492SJustin Hibbits uint32_t
547c7570492SJustin Hibbits dtrace_fuword32(void *uaddr)
548c7570492SJustin Hibbits {
549c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
550c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
551c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
552c7570492SJustin Hibbits 		return (0);
553c7570492SJustin Hibbits 	}
5547e7a9efdSJustin Hibbits 	return (fuword32(uaddr));
555c7570492SJustin Hibbits }
556c7570492SJustin Hibbits 
557c7570492SJustin Hibbits uint64_t
558c7570492SJustin Hibbits dtrace_fuword64(void *uaddr)
559c7570492SJustin Hibbits {
5607e7a9efdSJustin Hibbits 	uint64_t ret = 0;
5617e7a9efdSJustin Hibbits 
5627e7a9efdSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
5637e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
564c7570492SJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
565c7570492SJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
566c7570492SJustin Hibbits 		}
5677e7a9efdSJustin Hibbits 	}
5687e7a9efdSJustin Hibbits 	return ret;
569c7570492SJustin Hibbits }
570*80a5635cSJustin Hibbits 
571*80a5635cSJustin Hibbits uintptr_t
572*80a5635cSJustin Hibbits dtrace_fulword(void *uaddr)
573*80a5635cSJustin Hibbits {
574*80a5635cSJustin Hibbits 	uintptr_t ret = 0;
575*80a5635cSJustin Hibbits 
576*80a5635cSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
577*80a5635cSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
578*80a5635cSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
579*80a5635cSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
580*80a5635cSJustin Hibbits 		}
581*80a5635cSJustin Hibbits 	}
582*80a5635cSJustin Hibbits 	return ret;
583*80a5635cSJustin Hibbits }
584