xref: /freebsd/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c (revision 594ce9ad6fbcecd551367a1b315d36560d988e45)
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
52*594ce9adSJustin Hibbits /* Offset to LR Save word (ppc64).  CR Save area sits between back chain and LR */
53*594ce9adSJustin Hibbits #define RETURN_OFFSET64	16
54c7570492SJustin Hibbits 
55c7570492SJustin Hibbits #define INKERNEL(x)	((x) <= VM_MAX_KERNEL_ADDRESS && \
56c7570492SJustin Hibbits 		(x) >= VM_MIN_KERNEL_ADDRESS)
57c7570492SJustin Hibbits 
58c7570492SJustin Hibbits greg_t
59c7570492SJustin Hibbits dtrace_getfp(void)
60c7570492SJustin Hibbits {
61c7570492SJustin Hibbits 	return (greg_t)__builtin_frame_address(0);
62c7570492SJustin Hibbits }
63c7570492SJustin Hibbits 
64c7570492SJustin Hibbits void
65c7570492SJustin Hibbits dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
66c7570492SJustin Hibbits     uint32_t *intrpc)
67c7570492SJustin Hibbits {
68c7570492SJustin Hibbits 	int depth = 0;
69c7570492SJustin Hibbits 	register_t sp;
70c7570492SJustin Hibbits 	vm_offset_t callpc;
71c7570492SJustin Hibbits 	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
72c7570492SJustin Hibbits 
73c7570492SJustin Hibbits 	if (intrpc != 0)
74c7570492SJustin Hibbits 		pcstack[depth++] = (pc_t) intrpc;
75c7570492SJustin Hibbits 
76c7570492SJustin Hibbits 	aframes++;
77c7570492SJustin Hibbits 
78c7570492SJustin Hibbits 	sp = dtrace_getfp();
79c7570492SJustin Hibbits 
80c7570492SJustin Hibbits 	while (depth < pcstack_limit) {
81c7570492SJustin Hibbits 		if (!INKERNEL((long) sp))
82c7570492SJustin Hibbits 			break;
83c7570492SJustin Hibbits 
84cc117e27SJustin Hibbits #ifdef __powerpc64__
85cc117e27SJustin Hibbits 		callpc = *(uintptr_t *)(sp + RETURN_OFFSET64);
86cc117e27SJustin Hibbits #else
87c7570492SJustin Hibbits 		callpc = *(uintptr_t *)(sp + RETURN_OFFSET);
88cc117e27SJustin Hibbits #endif
89c7570492SJustin Hibbits 
90c7570492SJustin Hibbits 		if (!INKERNEL(callpc))
91c7570492SJustin Hibbits 			break;
92c7570492SJustin Hibbits 
93c7570492SJustin Hibbits 		if (aframes > 0) {
94c7570492SJustin Hibbits 			aframes--;
95c7570492SJustin Hibbits 			if ((aframes == 0) && (caller != 0)) {
96c7570492SJustin Hibbits 				pcstack[depth++] = caller;
97c7570492SJustin Hibbits 			}
98c7570492SJustin Hibbits 		}
99c7570492SJustin Hibbits 		else {
100c7570492SJustin Hibbits 			pcstack[depth++] = callpc;
101c7570492SJustin Hibbits 		}
102c7570492SJustin Hibbits 
103c7570492SJustin Hibbits 		sp = *(uintptr_t*)sp;
104c7570492SJustin Hibbits 	}
105c7570492SJustin Hibbits 
106c7570492SJustin Hibbits 	for (; depth < pcstack_limit; depth++) {
107c7570492SJustin Hibbits 		pcstack[depth] = 0;
108c7570492SJustin Hibbits 	}
109c7570492SJustin Hibbits }
110c7570492SJustin Hibbits 
111c7570492SJustin Hibbits static int
112c7570492SJustin Hibbits dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
113c7570492SJustin Hibbits     uintptr_t sp)
114c7570492SJustin Hibbits {
115c7570492SJustin Hibbits 	proc_t *p = curproc;
116c7570492SJustin Hibbits 	int ret = 0;
117c7570492SJustin Hibbits 
118c7570492SJustin Hibbits 	ASSERT(pcstack == NULL || pcstack_limit > 0);
119c7570492SJustin Hibbits 
120c7570492SJustin Hibbits 	while (pc != 0) {
121c7570492SJustin Hibbits 		ret++;
122c7570492SJustin Hibbits 		if (pcstack != NULL) {
123c7570492SJustin Hibbits 			*pcstack++ = (uint64_t)pc;
124c7570492SJustin Hibbits 			pcstack_limit--;
125c7570492SJustin Hibbits 			if (pcstack_limit <= 0)
126c7570492SJustin Hibbits 				break;
127c7570492SJustin Hibbits 		}
128c7570492SJustin Hibbits 
129c7570492SJustin Hibbits 		if (sp == 0)
130c7570492SJustin Hibbits 			break;
131c7570492SJustin Hibbits 
132c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
133c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
134c7570492SJustin Hibbits 			sp = dtrace_fuword32((void *)sp);
135c7570492SJustin Hibbits 		}
136c7570492SJustin Hibbits 		else {
137c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
138c7570492SJustin Hibbits 			sp = dtrace_fuword64((void *)sp);
139c7570492SJustin Hibbits 		}
140c7570492SJustin Hibbits 	}
141c7570492SJustin Hibbits 
142c7570492SJustin Hibbits 	return (ret);
143c7570492SJustin Hibbits }
144c7570492SJustin Hibbits 
145c7570492SJustin Hibbits void
146c7570492SJustin Hibbits dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
147c7570492SJustin Hibbits {
148c7570492SJustin Hibbits 	proc_t *p = curproc;
149c7570492SJustin Hibbits 	struct trapframe *tf;
150c7570492SJustin Hibbits 	uintptr_t pc, sp;
151c7570492SJustin Hibbits 	volatile uint16_t *flags =
152c7570492SJustin Hibbits 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
153c7570492SJustin Hibbits 	int n;
154c7570492SJustin Hibbits 
155c7570492SJustin Hibbits 	if (*flags & CPU_DTRACE_FAULT)
156c7570492SJustin Hibbits 		return;
157c7570492SJustin Hibbits 
158c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
159c7570492SJustin Hibbits 		return;
160c7570492SJustin Hibbits 
161c7570492SJustin Hibbits 	/*
162c7570492SJustin Hibbits 	 * If there's no user context we still need to zero the stack.
163c7570492SJustin Hibbits 	 */
164c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
165c7570492SJustin Hibbits 		goto zero;
166c7570492SJustin Hibbits 
167c7570492SJustin Hibbits 	*pcstack++ = (uint64_t)p->p_pid;
168c7570492SJustin Hibbits 	pcstack_limit--;
169c7570492SJustin Hibbits 
170c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
171c7570492SJustin Hibbits 		return;
172c7570492SJustin Hibbits 
173c7570492SJustin Hibbits 	pc = tf->srr0;
174c7570492SJustin Hibbits 	sp = tf->fixreg[1];
175c7570492SJustin Hibbits 
176c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
177c7570492SJustin Hibbits 		/*
178c7570492SJustin Hibbits 		 * In an entry probe.  The frame pointer has not yet been
179c7570492SJustin Hibbits 		 * pushed (that happens in the function prologue).  The
180c7570492SJustin Hibbits 		 * best approach is to add the current pc as a missing top
181c7570492SJustin Hibbits 		 * of stack and back the pc up to the caller, which is stored
182c7570492SJustin Hibbits 		 * at the current stack pointer address since the call
183c7570492SJustin Hibbits 		 * instruction puts it there right before the branch.
184c7570492SJustin Hibbits 		 */
185c7570492SJustin Hibbits 
186c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
187c7570492SJustin Hibbits 		pcstack_limit--;
188c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
189c7570492SJustin Hibbits 			return;
190c7570492SJustin Hibbits 
191c7570492SJustin Hibbits 		pc = tf->lr;
192c7570492SJustin Hibbits 	}
193c7570492SJustin Hibbits 
194c7570492SJustin Hibbits 	n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
195c7570492SJustin Hibbits 	ASSERT(n >= 0);
196c7570492SJustin Hibbits 	ASSERT(n <= pcstack_limit);
197c7570492SJustin Hibbits 
198c7570492SJustin Hibbits 	pcstack += n;
199c7570492SJustin Hibbits 	pcstack_limit -= n;
200c7570492SJustin Hibbits 
201c7570492SJustin Hibbits zero:
202c7570492SJustin Hibbits 	while (pcstack_limit-- > 0)
203c7570492SJustin Hibbits 		*pcstack++ = 0;
204c7570492SJustin Hibbits }
205c7570492SJustin Hibbits 
206c7570492SJustin Hibbits int
207c7570492SJustin Hibbits dtrace_getustackdepth(void)
208c7570492SJustin Hibbits {
209c7570492SJustin Hibbits 	proc_t *p = curproc;
210c7570492SJustin Hibbits 	struct trapframe *tf;
211c7570492SJustin Hibbits 	uintptr_t pc, sp;
212c7570492SJustin Hibbits 	int n = 0;
213c7570492SJustin Hibbits 
214c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
215c7570492SJustin Hibbits 		return (0);
216c7570492SJustin Hibbits 
217c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
218c7570492SJustin Hibbits 		return (-1);
219c7570492SJustin Hibbits 
220c7570492SJustin Hibbits 	pc = tf->srr0;
221c7570492SJustin Hibbits 	sp = tf->fixreg[1];
222c7570492SJustin Hibbits 
223c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
224c7570492SJustin Hibbits 		/*
225c7570492SJustin Hibbits 		 * In an entry probe.  The frame pointer has not yet been
226c7570492SJustin Hibbits 		 * pushed (that happens in the function prologue).  The
227c7570492SJustin Hibbits 		 * best approach is to add the current pc as a missing top
228c7570492SJustin Hibbits 		 * of stack and back the pc up to the caller, which is stored
229c7570492SJustin Hibbits 		 * at the current stack pointer address since the call
230c7570492SJustin Hibbits 		 * instruction puts it there right before the branch.
231c7570492SJustin Hibbits 		 */
232c7570492SJustin Hibbits 
233c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
234c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *) sp);
235c7570492SJustin Hibbits 		}
236c7570492SJustin Hibbits 		else
237c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *) sp);
238c7570492SJustin Hibbits 		n++;
239c7570492SJustin Hibbits 	}
240c7570492SJustin Hibbits 
241c7570492SJustin Hibbits 	n += dtrace_getustack_common(NULL, 0, pc, sp);
242c7570492SJustin Hibbits 
243c7570492SJustin Hibbits 	return (n);
244c7570492SJustin Hibbits }
245c7570492SJustin Hibbits 
246c7570492SJustin Hibbits void
247c7570492SJustin Hibbits dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
248c7570492SJustin Hibbits {
249c7570492SJustin Hibbits 	proc_t *p = curproc;
250c7570492SJustin Hibbits 	struct trapframe *tf;
251c7570492SJustin Hibbits 	uintptr_t pc, sp;
252c7570492SJustin Hibbits 	volatile uint16_t *flags =
253c7570492SJustin Hibbits 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
254c7570492SJustin Hibbits #ifdef notyet	/* XXX signal stack */
255c7570492SJustin Hibbits 	uintptr_t oldcontext;
256c7570492SJustin Hibbits 	size_t s1, s2;
257c7570492SJustin Hibbits #endif
258c7570492SJustin Hibbits 
259c7570492SJustin Hibbits 	if (*flags & CPU_DTRACE_FAULT)
260c7570492SJustin Hibbits 		return;
261c7570492SJustin Hibbits 
262c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
263c7570492SJustin Hibbits 		return;
264c7570492SJustin Hibbits 
265c7570492SJustin Hibbits 	/*
266c7570492SJustin Hibbits 	 * If there's no user context we still need to zero the stack.
267c7570492SJustin Hibbits 	 */
268c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
269c7570492SJustin Hibbits 		goto zero;
270c7570492SJustin Hibbits 
271c7570492SJustin Hibbits 	*pcstack++ = (uint64_t)p->p_pid;
272c7570492SJustin Hibbits 	pcstack_limit--;
273c7570492SJustin Hibbits 
274c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
275c7570492SJustin Hibbits 		return;
276c7570492SJustin Hibbits 
277c7570492SJustin Hibbits 	pc = tf->srr0;
278c7570492SJustin Hibbits 	sp = tf->fixreg[1];
279c7570492SJustin Hibbits 
280c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */
281c7570492SJustin Hibbits 	oldcontext = lwp->lwp_oldcontext;
282c7570492SJustin Hibbits 	s1 = sizeof (struct xframe) + 2 * sizeof (long);
283c7570492SJustin Hibbits 	s2 = s1 + sizeof (siginfo_t);
284c7570492SJustin Hibbits #endif
285c7570492SJustin Hibbits 
286c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
287c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
288c7570492SJustin Hibbits 		*fpstack++ = 0;
289c7570492SJustin Hibbits 		pcstack_limit--;
290c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
291c7570492SJustin Hibbits 			return;
292c7570492SJustin Hibbits 
293c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
294c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *)sp);
295c7570492SJustin Hibbits 		}
296c7570492SJustin Hibbits 		else {
297c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *)sp);
298c7570492SJustin Hibbits 		}
299c7570492SJustin Hibbits 	}
300c7570492SJustin Hibbits 
301c7570492SJustin Hibbits 	while (pc != 0) {
302c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
303c7570492SJustin Hibbits 		*fpstack++ = sp;
304c7570492SJustin Hibbits 		pcstack_limit--;
305c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
306c7570492SJustin Hibbits 			break;
307c7570492SJustin Hibbits 
308c7570492SJustin Hibbits 		if (sp == 0)
309c7570492SJustin Hibbits 			break;
310c7570492SJustin Hibbits 
311c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */
312c7570492SJustin Hibbits 		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
313c7570492SJustin Hibbits 			ucontext_t *ucp = (ucontext_t *)oldcontext;
314c7570492SJustin Hibbits 			greg_t *gregs = ucp->uc_mcontext.gregs;
315c7570492SJustin Hibbits 
316c7570492SJustin Hibbits 			sp = dtrace_fulword(&gregs[REG_FP]);
317c7570492SJustin Hibbits 			pc = dtrace_fulword(&gregs[REG_PC]);
318c7570492SJustin Hibbits 
319c7570492SJustin Hibbits 			oldcontext = dtrace_fulword(&ucp->uc_link);
320c7570492SJustin Hibbits 		} else
321c7570492SJustin Hibbits #endif /* XXX */
322c7570492SJustin Hibbits 		{
323c7570492SJustin Hibbits 			if (SV_PROC_FLAG(p, SV_ILP32)) {
324c7570492SJustin Hibbits 				pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
325c7570492SJustin Hibbits 				sp = dtrace_fuword32((void *)sp);
326c7570492SJustin Hibbits 			}
327c7570492SJustin Hibbits 			else {
328c7570492SJustin Hibbits 				pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
329c7570492SJustin Hibbits 				sp = dtrace_fuword64((void *)sp);
330c7570492SJustin Hibbits 			}
331c7570492SJustin Hibbits 		}
332c7570492SJustin Hibbits 
333c7570492SJustin Hibbits 		/*
334c7570492SJustin Hibbits 		 * This is totally bogus:  if we faulted, we're going to clear
335c7570492SJustin Hibbits 		 * the fault and break.  This is to deal with the apparently
336c7570492SJustin Hibbits 		 * broken Java stacks on x86.
337c7570492SJustin Hibbits 		 */
338c7570492SJustin Hibbits 		if (*flags & CPU_DTRACE_FAULT) {
339c7570492SJustin Hibbits 			*flags &= ~CPU_DTRACE_FAULT;
340c7570492SJustin Hibbits 			break;
341c7570492SJustin Hibbits 		}
342c7570492SJustin Hibbits 	}
343c7570492SJustin Hibbits 
344c7570492SJustin Hibbits zero:
345c7570492SJustin Hibbits 	while (pcstack_limit-- > 0)
346c7570492SJustin Hibbits 		*pcstack++ = 0;
347c7570492SJustin Hibbits }
348c7570492SJustin Hibbits 
349c7570492SJustin Hibbits /*ARGSUSED*/
350c7570492SJustin Hibbits uint64_t
351c7570492SJustin Hibbits dtrace_getarg(int arg, int aframes)
352c7570492SJustin Hibbits {
353f0bd82a1SJustin Hibbits 	uintptr_t val;
354f0bd82a1SJustin Hibbits 	uintptr_t *fp = (uintptr_t *)dtrace_getfp();
355f0bd82a1SJustin Hibbits 	uintptr_t *stack;
356f0bd82a1SJustin Hibbits 	int i;
357f0bd82a1SJustin Hibbits 
358f0bd82a1SJustin Hibbits 	/*
359f0bd82a1SJustin Hibbits 	 * A total of 8 arguments are passed via registers; any argument with
360f0bd82a1SJustin Hibbits 	 * index of 7 or lower is therefore in a register.
361f0bd82a1SJustin Hibbits 	 */
362f0bd82a1SJustin Hibbits 	int inreg = 7;
363f0bd82a1SJustin Hibbits 
364f0bd82a1SJustin Hibbits 	for (i = 1; i <= aframes; i++) {
365f0bd82a1SJustin Hibbits 		fp = (uintptr_t *)*fp;
366f0bd82a1SJustin Hibbits 
367f0bd82a1SJustin Hibbits 		/*
368f0bd82a1SJustin Hibbits 		 * On ppc32 AIM, and booke, trapexit() is the immediately following
369f0bd82a1SJustin Hibbits 		 * label.  On ppc64 AIM trapexit() follows a nop.
370f0bd82a1SJustin Hibbits 		 */
371f0bd82a1SJustin Hibbits 		if (((long)(fp[1]) == (long)trapexit) ||
372f0bd82a1SJustin Hibbits 				(((long)(fp[1]) + 4 == (long)trapexit))) {
373f0bd82a1SJustin Hibbits 			/*
374f0bd82a1SJustin Hibbits 			 * In the case of powerpc, we will use the pointer to the regs
375f0bd82a1SJustin Hibbits 			 * structure that was pushed when we took the trap.  To get this
376f0bd82a1SJustin Hibbits 			 * structure, we must increment beyond the frame structure.  If the
377f0bd82a1SJustin Hibbits 			 * argument that we're seeking is passed on the stack, we'll pull
378f0bd82a1SJustin Hibbits 			 * the true stack pointer out of the saved registers and decrement
379f0bd82a1SJustin Hibbits 			 * our argument by the number of arguments passed in registers; if
380f0bd82a1SJustin Hibbits 			 * the argument we're seeking is passed in regsiters, we can just
381f0bd82a1SJustin Hibbits 			 * load it directly.
382f0bd82a1SJustin Hibbits 			 */
383f0bd82a1SJustin Hibbits #ifdef __powerpc64__
384f0bd82a1SJustin Hibbits 			struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48);
385f0bd82a1SJustin Hibbits #else
386f0bd82a1SJustin Hibbits 			struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8);
387f0bd82a1SJustin Hibbits #endif
388f0bd82a1SJustin Hibbits 
389f0bd82a1SJustin Hibbits 			if (arg <= inreg) {
390f0bd82a1SJustin Hibbits 				stack = &rp->fixreg[3];
391f0bd82a1SJustin Hibbits 			} else {
392f0bd82a1SJustin Hibbits 				stack = (uintptr_t *)(rp->fixreg[1]);
393f0bd82a1SJustin Hibbits 				arg -= inreg;
394f0bd82a1SJustin Hibbits 			}
395f0bd82a1SJustin Hibbits 			goto load;
396f0bd82a1SJustin Hibbits 		}
397f0bd82a1SJustin Hibbits 
398f0bd82a1SJustin Hibbits 	}
399f0bd82a1SJustin Hibbits 
400f0bd82a1SJustin Hibbits 	/*
401f0bd82a1SJustin Hibbits 	 * We know that we did not come through a trap to get into
402f0bd82a1SJustin Hibbits 	 * dtrace_probe() -- the provider simply called dtrace_probe()
403f0bd82a1SJustin Hibbits 	 * directly.  As this is the case, we need to shift the argument
404f0bd82a1SJustin Hibbits 	 * that we're looking for:  the probe ID is the first argument to
405f0bd82a1SJustin Hibbits 	 * dtrace_probe(), so the argument n will actually be found where
406f0bd82a1SJustin Hibbits 	 * one would expect to find argument (n + 1).
407f0bd82a1SJustin Hibbits 	 */
408f0bd82a1SJustin Hibbits 	arg++;
409f0bd82a1SJustin Hibbits 
410f0bd82a1SJustin Hibbits 	if (arg <= inreg) {
411f0bd82a1SJustin Hibbits 		/*
412f0bd82a1SJustin Hibbits 		 * This shouldn't happen.  If the argument is passed in a
413f0bd82a1SJustin Hibbits 		 * register then it should have been, well, passed in a
414f0bd82a1SJustin Hibbits 		 * register...
415f0bd82a1SJustin Hibbits 		 */
416f0bd82a1SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
417c7570492SJustin Hibbits 		return (0);
418c7570492SJustin Hibbits 	}
419c7570492SJustin Hibbits 
420f0bd82a1SJustin Hibbits 	arg -= (inreg + 1);
421f0bd82a1SJustin Hibbits 	stack = fp + 2;
422c7570492SJustin Hibbits 
423f0bd82a1SJustin Hibbits load:
424f0bd82a1SJustin Hibbits 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
425f0bd82a1SJustin Hibbits 	val = stack[arg];
426f0bd82a1SJustin Hibbits 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
427c7570492SJustin Hibbits 
428f0bd82a1SJustin Hibbits 	return (val);
429f0bd82a1SJustin Hibbits 	return (0);
430c7570492SJustin Hibbits }
431c7570492SJustin Hibbits 
432c7570492SJustin Hibbits int
433c7570492SJustin Hibbits dtrace_getstackdepth(int aframes)
434c7570492SJustin Hibbits {
435c7570492SJustin Hibbits 	int depth = 0;
436c7570492SJustin Hibbits 	register_t sp;
437c7570492SJustin Hibbits 
438c7570492SJustin Hibbits 	aframes++;
439c7570492SJustin Hibbits 	sp = dtrace_getfp();
440c7570492SJustin Hibbits 	depth++;
441c7570492SJustin Hibbits 	for(;;) {
442c7570492SJustin Hibbits 		if (!INKERNEL((long) sp))
443c7570492SJustin Hibbits 			break;
444c7570492SJustin Hibbits 		if (!INKERNEL((long) *(void **)sp))
445c7570492SJustin Hibbits 			break;
446c7570492SJustin Hibbits 		depth++;
447c7570492SJustin Hibbits 		sp = *(uintptr_t *)sp;
448c7570492SJustin Hibbits 	}
449c7570492SJustin Hibbits 	if (depth < aframes)
450c7570492SJustin Hibbits 		return 0;
451c7570492SJustin Hibbits 	else
452c7570492SJustin Hibbits 		return depth - aframes;
453c7570492SJustin Hibbits }
454c7570492SJustin Hibbits 
455c7570492SJustin Hibbits ulong_t
456c7570492SJustin Hibbits dtrace_getreg(struct trapframe *rp, uint_t reg)
457c7570492SJustin Hibbits {
458c7570492SJustin Hibbits 	if (reg < 32)
459c7570492SJustin Hibbits 		return (rp->fixreg[reg]);
460c7570492SJustin Hibbits 
461c7570492SJustin Hibbits 	switch (reg) {
462c7570492SJustin Hibbits 	case 33:
463c7570492SJustin Hibbits 		return (rp->lr);
464c7570492SJustin Hibbits 	case 34:
465c7570492SJustin Hibbits 		return (rp->cr);
466c7570492SJustin Hibbits 	case 35:
467c7570492SJustin Hibbits 		return (rp->xer);
468c7570492SJustin Hibbits 	case 36:
469c7570492SJustin Hibbits 		return (rp->ctr);
470c7570492SJustin Hibbits 	case 37:
471c7570492SJustin Hibbits 		return (rp->srr0);
472c7570492SJustin Hibbits 	case 38:
473c7570492SJustin Hibbits 		return (rp->srr1);
474c7570492SJustin Hibbits 	case 39:
475c7570492SJustin Hibbits 		return (rp->exc);
476c7570492SJustin Hibbits 	default:
477c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
478c7570492SJustin Hibbits 		return (0);
479c7570492SJustin Hibbits 	}
480c7570492SJustin Hibbits }
481c7570492SJustin Hibbits 
482c7570492SJustin Hibbits static int
483c7570492SJustin Hibbits dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
484c7570492SJustin Hibbits {
485c7570492SJustin Hibbits 	ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
486c7570492SJustin Hibbits 
487c7570492SJustin Hibbits 	if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
488c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
489c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
490c7570492SJustin Hibbits 		return (0);
491c7570492SJustin Hibbits 	}
492c7570492SJustin Hibbits 
493c7570492SJustin Hibbits 	return (1);
494c7570492SJustin Hibbits }
495c7570492SJustin Hibbits 
496c7570492SJustin Hibbits void
497c7570492SJustin Hibbits dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
498c7570492SJustin Hibbits     volatile uint16_t *flags)
499c7570492SJustin Hibbits {
500c7570492SJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size))
5017e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)kaddr, size)) {
5027e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
5037e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
5047e7a9efdSJustin Hibbits 		}
505c7570492SJustin Hibbits }
506c7570492SJustin Hibbits 
507c7570492SJustin Hibbits void
508c7570492SJustin Hibbits dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
509c7570492SJustin Hibbits     volatile uint16_t *flags)
510c7570492SJustin Hibbits {
5117e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
5127e7a9efdSJustin Hibbits 		if (copyout((const void *)kaddr, (void *)uaddr, size)) {
5137e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
5147e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
5157e7a9efdSJustin Hibbits 		}
5167e7a9efdSJustin Hibbits 	}
517c7570492SJustin Hibbits }
518c7570492SJustin Hibbits 
519c7570492SJustin Hibbits void
520c7570492SJustin Hibbits dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
521c7570492SJustin Hibbits     volatile uint16_t *flags)
522c7570492SJustin Hibbits {
5237e7a9efdSJustin Hibbits 	size_t actual;
5247e7a9efdSJustin Hibbits 	int    error;
5257e7a9efdSJustin Hibbits 
5267e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
5277e7a9efdSJustin Hibbits 		error = copyinstr((const void *)uaddr, (void *)kaddr,
5287e7a9efdSJustin Hibbits 		    size, &actual);
5297e7a9efdSJustin Hibbits 
5307e7a9efdSJustin Hibbits 		/* ENAMETOOLONG is not a fault condition. */
5317e7a9efdSJustin Hibbits 		if (error && error != ENAMETOOLONG) {
5327e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
5337e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
5347e7a9efdSJustin Hibbits 		}
5357e7a9efdSJustin Hibbits 	}
536c7570492SJustin Hibbits }
537c7570492SJustin Hibbits 
5387e7a9efdSJustin Hibbits /*
5397e7a9efdSJustin Hibbits  * The bulk of this function could be replaced to match dtrace_copyinstr()
5407e7a9efdSJustin Hibbits  * if we ever implement a copyoutstr().
5417e7a9efdSJustin Hibbits  */
542c7570492SJustin Hibbits void
543c7570492SJustin Hibbits dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
544c7570492SJustin Hibbits     volatile uint16_t *flags)
545c7570492SJustin Hibbits {
5467e7a9efdSJustin Hibbits 	size_t len;
5477e7a9efdSJustin Hibbits 
5487e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
5497e7a9efdSJustin Hibbits 		len = strlen((const char *)kaddr);
5507e7a9efdSJustin Hibbits 		if (len > size)
5517e7a9efdSJustin Hibbits 			len = size;
5527e7a9efdSJustin Hibbits 
5537e7a9efdSJustin Hibbits 		if (copyout((const void *)kaddr, (void *)uaddr, len)) {
5547e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
5557e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
5567e7a9efdSJustin Hibbits 		}
5577e7a9efdSJustin Hibbits 	}
558c7570492SJustin Hibbits }
559c7570492SJustin Hibbits 
560c7570492SJustin Hibbits uint8_t
561c7570492SJustin Hibbits dtrace_fuword8(void *uaddr)
562c7570492SJustin Hibbits {
563c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
564c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
565c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
566c7570492SJustin Hibbits 		return (0);
567c7570492SJustin Hibbits 	}
5687e7a9efdSJustin Hibbits 	return (fubyte(uaddr));
569c7570492SJustin Hibbits }
570c7570492SJustin Hibbits 
571c7570492SJustin Hibbits uint16_t
572c7570492SJustin Hibbits dtrace_fuword16(void *uaddr)
573c7570492SJustin Hibbits {
5747e7a9efdSJustin Hibbits 	uint16_t ret = 0;
5757e7a9efdSJustin Hibbits 
5767e7a9efdSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
5777e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
578c7570492SJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
579c7570492SJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
580c7570492SJustin Hibbits 		}
5817e7a9efdSJustin Hibbits 	}
5827e7a9efdSJustin Hibbits 	return ret;
583c7570492SJustin Hibbits }
584c7570492SJustin Hibbits 
585c7570492SJustin Hibbits uint32_t
586c7570492SJustin Hibbits dtrace_fuword32(void *uaddr)
587c7570492SJustin Hibbits {
588c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
589c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
590c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
591c7570492SJustin Hibbits 		return (0);
592c7570492SJustin Hibbits 	}
5937e7a9efdSJustin Hibbits 	return (fuword32(uaddr));
594c7570492SJustin Hibbits }
595c7570492SJustin Hibbits 
596c7570492SJustin Hibbits uint64_t
597c7570492SJustin Hibbits dtrace_fuword64(void *uaddr)
598c7570492SJustin Hibbits {
5997e7a9efdSJustin Hibbits 	uint64_t ret = 0;
6007e7a9efdSJustin Hibbits 
6017e7a9efdSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
6027e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
603c7570492SJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
604c7570492SJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
605c7570492SJustin Hibbits 		}
6067e7a9efdSJustin Hibbits 	}
6077e7a9efdSJustin Hibbits 	return ret;
608c7570492SJustin Hibbits }
60980a5635cSJustin Hibbits 
61080a5635cSJustin Hibbits uintptr_t
61180a5635cSJustin Hibbits dtrace_fulword(void *uaddr)
61280a5635cSJustin Hibbits {
61380a5635cSJustin Hibbits 	uintptr_t ret = 0;
61480a5635cSJustin Hibbits 
61580a5635cSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
61680a5635cSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
61780a5635cSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
61880a5635cSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
61980a5635cSJustin Hibbits 		}
62080a5635cSJustin Hibbits 	}
62180a5635cSJustin Hibbits 	return ret;
62280a5635cSJustin Hibbits }
623