xref: /freebsd/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c (revision d69b94bab0e2a72c62747c188e9df7170824c034)
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 
64*d69b94baSJustin Hibbits #define INKERNEL(x)	(((x) <= VM_MAX_KERNEL_ADDRESS && \
65*d69b94baSJustin Hibbits 		(x) >= VM_MIN_KERNEL_ADDRESS) || \
66*d69b94baSJustin Hibbits 		(PMAP_HAS_DMAP && (x) >= DMAP_BASE_ADDRESS && \
67*d69b94baSJustin Hibbits 		 (x) <= DMAP_MAX_ADDRESS))
68c7570492SJustin Hibbits 
69e40a5cd3SJustin Hibbits static __inline int
70675cad71SJustin Hibbits dtrace_sp_inkernel(uintptr_t sp)
71e40a5cd3SJustin Hibbits {
72675cad71SJustin Hibbits 	struct trapframe *frame;
73e40a5cd3SJustin Hibbits 	vm_offset_t callpc;
74e40a5cd3SJustin Hibbits 
75*d69b94baSJustin Hibbits 	/* Not within the kernel, or not aligned. */
76*d69b94baSJustin Hibbits 	if (!INKERNEL(sp) || (sp & 0xf) != 0)
77*d69b94baSJustin Hibbits 		return (0);
78e40a5cd3SJustin Hibbits #ifdef __powerpc64__
79e40a5cd3SJustin Hibbits 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
80e40a5cd3SJustin Hibbits #else
81e40a5cd3SJustin Hibbits 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
82e40a5cd3SJustin Hibbits #endif
83e40a5cd3SJustin Hibbits 	if ((callpc & 3) || (callpc < 0x100))
84e40a5cd3SJustin Hibbits 		return (0);
85e40a5cd3SJustin Hibbits 
86e40a5cd3SJustin Hibbits 	/*
87e40a5cd3SJustin Hibbits 	 * trapexit() and asttrapexit() are sentinels
88e40a5cd3SJustin Hibbits 	 * for kernel stack tracing.
89e40a5cd3SJustin Hibbits 	 */
90675cad71SJustin Hibbits 	if (callpc + OFFSET == (vm_offset_t) &trapexit ||
91675cad71SJustin Hibbits 	    callpc + OFFSET == (vm_offset_t) &asttrapexit) {
92675cad71SJustin Hibbits 		frame = (struct trapframe *)(sp + FRAME_OFFSET);
93675cad71SJustin Hibbits 
94675cad71SJustin Hibbits 		return ((frame->srr1 & PSL_PR) == 0);
95675cad71SJustin Hibbits 	}
96e40a5cd3SJustin Hibbits 
97e40a5cd3SJustin Hibbits 	return (1);
98e40a5cd3SJustin Hibbits }
99e40a5cd3SJustin Hibbits 
100e9aae349SJustin Hibbits static __inline void
101e9aae349SJustin Hibbits dtrace_next_sp_pc(uintptr_t sp, uintptr_t *nsp, uintptr_t *pc)
102e40a5cd3SJustin Hibbits {
103e40a5cd3SJustin Hibbits 	vm_offset_t callpc;
104675cad71SJustin Hibbits 	struct trapframe *frame;
105e40a5cd3SJustin Hibbits 
106e40a5cd3SJustin Hibbits #ifdef __powerpc64__
107e40a5cd3SJustin Hibbits 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64);
108e40a5cd3SJustin Hibbits #else
109e40a5cd3SJustin Hibbits 	callpc = *(vm_offset_t *)(sp + RETURN_OFFSET);
110e40a5cd3SJustin Hibbits #endif
111e40a5cd3SJustin Hibbits 
112e40a5cd3SJustin Hibbits 	/*
113e40a5cd3SJustin Hibbits 	 * trapexit() and asttrapexit() are sentinels
114e40a5cd3SJustin Hibbits 	 * for kernel stack tracing.
115e40a5cd3SJustin Hibbits 	 */
116e40a5cd3SJustin Hibbits 	if ((callpc + OFFSET == (vm_offset_t) &trapexit ||
117675cad71SJustin Hibbits 	    callpc + OFFSET == (vm_offset_t) &asttrapexit)) {
118e40a5cd3SJustin Hibbits 		/* Access the trap frame */
119675cad71SJustin Hibbits 		frame = (struct trapframe *)(sp + FRAME_OFFSET);
120e9aae349SJustin Hibbits 
121e9aae349SJustin Hibbits 		if (nsp != NULL)
122e9aae349SJustin Hibbits 			*nsp = frame->fixreg[1];
123e9aae349SJustin Hibbits 		if (pc != NULL)
124e9aae349SJustin Hibbits 			*pc = frame->srr0;
125*d69b94baSJustin Hibbits 		return;
126675cad71SJustin Hibbits 	}
127e40a5cd3SJustin Hibbits 
128e9aae349SJustin Hibbits 	if (nsp != NULL)
129e9aae349SJustin Hibbits 		*nsp = *(uintptr_t *)sp;
130e9aae349SJustin Hibbits 	if (pc != NULL)
131e9aae349SJustin Hibbits 		*pc = callpc;
132e40a5cd3SJustin Hibbits }
133e40a5cd3SJustin Hibbits 
134c7570492SJustin Hibbits void
135c7570492SJustin Hibbits dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
136c7570492SJustin Hibbits     uint32_t *intrpc)
137c7570492SJustin Hibbits {
138c7570492SJustin Hibbits 	int depth = 0;
139e40a5cd3SJustin Hibbits 	uintptr_t osp, sp;
140c7570492SJustin Hibbits 	vm_offset_t callpc;
141c7570492SJustin Hibbits 	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
142c7570492SJustin Hibbits 
143e40a5cd3SJustin Hibbits 	osp = PAGE_SIZE;
144c7570492SJustin Hibbits 	if (intrpc != 0)
145c7570492SJustin Hibbits 		pcstack[depth++] = (pc_t) intrpc;
146c7570492SJustin Hibbits 
147c7570492SJustin Hibbits 	aframes++;
148c7570492SJustin Hibbits 
149*d69b94baSJustin Hibbits 	sp = (uintptr_t)__builtin_frame_address(0);
150c7570492SJustin Hibbits 
151c7570492SJustin Hibbits 	while (depth < pcstack_limit) {
152e40a5cd3SJustin Hibbits 		if (sp <= osp)
153c7570492SJustin Hibbits 			break;
154c7570492SJustin Hibbits 
155675cad71SJustin Hibbits 		if (!dtrace_sp_inkernel(sp))
156c7570492SJustin Hibbits 			break;
157e9aae349SJustin Hibbits 		osp = sp;
158e9aae349SJustin Hibbits 		dtrace_next_sp_pc(osp, &sp, &callpc);
159c7570492SJustin Hibbits 
160c7570492SJustin Hibbits 		if (aframes > 0) {
161c7570492SJustin Hibbits 			aframes--;
162c7570492SJustin Hibbits 			if ((aframes == 0) && (caller != 0)) {
163c7570492SJustin Hibbits 				pcstack[depth++] = caller;
164c7570492SJustin Hibbits 			}
165c7570492SJustin Hibbits 		}
166c7570492SJustin Hibbits 		else {
167c7570492SJustin Hibbits 			pcstack[depth++] = callpc;
168c7570492SJustin Hibbits 		}
169c7570492SJustin Hibbits 	}
170c7570492SJustin Hibbits 
171c7570492SJustin Hibbits 	for (; depth < pcstack_limit; depth++) {
172c7570492SJustin Hibbits 		pcstack[depth] = 0;
173c7570492SJustin Hibbits 	}
174c7570492SJustin Hibbits }
175c7570492SJustin Hibbits 
176c7570492SJustin Hibbits static int
177c7570492SJustin Hibbits dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
178c7570492SJustin Hibbits     uintptr_t sp)
179c7570492SJustin Hibbits {
180c7570492SJustin Hibbits 	proc_t *p = curproc;
181c7570492SJustin Hibbits 	int ret = 0;
182c7570492SJustin Hibbits 
183c7570492SJustin Hibbits 	ASSERT(pcstack == NULL || pcstack_limit > 0);
184c7570492SJustin Hibbits 
185c7570492SJustin Hibbits 	while (pc != 0) {
186c7570492SJustin Hibbits 		ret++;
187c7570492SJustin Hibbits 		if (pcstack != NULL) {
188c7570492SJustin Hibbits 			*pcstack++ = (uint64_t)pc;
189c7570492SJustin Hibbits 			pcstack_limit--;
190c7570492SJustin Hibbits 			if (pcstack_limit <= 0)
191c7570492SJustin Hibbits 				break;
192c7570492SJustin Hibbits 		}
193c7570492SJustin Hibbits 
194c7570492SJustin Hibbits 		if (sp == 0)
195c7570492SJustin Hibbits 			break;
196c7570492SJustin Hibbits 
197c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
198c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
199c7570492SJustin Hibbits 			sp = dtrace_fuword32((void *)sp);
200c7570492SJustin Hibbits 		}
201c7570492SJustin Hibbits 		else {
202c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
203c7570492SJustin Hibbits 			sp = dtrace_fuword64((void *)sp);
204c7570492SJustin Hibbits 		}
205c7570492SJustin Hibbits 	}
206c7570492SJustin Hibbits 
207c7570492SJustin Hibbits 	return (ret);
208c7570492SJustin Hibbits }
209c7570492SJustin Hibbits 
210c7570492SJustin Hibbits void
211c7570492SJustin Hibbits dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
212c7570492SJustin Hibbits {
213c7570492SJustin Hibbits 	proc_t *p = curproc;
214c7570492SJustin Hibbits 	struct trapframe *tf;
215c7570492SJustin Hibbits 	uintptr_t pc, sp;
216c7570492SJustin Hibbits 	volatile uint16_t *flags =
217c7570492SJustin Hibbits 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
218c7570492SJustin Hibbits 	int n;
219c7570492SJustin Hibbits 
220c7570492SJustin Hibbits 	if (*flags & CPU_DTRACE_FAULT)
221c7570492SJustin Hibbits 		return;
222c7570492SJustin Hibbits 
223c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
224c7570492SJustin Hibbits 		return;
225c7570492SJustin Hibbits 
226c7570492SJustin Hibbits 	/*
227c7570492SJustin Hibbits 	 * If there's no user context we still need to zero the stack.
228c7570492SJustin Hibbits 	 */
229c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
230c7570492SJustin Hibbits 		goto zero;
231c7570492SJustin Hibbits 
232c7570492SJustin Hibbits 	*pcstack++ = (uint64_t)p->p_pid;
233c7570492SJustin Hibbits 	pcstack_limit--;
234c7570492SJustin Hibbits 
235c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
236c7570492SJustin Hibbits 		return;
237c7570492SJustin Hibbits 
238c7570492SJustin Hibbits 	pc = tf->srr0;
239c7570492SJustin Hibbits 	sp = tf->fixreg[1];
240c7570492SJustin Hibbits 
241c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
242c7570492SJustin Hibbits 		/*
243c7570492SJustin Hibbits 		 * In an entry probe.  The frame pointer has not yet been
244c7570492SJustin Hibbits 		 * pushed (that happens in the function prologue).  The
245c7570492SJustin Hibbits 		 * best approach is to add the current pc as a missing top
246c7570492SJustin Hibbits 		 * of stack and back the pc up to the caller, which is stored
247c7570492SJustin Hibbits 		 * at the current stack pointer address since the call
248c7570492SJustin Hibbits 		 * instruction puts it there right before the branch.
249c7570492SJustin Hibbits 		 */
250c7570492SJustin Hibbits 
251c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
252c7570492SJustin Hibbits 		pcstack_limit--;
253c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
254c7570492SJustin Hibbits 			return;
255c7570492SJustin Hibbits 
256c7570492SJustin Hibbits 		pc = tf->lr;
257c7570492SJustin Hibbits 	}
258c7570492SJustin Hibbits 
259c7570492SJustin Hibbits 	n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
260c7570492SJustin Hibbits 	ASSERT(n >= 0);
261c7570492SJustin Hibbits 	ASSERT(n <= pcstack_limit);
262c7570492SJustin Hibbits 
263c7570492SJustin Hibbits 	pcstack += n;
264c7570492SJustin Hibbits 	pcstack_limit -= n;
265c7570492SJustin Hibbits 
266c7570492SJustin Hibbits zero:
267c7570492SJustin Hibbits 	while (pcstack_limit-- > 0)
268c7570492SJustin Hibbits 		*pcstack++ = 0;
269c7570492SJustin Hibbits }
270c7570492SJustin Hibbits 
271c7570492SJustin Hibbits int
272c7570492SJustin Hibbits dtrace_getustackdepth(void)
273c7570492SJustin Hibbits {
274c7570492SJustin Hibbits 	proc_t *p = curproc;
275c7570492SJustin Hibbits 	struct trapframe *tf;
276c7570492SJustin Hibbits 	uintptr_t pc, sp;
277c7570492SJustin Hibbits 	int n = 0;
278c7570492SJustin Hibbits 
279c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
280c7570492SJustin Hibbits 		return (0);
281c7570492SJustin Hibbits 
282c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
283c7570492SJustin Hibbits 		return (-1);
284c7570492SJustin Hibbits 
285c7570492SJustin Hibbits 	pc = tf->srr0;
286c7570492SJustin Hibbits 	sp = tf->fixreg[1];
287c7570492SJustin Hibbits 
288c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
289c7570492SJustin Hibbits 		/*
290c7570492SJustin Hibbits 		 * In an entry probe.  The frame pointer has not yet been
291c7570492SJustin Hibbits 		 * pushed (that happens in the function prologue).  The
292c7570492SJustin Hibbits 		 * best approach is to add the current pc as a missing top
293c7570492SJustin Hibbits 		 * of stack and back the pc up to the caller, which is stored
294c7570492SJustin Hibbits 		 * at the current stack pointer address since the call
295c7570492SJustin Hibbits 		 * instruction puts it there right before the branch.
296c7570492SJustin Hibbits 		 */
297c7570492SJustin Hibbits 
298c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
299c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *) sp);
300c7570492SJustin Hibbits 		}
301c7570492SJustin Hibbits 		else
302c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *) sp);
303c7570492SJustin Hibbits 		n++;
304c7570492SJustin Hibbits 	}
305c7570492SJustin Hibbits 
306c7570492SJustin Hibbits 	n += dtrace_getustack_common(NULL, 0, pc, sp);
307c7570492SJustin Hibbits 
308c7570492SJustin Hibbits 	return (n);
309c7570492SJustin Hibbits }
310c7570492SJustin Hibbits 
311c7570492SJustin Hibbits void
312c7570492SJustin Hibbits dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
313c7570492SJustin Hibbits {
314c7570492SJustin Hibbits 	proc_t *p = curproc;
315c7570492SJustin Hibbits 	struct trapframe *tf;
316c7570492SJustin Hibbits 	uintptr_t pc, sp;
317c7570492SJustin Hibbits 	volatile uint16_t *flags =
318c7570492SJustin Hibbits 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
319c7570492SJustin Hibbits #ifdef notyet	/* XXX signal stack */
320c7570492SJustin Hibbits 	uintptr_t oldcontext;
321c7570492SJustin Hibbits 	size_t s1, s2;
322c7570492SJustin Hibbits #endif
323c7570492SJustin Hibbits 
324c7570492SJustin Hibbits 	if (*flags & CPU_DTRACE_FAULT)
325c7570492SJustin Hibbits 		return;
326c7570492SJustin Hibbits 
327c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
328c7570492SJustin Hibbits 		return;
329c7570492SJustin Hibbits 
330c7570492SJustin Hibbits 	/*
331c7570492SJustin Hibbits 	 * If there's no user context we still need to zero the stack.
332c7570492SJustin Hibbits 	 */
333c7570492SJustin Hibbits 	if (p == NULL || (tf = curthread->td_frame) == NULL)
334c7570492SJustin Hibbits 		goto zero;
335c7570492SJustin Hibbits 
336c7570492SJustin Hibbits 	*pcstack++ = (uint64_t)p->p_pid;
337c7570492SJustin Hibbits 	pcstack_limit--;
338c7570492SJustin Hibbits 
339c7570492SJustin Hibbits 	if (pcstack_limit <= 0)
340c7570492SJustin Hibbits 		return;
341c7570492SJustin Hibbits 
342c7570492SJustin Hibbits 	pc = tf->srr0;
343c7570492SJustin Hibbits 	sp = tf->fixreg[1];
344c7570492SJustin Hibbits 
345c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */
346c7570492SJustin Hibbits 	oldcontext = lwp->lwp_oldcontext;
347c7570492SJustin Hibbits 	s1 = sizeof (struct xframe) + 2 * sizeof (long);
348c7570492SJustin Hibbits 	s2 = s1 + sizeof (siginfo_t);
349c7570492SJustin Hibbits #endif
350c7570492SJustin Hibbits 
351c7570492SJustin Hibbits 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
352c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
353c7570492SJustin Hibbits 		*fpstack++ = 0;
354c7570492SJustin Hibbits 		pcstack_limit--;
355c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
356c7570492SJustin Hibbits 			return;
357c7570492SJustin Hibbits 
358c7570492SJustin Hibbits 		if (SV_PROC_FLAG(p, SV_ILP32)) {
359c7570492SJustin Hibbits 			pc = dtrace_fuword32((void *)sp);
360c7570492SJustin Hibbits 		}
361c7570492SJustin Hibbits 		else {
362c7570492SJustin Hibbits 			pc = dtrace_fuword64((void *)sp);
363c7570492SJustin Hibbits 		}
364c7570492SJustin Hibbits 	}
365c7570492SJustin Hibbits 
366c7570492SJustin Hibbits 	while (pc != 0) {
367c7570492SJustin Hibbits 		*pcstack++ = (uint64_t)pc;
368c7570492SJustin Hibbits 		*fpstack++ = sp;
369c7570492SJustin Hibbits 		pcstack_limit--;
370c7570492SJustin Hibbits 		if (pcstack_limit <= 0)
371c7570492SJustin Hibbits 			break;
372c7570492SJustin Hibbits 
373c7570492SJustin Hibbits 		if (sp == 0)
374c7570492SJustin Hibbits 			break;
375c7570492SJustin Hibbits 
376c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */
377c7570492SJustin Hibbits 		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
378c7570492SJustin Hibbits 			ucontext_t *ucp = (ucontext_t *)oldcontext;
379c7570492SJustin Hibbits 			greg_t *gregs = ucp->uc_mcontext.gregs;
380c7570492SJustin Hibbits 
381c7570492SJustin Hibbits 			sp = dtrace_fulword(&gregs[REG_FP]);
382c7570492SJustin Hibbits 			pc = dtrace_fulword(&gregs[REG_PC]);
383c7570492SJustin Hibbits 
384c7570492SJustin Hibbits 			oldcontext = dtrace_fulword(&ucp->uc_link);
385c7570492SJustin Hibbits 		} else
386c7570492SJustin Hibbits #endif /* XXX */
387c7570492SJustin Hibbits 		{
388c7570492SJustin Hibbits 			if (SV_PROC_FLAG(p, SV_ILP32)) {
389c7570492SJustin Hibbits 				pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET));
390c7570492SJustin Hibbits 				sp = dtrace_fuword32((void *)sp);
391c7570492SJustin Hibbits 			}
392c7570492SJustin Hibbits 			else {
393c7570492SJustin Hibbits 				pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64));
394c7570492SJustin Hibbits 				sp = dtrace_fuword64((void *)sp);
395c7570492SJustin Hibbits 			}
396c7570492SJustin Hibbits 		}
397c7570492SJustin Hibbits 
398c7570492SJustin Hibbits 		/*
399c7570492SJustin Hibbits 		 * This is totally bogus:  if we faulted, we're going to clear
400c7570492SJustin Hibbits 		 * the fault and break.  This is to deal with the apparently
401c7570492SJustin Hibbits 		 * broken Java stacks on x86.
402c7570492SJustin Hibbits 		 */
403c7570492SJustin Hibbits 		if (*flags & CPU_DTRACE_FAULT) {
404c7570492SJustin Hibbits 			*flags &= ~CPU_DTRACE_FAULT;
405c7570492SJustin Hibbits 			break;
406c7570492SJustin Hibbits 		}
407c7570492SJustin Hibbits 	}
408c7570492SJustin Hibbits 
409c7570492SJustin Hibbits zero:
410c7570492SJustin Hibbits 	while (pcstack_limit-- > 0)
411c7570492SJustin Hibbits 		*pcstack++ = 0;
412c7570492SJustin Hibbits }
413c7570492SJustin Hibbits 
414c7570492SJustin Hibbits /*ARGSUSED*/
415c7570492SJustin Hibbits uint64_t
416c7570492SJustin Hibbits dtrace_getarg(int arg, int aframes)
417c7570492SJustin Hibbits {
418f0bd82a1SJustin Hibbits 	uintptr_t val;
419*d69b94baSJustin Hibbits 	uintptr_t *fp = (uintptr_t *)__builtin_frame_address(0);
420f0bd82a1SJustin Hibbits 	uintptr_t *stack;
421f0bd82a1SJustin Hibbits 	int i;
422f0bd82a1SJustin Hibbits 
423f0bd82a1SJustin Hibbits 	/*
424f0bd82a1SJustin Hibbits 	 * A total of 8 arguments are passed via registers; any argument with
425f0bd82a1SJustin Hibbits 	 * index of 7 or lower is therefore in a register.
426f0bd82a1SJustin Hibbits 	 */
427f0bd82a1SJustin Hibbits 	int inreg = 7;
428f0bd82a1SJustin Hibbits 
429f0bd82a1SJustin Hibbits 	for (i = 1; i <= aframes; i++) {
430f0bd82a1SJustin Hibbits 		fp = (uintptr_t *)*fp;
431f0bd82a1SJustin Hibbits 
432f0bd82a1SJustin Hibbits 		/*
433*d69b94baSJustin Hibbits 		 * On ppc32 trapexit() is the immediately following label.  On
434*d69b94baSJustin Hibbits 		 * ppc64 AIM trapexit() follows a nop.
435f0bd82a1SJustin Hibbits 		 */
436e40a5cd3SJustin Hibbits #ifdef __powerpc64__
437e40a5cd3SJustin Hibbits 		if ((long)(fp[2]) + 4 == (long)trapexit) {
438e40a5cd3SJustin Hibbits #else
439e40a5cd3SJustin Hibbits 		if ((long)(fp[1]) == (long)trapexit) {
440e40a5cd3SJustin Hibbits #endif
441f0bd82a1SJustin Hibbits 			/*
442f0bd82a1SJustin Hibbits 			 * In the case of powerpc, we will use the pointer to the regs
443f0bd82a1SJustin Hibbits 			 * structure that was pushed when we took the trap.  To get this
444f0bd82a1SJustin Hibbits 			 * structure, we must increment beyond the frame structure.  If the
445f0bd82a1SJustin Hibbits 			 * argument that we're seeking is passed on the stack, we'll pull
446f0bd82a1SJustin Hibbits 			 * the true stack pointer out of the saved registers and decrement
447f0bd82a1SJustin Hibbits 			 * our argument by the number of arguments passed in registers; if
448f0bd82a1SJustin Hibbits 			 * the argument we're seeking is passed in regsiters, we can just
449f0bd82a1SJustin Hibbits 			 * load it directly.
450f0bd82a1SJustin Hibbits 			 */
451f0bd82a1SJustin Hibbits #ifdef __powerpc64__
452f0bd82a1SJustin Hibbits 			struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48);
453f0bd82a1SJustin Hibbits #else
454f0bd82a1SJustin Hibbits 			struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8);
455f0bd82a1SJustin Hibbits #endif
456f0bd82a1SJustin Hibbits 
457f0bd82a1SJustin Hibbits 			if (arg <= inreg) {
458f0bd82a1SJustin Hibbits 				stack = &rp->fixreg[3];
459f0bd82a1SJustin Hibbits 			} else {
460f0bd82a1SJustin Hibbits 				stack = (uintptr_t *)(rp->fixreg[1]);
461f0bd82a1SJustin Hibbits 				arg -= inreg;
462f0bd82a1SJustin Hibbits 			}
463f0bd82a1SJustin Hibbits 			goto load;
464f0bd82a1SJustin Hibbits 		}
465f0bd82a1SJustin Hibbits 
466f0bd82a1SJustin Hibbits 	}
467f0bd82a1SJustin Hibbits 
468f0bd82a1SJustin Hibbits 	/*
469f0bd82a1SJustin Hibbits 	 * We know that we did not come through a trap to get into
470f0bd82a1SJustin Hibbits 	 * dtrace_probe() -- the provider simply called dtrace_probe()
471f0bd82a1SJustin Hibbits 	 * directly.  As this is the case, we need to shift the argument
472f0bd82a1SJustin Hibbits 	 * that we're looking for:  the probe ID is the first argument to
473f0bd82a1SJustin Hibbits 	 * dtrace_probe(), so the argument n will actually be found where
474f0bd82a1SJustin Hibbits 	 * one would expect to find argument (n + 1).
475f0bd82a1SJustin Hibbits 	 */
476f0bd82a1SJustin Hibbits 	arg++;
477f0bd82a1SJustin Hibbits 
478f0bd82a1SJustin Hibbits 	if (arg <= inreg) {
479f0bd82a1SJustin Hibbits 		/*
480f0bd82a1SJustin Hibbits 		 * This shouldn't happen.  If the argument is passed in a
481f0bd82a1SJustin Hibbits 		 * register then it should have been, well, passed in a
482f0bd82a1SJustin Hibbits 		 * register...
483f0bd82a1SJustin Hibbits 		 */
484f0bd82a1SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
485c7570492SJustin Hibbits 		return (0);
486c7570492SJustin Hibbits 	}
487c7570492SJustin Hibbits 
488f0bd82a1SJustin Hibbits 	arg -= (inreg + 1);
489f0bd82a1SJustin Hibbits 	stack = fp + 2;
490c7570492SJustin Hibbits 
491f0bd82a1SJustin Hibbits load:
492f0bd82a1SJustin Hibbits 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
493f0bd82a1SJustin Hibbits 	val = stack[arg];
494f0bd82a1SJustin Hibbits 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
495c7570492SJustin Hibbits 
496f0bd82a1SJustin Hibbits 	return (val);
497c7570492SJustin Hibbits }
498c7570492SJustin Hibbits 
499c7570492SJustin Hibbits int
500c7570492SJustin Hibbits dtrace_getstackdepth(int aframes)
501c7570492SJustin Hibbits {
502c7570492SJustin Hibbits 	int depth = 0;
503e40a5cd3SJustin Hibbits 	uintptr_t osp, sp;
504e40a5cd3SJustin Hibbits 	vm_offset_t callpc;
505c7570492SJustin Hibbits 
506e40a5cd3SJustin Hibbits 	osp = PAGE_SIZE;
507*d69b94baSJustin Hibbits 	sp = (uintptr_t)__builtin_frame_address(0);
508c7570492SJustin Hibbits 	for(;;) {
509e40a5cd3SJustin Hibbits 		if (sp <= osp)
510c7570492SJustin Hibbits 			break;
511e40a5cd3SJustin Hibbits 
512675cad71SJustin Hibbits 		if (!dtrace_sp_inkernel(sp))
513c7570492SJustin Hibbits 			break;
514e40a5cd3SJustin Hibbits 
515c7570492SJustin Hibbits 		depth++;
516e40a5cd3SJustin Hibbits 		osp = sp;
517e9aae349SJustin Hibbits 		dtrace_next_sp_pc(sp, &sp, NULL);
518c7570492SJustin Hibbits 	}
519c7570492SJustin Hibbits 	if (depth < aframes)
520e40a5cd3SJustin Hibbits 		return (0);
521e40a5cd3SJustin Hibbits 
522*d69b94baSJustin Hibbits 	return (depth - aframes);
523c7570492SJustin Hibbits }
524c7570492SJustin Hibbits 
525c7570492SJustin Hibbits ulong_t
526c7570492SJustin Hibbits dtrace_getreg(struct trapframe *rp, uint_t reg)
527c7570492SJustin Hibbits {
528c7570492SJustin Hibbits 	if (reg < 32)
529c7570492SJustin Hibbits 		return (rp->fixreg[reg]);
530c7570492SJustin Hibbits 
531c7570492SJustin Hibbits 	switch (reg) {
5327f0df9acSJustin Hibbits 	case 32:
533c7570492SJustin Hibbits 		return (rp->lr);
5347f0df9acSJustin Hibbits 	case 33:
535c7570492SJustin Hibbits 		return (rp->cr);
5367f0df9acSJustin Hibbits 	case 34:
537c7570492SJustin Hibbits 		return (rp->xer);
5387f0df9acSJustin Hibbits 	case 35:
539c7570492SJustin Hibbits 		return (rp->ctr);
5407f0df9acSJustin Hibbits 	case 36:
541c7570492SJustin Hibbits 		return (rp->srr0);
5427f0df9acSJustin Hibbits 	case 37:
543c7570492SJustin Hibbits 		return (rp->srr1);
5447f0df9acSJustin Hibbits 	case 38:
545c7570492SJustin Hibbits 		return (rp->exc);
546c7570492SJustin Hibbits 	default:
547c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
548c7570492SJustin Hibbits 		return (0);
549c7570492SJustin Hibbits 	}
550c7570492SJustin Hibbits }
551c7570492SJustin Hibbits 
552c7570492SJustin Hibbits static int
553c7570492SJustin Hibbits dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
554c7570492SJustin Hibbits {
555c7570492SJustin Hibbits 	ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
556c7570492SJustin Hibbits 
557c7570492SJustin Hibbits 	if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
558c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
559c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
560c7570492SJustin Hibbits 		return (0);
561c7570492SJustin Hibbits 	}
562c7570492SJustin Hibbits 
563c7570492SJustin Hibbits 	return (1);
564c7570492SJustin Hibbits }
565c7570492SJustin Hibbits 
566c7570492SJustin Hibbits void
567c7570492SJustin Hibbits dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
568c7570492SJustin Hibbits     volatile uint16_t *flags)
569c7570492SJustin Hibbits {
570c7570492SJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size))
5717e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)kaddr, size)) {
5727e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
5737e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
5747e7a9efdSJustin Hibbits 		}
575c7570492SJustin Hibbits }
576c7570492SJustin Hibbits 
577c7570492SJustin Hibbits void
578c7570492SJustin Hibbits dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
579c7570492SJustin Hibbits     volatile uint16_t *flags)
580c7570492SJustin Hibbits {
5817e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
5827e7a9efdSJustin Hibbits 		if (copyout((const void *)kaddr, (void *)uaddr, size)) {
5837e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
5847e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
5857e7a9efdSJustin Hibbits 		}
5867e7a9efdSJustin Hibbits 	}
587c7570492SJustin Hibbits }
588c7570492SJustin Hibbits 
589c7570492SJustin Hibbits void
590c7570492SJustin Hibbits dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
591c7570492SJustin Hibbits     volatile uint16_t *flags)
592c7570492SJustin Hibbits {
5937e7a9efdSJustin Hibbits 	size_t actual;
5947e7a9efdSJustin Hibbits 	int    error;
5957e7a9efdSJustin Hibbits 
5967e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
5977e7a9efdSJustin Hibbits 		error = copyinstr((const void *)uaddr, (void *)kaddr,
5987e7a9efdSJustin Hibbits 		    size, &actual);
5997e7a9efdSJustin Hibbits 
6007e7a9efdSJustin Hibbits 		/* ENAMETOOLONG is not a fault condition. */
6017e7a9efdSJustin Hibbits 		if (error && error != ENAMETOOLONG) {
6027e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
6037e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
6047e7a9efdSJustin Hibbits 		}
6057e7a9efdSJustin Hibbits 	}
606c7570492SJustin Hibbits }
607c7570492SJustin Hibbits 
6087e7a9efdSJustin Hibbits /*
6097e7a9efdSJustin Hibbits  * The bulk of this function could be replaced to match dtrace_copyinstr()
6107e7a9efdSJustin Hibbits  * if we ever implement a copyoutstr().
6117e7a9efdSJustin Hibbits  */
612c7570492SJustin Hibbits void
613c7570492SJustin Hibbits dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
614c7570492SJustin Hibbits     volatile uint16_t *flags)
615c7570492SJustin Hibbits {
6167e7a9efdSJustin Hibbits 	size_t len;
6177e7a9efdSJustin Hibbits 
6187e7a9efdSJustin Hibbits 	if (dtrace_copycheck(uaddr, kaddr, size)) {
6197e7a9efdSJustin Hibbits 		len = strlen((const char *)kaddr);
6207e7a9efdSJustin Hibbits 		if (len > size)
6217e7a9efdSJustin Hibbits 			len = size;
6227e7a9efdSJustin Hibbits 
6237e7a9efdSJustin Hibbits 		if (copyout((const void *)kaddr, (void *)uaddr, len)) {
6247e7a9efdSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
6257e7a9efdSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
6267e7a9efdSJustin Hibbits 		}
6277e7a9efdSJustin Hibbits 	}
628c7570492SJustin Hibbits }
629c7570492SJustin Hibbits 
630c7570492SJustin Hibbits uint8_t
631c7570492SJustin Hibbits dtrace_fuword8(void *uaddr)
632c7570492SJustin Hibbits {
633c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
634c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
635c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
636c7570492SJustin Hibbits 		return (0);
637c7570492SJustin Hibbits 	}
6387e7a9efdSJustin Hibbits 	return (fubyte(uaddr));
639c7570492SJustin Hibbits }
640c7570492SJustin Hibbits 
641c7570492SJustin Hibbits uint16_t
642c7570492SJustin Hibbits dtrace_fuword16(void *uaddr)
643c7570492SJustin Hibbits {
6447e7a9efdSJustin Hibbits 	uint16_t ret = 0;
6457e7a9efdSJustin Hibbits 
6467e7a9efdSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
6477e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
648c7570492SJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
649c7570492SJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
650c7570492SJustin Hibbits 		}
6517e7a9efdSJustin Hibbits 	}
6527e7a9efdSJustin Hibbits 	return ret;
653c7570492SJustin Hibbits }
654c7570492SJustin Hibbits 
655c7570492SJustin Hibbits uint32_t
656c7570492SJustin Hibbits dtrace_fuword32(void *uaddr)
657c7570492SJustin Hibbits {
658c7570492SJustin Hibbits 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
659c7570492SJustin Hibbits 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
660c7570492SJustin Hibbits 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
661c7570492SJustin Hibbits 		return (0);
662c7570492SJustin Hibbits 	}
6637e7a9efdSJustin Hibbits 	return (fuword32(uaddr));
664c7570492SJustin Hibbits }
665c7570492SJustin Hibbits 
666c7570492SJustin Hibbits uint64_t
667c7570492SJustin Hibbits dtrace_fuword64(void *uaddr)
668c7570492SJustin Hibbits {
6697e7a9efdSJustin Hibbits 	uint64_t ret = 0;
6707e7a9efdSJustin Hibbits 
6717e7a9efdSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
6727e7a9efdSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
673c7570492SJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
674c7570492SJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
675c7570492SJustin Hibbits 		}
6767e7a9efdSJustin Hibbits 	}
6777e7a9efdSJustin Hibbits 	return ret;
678c7570492SJustin Hibbits }
67980a5635cSJustin Hibbits 
68080a5635cSJustin Hibbits uintptr_t
68180a5635cSJustin Hibbits dtrace_fulword(void *uaddr)
68280a5635cSJustin Hibbits {
68380a5635cSJustin Hibbits 	uintptr_t ret = 0;
68480a5635cSJustin Hibbits 
68580a5635cSJustin Hibbits 	if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) {
68680a5635cSJustin Hibbits 		if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) {
68780a5635cSJustin Hibbits 			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
68880a5635cSJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
68980a5635cSJustin Hibbits 		}
69080a5635cSJustin Hibbits 	}
69180a5635cSJustin Hibbits 	return ret;
69280a5635cSJustin Hibbits }
693