1*eada09acSchs /*	$NetBSD: dtrace_isa.c,v 1.6 2018/05/28 21:05:03 chs Exp $	*/
201c9547eSdarran 
3bb8023b5Sdarran /*
4bb8023b5Sdarran  * CDDL HEADER START
5bb8023b5Sdarran  *
6bb8023b5Sdarran  * The contents of this file are subject to the terms of the
7bb8023b5Sdarran  * Common Development and Distribution License, Version 1.0 only
8bb8023b5Sdarran  * (the "License").  You may not use this file except in compliance
9bb8023b5Sdarran  * with the License.
10bb8023b5Sdarran  *
11bb8023b5Sdarran  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
12bb8023b5Sdarran  * or http://www.opensolaris.org/os/licensing.
13bb8023b5Sdarran  * See the License for the specific language governing permissions
14bb8023b5Sdarran  * and limitations under the License.
15bb8023b5Sdarran  *
16bb8023b5Sdarran  * When distributing Covered Code, include this CDDL HEADER in each
17bb8023b5Sdarran  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
18bb8023b5Sdarran  * If applicable, add the following below this CDDL HEADER, with the
19bb8023b5Sdarran  * fields enclosed by brackets "[]" replaced with your own identifying
20bb8023b5Sdarran  * information: Portions Copyright [yyyy] [name of copyright owner]
21bb8023b5Sdarran  *
22bb8023b5Sdarran  * CDDL HEADER END
23bb8023b5Sdarran  *
24*eada09acSchs  * $FreeBSD: head/sys/cddl/dev/dtrace/i386/dtrace_isa.c 298171 2016-04-17 23:08:47Z markj $
25bb8023b5Sdarran  */
26bb8023b5Sdarran /*
27bb8023b5Sdarran  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28bb8023b5Sdarran  * Use is subject to license terms.
29bb8023b5Sdarran  */
30bb8023b5Sdarran #include <sys/cdefs.h>
31bb8023b5Sdarran 
32bb8023b5Sdarran #include <sys/param.h>
33bb8023b5Sdarran #include <sys/systm.h>
34bb8023b5Sdarran #include <sys/kernel.h>
35bb8023b5Sdarran 
3601c9547eSdarran #include <machine/vmparam.h>
3701c9547eSdarran #include <machine/pmap.h>
38bb8023b5Sdarran 
39*eada09acSchs #include "regset.h"
40*eada09acSchs 
4101c9547eSdarran uintptr_t kernelbase = (uintptr_t)KERNBASE;
42bb8023b5Sdarran 
4380dd0070Schs #define INKERNEL(va) \
4480dd0070Schs 	(((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS && \
45bb8023b5Sdarran 	 ((vm_offset_t)(va)) < VM_MAX_KERNEL_ADDRESS)
46bb8023b5Sdarran 
4701c9547eSdarran struct i386_frame {
4801c9547eSdarran 	struct i386_frame	*f_frame;
4901c9547eSdarran 	int			 f_retaddr;
5001c9547eSdarran };
5101c9547eSdarran 
5201c9547eSdarran typedef	unsigned long	vm_offset_t;
5301c9547eSdarran 
54bb8023b5Sdarran uint8_t dtrace_fuword8_nocheck(void *);
55bb8023b5Sdarran uint16_t dtrace_fuword16_nocheck(void *);
56bb8023b5Sdarran uint32_t dtrace_fuword32_nocheck(void *);
57bb8023b5Sdarran uint64_t dtrace_fuword64_nocheck(void *);
58bb8023b5Sdarran 
59*eada09acSchs int	dtrace_ustackdepth_max = 2048;
60*eada09acSchs 
61bb8023b5Sdarran void
dtrace_getpcstack(pc_t * pcstack,int pcstack_limit,int aframes,uint32_t * intrpc)62bb8023b5Sdarran dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
63bb8023b5Sdarran     uint32_t *intrpc)
64bb8023b5Sdarran {
65bb8023b5Sdarran 	int depth = 0;
66bb8023b5Sdarran 	register_t ebp;
67bb8023b5Sdarran 	struct i386_frame *frame;
68bb8023b5Sdarran 	vm_offset_t callpc;
6901c9547eSdarran 	pc_t caller = (pc_t) solaris_cpu[cpu_number()].cpu_dtrace_caller;
70bb8023b5Sdarran 
71bb8023b5Sdarran 	if (intrpc != 0)
72bb8023b5Sdarran 		pcstack[depth++] = (pc_t) intrpc;
73bb8023b5Sdarran 
74bb8023b5Sdarran 	aframes++;
75bb8023b5Sdarran 
76bb8023b5Sdarran 	__asm __volatile("movl %%ebp,%0" : "=r" (ebp));
77bb8023b5Sdarran 
78bb8023b5Sdarran 	frame = (struct i386_frame *)ebp;
79bb8023b5Sdarran 	while (depth < pcstack_limit) {
80bb8023b5Sdarran 		if (!INKERNEL(frame))
81bb8023b5Sdarran 			break;
82bb8023b5Sdarran 
83bb8023b5Sdarran 		callpc = frame->f_retaddr;
84bb8023b5Sdarran 
85bb8023b5Sdarran 		if (!INKERNEL(callpc))
86bb8023b5Sdarran 			break;
87bb8023b5Sdarran 
88bb8023b5Sdarran 		if (aframes > 0) {
89bb8023b5Sdarran 			aframes--;
90bb8023b5Sdarran 			if ((aframes == 0) && (caller != 0)) {
91bb8023b5Sdarran 				pcstack[depth++] = caller;
92bb8023b5Sdarran 			}
93bb8023b5Sdarran 		}
94bb8023b5Sdarran 		else {
95bb8023b5Sdarran 			pcstack[depth++] = callpc;
96bb8023b5Sdarran 		}
97bb8023b5Sdarran 
98bb8023b5Sdarran 		if (frame->f_frame <= frame ||
99bb8023b5Sdarran 		    (vm_offset_t)frame->f_frame >=
10001c9547eSdarran 		    (vm_offset_t)ebp + KSTACK_SIZE)
101bb8023b5Sdarran 			break;
102bb8023b5Sdarran 		frame = frame->f_frame;
103bb8023b5Sdarran 	}
104bb8023b5Sdarran 
105bb8023b5Sdarran 	for (; depth < pcstack_limit; depth++) {
106bb8023b5Sdarran 		pcstack[depth] = 0;
107bb8023b5Sdarran 	}
108bb8023b5Sdarran }
109bb8023b5Sdarran 
110bb8023b5Sdarran static int
dtrace_getustack_common(uint64_t * pcstack,int pcstack_limit,uintptr_t pc,uintptr_t sp)111bb8023b5Sdarran dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
112bb8023b5Sdarran     uintptr_t sp)
113bb8023b5Sdarran {
11480dd0070Schs #ifdef notyet
115bb8023b5Sdarran 	proc_t *p = curproc;
11680dd0070Schs 	uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */
11780dd0070Schs 	size_t s1, s2;
11880dd0070Schs #endif
119*eada09acSchs 	uintptr_t oldsp;
120bb8023b5Sdarran 	volatile uint16_t *flags =
12101c9547eSdarran 	    (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags;
122bb8023b5Sdarran 	int ret = 0;
123bb8023b5Sdarran 
124bb8023b5Sdarran 	ASSERT(pcstack == NULL || pcstack_limit > 0);
125*eada09acSchs 	ASSERT(dtrace_ustackdepth_max > 0);
126bb8023b5Sdarran 
12780dd0070Schs #ifdef notyet /* XXX signal stack. */
128bb8023b5Sdarran 	if (p->p_model == DATAMODEL_NATIVE) {
129bb8023b5Sdarran 		s1 = sizeof (struct frame) + 2 * sizeof (long);
130bb8023b5Sdarran 		s2 = s1 + sizeof (siginfo_t);
131bb8023b5Sdarran 	} else {
132bb8023b5Sdarran 		s1 = sizeof (struct frame32) + 3 * sizeof (int);
133bb8023b5Sdarran 		s2 = s1 + sizeof (siginfo32_t);
134bb8023b5Sdarran 	}
13580dd0070Schs #endif
136bb8023b5Sdarran 
13780dd0070Schs 	while (pc != 0) {
138*eada09acSchs 		/*
139*eada09acSchs 		 * We limit the number of times we can go around this
140*eada09acSchs 		 * loop to account for a circular stack.
141*eada09acSchs 		 */
142*eada09acSchs 		if (ret++ >= dtrace_ustackdepth_max) {
143*eada09acSchs 			*flags |= CPU_DTRACE_BADSTACK;
144*eada09acSchs 			cpu_core[cpu_number()].cpuc_dtrace_illval = sp;
145*eada09acSchs 			break;
146*eada09acSchs 		}
147*eada09acSchs 
148bb8023b5Sdarran 		if (pcstack != NULL) {
149bb8023b5Sdarran 			*pcstack++ = (uint64_t)pc;
150bb8023b5Sdarran 			pcstack_limit--;
151bb8023b5Sdarran 			if (pcstack_limit <= 0)
152bb8023b5Sdarran 				break;
153bb8023b5Sdarran 		}
154bb8023b5Sdarran 
15580dd0070Schs 		if (sp == 0)
15680dd0070Schs 			break;
15780dd0070Schs 
158*eada09acSchs 		oldsp = sp;
159*eada09acSchs 
16080dd0070Schs #ifdef notyet /* XXX signal stack. */
161bb8023b5Sdarran 		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
162bb8023b5Sdarran 			if (p->p_model == DATAMODEL_NATIVE) {
163bb8023b5Sdarran 				ucontext_t *ucp = (ucontext_t *)oldcontext;
164bb8023b5Sdarran 				greg_t *gregs = ucp->uc_mcontext.gregs;
165bb8023b5Sdarran 
166bb8023b5Sdarran 				sp = dtrace_fulword(&gregs[REG_FP]);
167bb8023b5Sdarran 				pc = dtrace_fulword(&gregs[REG_PC]);
168bb8023b5Sdarran 
169bb8023b5Sdarran 				oldcontext = dtrace_fulword(&ucp->uc_link);
170bb8023b5Sdarran 			} else {
171bb8023b5Sdarran 				ucontext32_t *ucp = (ucontext32_t *)oldcontext;
172bb8023b5Sdarran 				greg32_t *gregs = ucp->uc_mcontext.gregs;
173bb8023b5Sdarran 
174bb8023b5Sdarran 				sp = dtrace_fuword32(&gregs[EBP]);
175bb8023b5Sdarran 				pc = dtrace_fuword32(&gregs[EIP]);
176bb8023b5Sdarran 
177bb8023b5Sdarran 				oldcontext = dtrace_fuword32(&ucp->uc_link);
178bb8023b5Sdarran 			}
179bb8023b5Sdarran 		} else {
180bb8023b5Sdarran 			if (p->p_model == DATAMODEL_NATIVE) {
181bb8023b5Sdarran 				struct frame *fr = (struct frame *)sp;
182bb8023b5Sdarran 
183bb8023b5Sdarran 				pc = dtrace_fulword(&fr->fr_savpc);
184bb8023b5Sdarran 				sp = dtrace_fulword(&fr->fr_savfp);
185bb8023b5Sdarran 			} else {
186bb8023b5Sdarran 				struct frame32 *fr = (struct frame32 *)sp;
187bb8023b5Sdarran 
188bb8023b5Sdarran 				pc = dtrace_fuword32(&fr->fr_savpc);
189bb8023b5Sdarran 				sp = dtrace_fuword32(&fr->fr_savfp);
190bb8023b5Sdarran 			}
191bb8023b5Sdarran 		}
19280dd0070Schs #else
19380dd0070Schs 		pc = dtrace_fuword32((void *)(sp +
19480dd0070Schs 			offsetof(struct i386_frame, f_retaddr)));
19580dd0070Schs 		sp = dtrace_fuword32((void *)sp);
19680dd0070Schs #endif /* ! notyet */
197bb8023b5Sdarran 
198*eada09acSchs 		if (sp == oldsp) {
199*eada09acSchs 			*flags |= CPU_DTRACE_BADSTACK;
200*eada09acSchs 			cpu_core[cpu_number()].cpuc_dtrace_illval = sp;
201*eada09acSchs 			break;
202*eada09acSchs 		}
203*eada09acSchs 
204bb8023b5Sdarran 		/*
205bb8023b5Sdarran 		 * This is totally bogus:  if we faulted, we're going to clear
206bb8023b5Sdarran 		 * the fault and break.  This is to deal with the apparently
207bb8023b5Sdarran 		 * broken Java stacks on x86.
208bb8023b5Sdarran 		 */
209bb8023b5Sdarran 		if (*flags & CPU_DTRACE_FAULT) {
210bb8023b5Sdarran 			*flags &= ~CPU_DTRACE_FAULT;
211bb8023b5Sdarran 			break;
212bb8023b5Sdarran 		}
213bb8023b5Sdarran 	}
214bb8023b5Sdarran 
215bb8023b5Sdarran 	return (ret);
216bb8023b5Sdarran }
217bb8023b5Sdarran 
218bb8023b5Sdarran void
dtrace_getupcstack(uint64_t * pcstack,int pcstack_limit)219bb8023b5Sdarran dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
220bb8023b5Sdarran {
221bb8023b5Sdarran 	proc_t *p = curproc;
22280dd0070Schs 	struct trapframe *tf;
22380dd0070Schs 	uintptr_t pc, sp, fp;
224bb8023b5Sdarran 	volatile uint16_t *flags =
22501c9547eSdarran 	    (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags;
226bb8023b5Sdarran 	int n;
227bb8023b5Sdarran 
228bb8023b5Sdarran 	if (*flags & CPU_DTRACE_FAULT)
229bb8023b5Sdarran 		return;
230bb8023b5Sdarran 
231bb8023b5Sdarran 	if (pcstack_limit <= 0)
232bb8023b5Sdarran 		return;
233bb8023b5Sdarran 
234bb8023b5Sdarran 	/*
235bb8023b5Sdarran 	 * If there's no user context we still need to zero the stack.
236bb8023b5Sdarran 	 */
23780dd0070Schs 	if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL)
238bb8023b5Sdarran 		goto zero;
239bb8023b5Sdarran 
240bb8023b5Sdarran 	*pcstack++ = (uint64_t)p->p_pid;
241bb8023b5Sdarran 	pcstack_limit--;
242bb8023b5Sdarran 
243bb8023b5Sdarran 	if (pcstack_limit <= 0)
244bb8023b5Sdarran 		return;
245bb8023b5Sdarran 
24680dd0070Schs 	pc = tf->tf_eip;
24780dd0070Schs 	fp = tf->tf_ebp;
24880dd0070Schs 	sp = tf->tf_esp;
249bb8023b5Sdarran 
250bb8023b5Sdarran 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
25180dd0070Schs 		/*
25280dd0070Schs 		 * In an entry probe.  The frame pointer has not yet been
25380dd0070Schs 		 * pushed (that happens in the function prologue).  The
25480dd0070Schs 		 * best approach is to add the current pc as a missing top
25580dd0070Schs 		 * of stack and back the pc up to the caller, which is stored
25680dd0070Schs 		 * at the current stack pointer address since the call
25780dd0070Schs 		 * instruction puts it there right before the branch.
25880dd0070Schs 		 */
25980dd0070Schs 
260bb8023b5Sdarran 		*pcstack++ = (uint64_t)pc;
261bb8023b5Sdarran 		pcstack_limit--;
262bb8023b5Sdarran 		if (pcstack_limit <= 0)
263bb8023b5Sdarran 			return;
264bb8023b5Sdarran 
26580dd0070Schs 		pc = dtrace_fuword32((void *) sp);
266bb8023b5Sdarran 	}
267bb8023b5Sdarran 
268*eada09acSchs 	n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp);
269bb8023b5Sdarran 	ASSERT(n >= 0);
270bb8023b5Sdarran 	ASSERT(n <= pcstack_limit);
271bb8023b5Sdarran 
272bb8023b5Sdarran 	pcstack += n;
273bb8023b5Sdarran 	pcstack_limit -= n;
274bb8023b5Sdarran 
275bb8023b5Sdarran zero:
276bb8023b5Sdarran 	while (pcstack_limit-- > 0)
27780dd0070Schs 		*pcstack++ = 0;
278bb8023b5Sdarran }
279bb8023b5Sdarran 
280bb8023b5Sdarran int
dtrace_getustackdepth(void)281bb8023b5Sdarran dtrace_getustackdepth(void)
282bb8023b5Sdarran {
28380dd0070Schs 	proc_t *p = curproc;
28480dd0070Schs 	struct trapframe *tf;
28580dd0070Schs 	uintptr_t pc, fp, sp;
28680dd0070Schs 	int n = 0;
28780dd0070Schs 
28880dd0070Schs 	if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL)
28980dd0070Schs 		return (0);
29080dd0070Schs 
29180dd0070Schs 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
29280dd0070Schs 		return (-1);
29380dd0070Schs 
29480dd0070Schs 	pc = tf->tf_eip;
29580dd0070Schs 	fp = tf->tf_ebp;
29680dd0070Schs 	sp = tf->tf_esp;
29780dd0070Schs 
29880dd0070Schs 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
29980dd0070Schs 		/*
30080dd0070Schs 		 * In an entry probe.  The frame pointer has not yet been
30180dd0070Schs 		 * pushed (that happens in the function prologue).  The
30280dd0070Schs 		 * best approach is to add the current pc as a missing top
30380dd0070Schs 		 * of stack and back the pc up to the caller, which is stored
30480dd0070Schs 		 * at the current stack pointer address since the call
30580dd0070Schs 		 * instruction puts it there right before the branch.
30680dd0070Schs 		 */
30780dd0070Schs 
30880dd0070Schs 		pc = dtrace_fuword32((void *) sp);
30980dd0070Schs 		n++;
31080dd0070Schs 	}
31180dd0070Schs 
31280dd0070Schs 	n += dtrace_getustack_common(NULL, 0, pc, fp);
31380dd0070Schs 
31480dd0070Schs 	return (n);
315bb8023b5Sdarran }
316bb8023b5Sdarran 
317bb8023b5Sdarran void
dtrace_getufpstack(uint64_t * pcstack,uint64_t * fpstack,int pcstack_limit)318bb8023b5Sdarran dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
319bb8023b5Sdarran {
320bb8023b5Sdarran 	proc_t *p = curproc;
32180dd0070Schs 	struct trapframe *tf;
32280dd0070Schs 	uintptr_t pc, sp, fp;
323bb8023b5Sdarran 	volatile uint16_t *flags =
32401c9547eSdarran 	    (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags;
32580dd0070Schs #ifdef notyet /* XXX signal stack */
32680dd0070Schs 	uintptr_t oldcontext;
327bb8023b5Sdarran 	size_t s1, s2;
32880dd0070Schs #endif
329bb8023b5Sdarran 
330bb8023b5Sdarran 	if (*flags & CPU_DTRACE_FAULT)
331bb8023b5Sdarran 		return;
332bb8023b5Sdarran 
333bb8023b5Sdarran 	if (pcstack_limit <= 0)
334bb8023b5Sdarran 		return;
335bb8023b5Sdarran 
336bb8023b5Sdarran 	/*
337bb8023b5Sdarran 	 * If there's no user context we still need to zero the stack.
338bb8023b5Sdarran 	 */
33980dd0070Schs 	if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL)
340bb8023b5Sdarran 		goto zero;
341bb8023b5Sdarran 
342bb8023b5Sdarran 	*pcstack++ = (uint64_t)p->p_pid;
343bb8023b5Sdarran 	pcstack_limit--;
344bb8023b5Sdarran 
345bb8023b5Sdarran 	if (pcstack_limit <= 0)
346bb8023b5Sdarran 		return;
347bb8023b5Sdarran 
34880dd0070Schs 	pc = tf->tf_eip;
34980dd0070Schs 	fp = tf->tf_ebp;
35080dd0070Schs 	sp = tf->tf_esp;
35180dd0070Schs 
35280dd0070Schs #ifdef notyet /* XXX signal stack */
353bb8023b5Sdarran 	oldcontext = lwp->lwp_oldcontext;
354bb8023b5Sdarran 
355bb8023b5Sdarran 	if (p->p_model == DATAMODEL_NATIVE) {
356bb8023b5Sdarran 		s1 = sizeof (struct frame) + 2 * sizeof (long);
357bb8023b5Sdarran 		s2 = s1 + sizeof (siginfo_t);
358bb8023b5Sdarran 	} else {
359bb8023b5Sdarran 		s1 = sizeof (struct frame32) + 3 * sizeof (int);
360bb8023b5Sdarran 		s2 = s1 + sizeof (siginfo32_t);
361bb8023b5Sdarran 	}
36280dd0070Schs #endif
363bb8023b5Sdarran 
364bb8023b5Sdarran 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
365bb8023b5Sdarran 		*pcstack++ = (uint64_t)pc;
366bb8023b5Sdarran 		*fpstack++ = 0;
367bb8023b5Sdarran 		pcstack_limit--;
368bb8023b5Sdarran 		if (pcstack_limit <= 0)
369bb8023b5Sdarran 			return;
370bb8023b5Sdarran 
37180dd0070Schs 		pc = dtrace_fuword32((void *)sp);
372bb8023b5Sdarran 	}
373bb8023b5Sdarran 
37480dd0070Schs 	while (pc != 0) {
375bb8023b5Sdarran 		*pcstack++ = (uint64_t)pc;
37680dd0070Schs 		*fpstack++ = fp;
377bb8023b5Sdarran 		pcstack_limit--;
378bb8023b5Sdarran 		if (pcstack_limit <= 0)
379bb8023b5Sdarran 			break;
380bb8023b5Sdarran 
38180dd0070Schs 		if (fp == 0)
38280dd0070Schs 			break;
38380dd0070Schs 
38480dd0070Schs #ifdef notyet /* XXX signal stack */
385bb8023b5Sdarran 		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
386bb8023b5Sdarran 			if (p->p_model == DATAMODEL_NATIVE) {
387bb8023b5Sdarran 				ucontext_t *ucp = (ucontext_t *)oldcontext;
388bb8023b5Sdarran 				greg_t *gregs = ucp->uc_mcontext.gregs;
389bb8023b5Sdarran 
390bb8023b5Sdarran 				sp = dtrace_fulword(&gregs[REG_FP]);
391bb8023b5Sdarran 				pc = dtrace_fulword(&gregs[REG_PC]);
392bb8023b5Sdarran 
393bb8023b5Sdarran 				oldcontext = dtrace_fulword(&ucp->uc_link);
394bb8023b5Sdarran 			} else {
395bb8023b5Sdarran 				ucontext_t *ucp = (ucontext_t *)oldcontext;
396bb8023b5Sdarran 				greg_t *gregs = ucp->uc_mcontext.gregs;
397bb8023b5Sdarran 
398bb8023b5Sdarran 				sp = dtrace_fuword32(&gregs[EBP]);
399bb8023b5Sdarran 				pc = dtrace_fuword32(&gregs[EIP]);
400bb8023b5Sdarran 
401bb8023b5Sdarran 				oldcontext = dtrace_fuword32(&ucp->uc_link);
402bb8023b5Sdarran 			}
40380dd0070Schs 		} else
40480dd0070Schs #endif /* XXX */
40580dd0070Schs 		{
40680dd0070Schs 			pc = dtrace_fuword32((void *)(fp +
40780dd0070Schs 				offsetof(struct i386_frame, f_retaddr)));
40880dd0070Schs 			fp = dtrace_fuword32((void *)fp);
409bb8023b5Sdarran 		}
410bb8023b5Sdarran 
411bb8023b5Sdarran 		/*
412bb8023b5Sdarran 		 * This is totally bogus:  if we faulted, we're going to clear
413bb8023b5Sdarran 		 * the fault and break.  This is to deal with the apparently
414bb8023b5Sdarran 		 * broken Java stacks on x86.
415bb8023b5Sdarran 		 */
416bb8023b5Sdarran 		if (*flags & CPU_DTRACE_FAULT) {
417bb8023b5Sdarran 			*flags &= ~CPU_DTRACE_FAULT;
418bb8023b5Sdarran 			break;
419bb8023b5Sdarran 		}
420bb8023b5Sdarran 	}
421bb8023b5Sdarran 
422bb8023b5Sdarran zero:
423bb8023b5Sdarran 	while (pcstack_limit-- > 0)
42480dd0070Schs 		*pcstack++ = 0;
425bb8023b5Sdarran }
426bb8023b5Sdarran 
427bb8023b5Sdarran uint64_t
dtrace_getarg(int arg,int aframes)428bb8023b5Sdarran dtrace_getarg(int arg, int aframes)
429bb8023b5Sdarran {
4300fa27af2Schs 	struct trapframe *frame;
431bb8023b5Sdarran 	struct i386_frame *fp = (struct i386_frame *)dtrace_getfp();
4320fa27af2Schs 	uintptr_t *stack, val;
43301c9547eSdarran 	int i;
43480dd0070Schs 
435bb8023b5Sdarran 	for (i = 1; i <= aframes; i++) {
436bb8023b5Sdarran 		fp = fp->f_frame;
437bb8023b5Sdarran 
4380fa27af2Schs 		if (P2ROUNDUP(fp->f_retaddr, 16) ==
4390fa27af2Schs 		    (long)dtrace_invop_callsite) {
440bb8023b5Sdarran 			/*
441bb8023b5Sdarran 			 * If we pass through the invalid op handler, we will
4420fa27af2Schs 			 * use the trap frame pointer that it pushed on the
4430fa27af2Schs 			 * stack as the second argument to dtrace_invop() as
4440fa27af2Schs 			 * the pointer to the stack.
445bb8023b5Sdarran 			 */
4460fa27af2Schs 			frame = (struct trapframe *)(((uintptr_t **)&fp[1])[1]);
4470fa27af2Schs 
4480fa27af2Schs 			/*
4490fa27af2Schs 			 * Skip the three hardware-saved registers and the
4500fa27af2Schs 			 * return address.
4510fa27af2Schs 			 */
4520fa27af2Schs 			stack = (uintptr_t *)&frame->tf_esp + 1;
453bb8023b5Sdarran 			goto load;
454bb8023b5Sdarran 		}
455*eada09acSchs 
456bb8023b5Sdarran 	}
457bb8023b5Sdarran 
458bb8023b5Sdarran 	/*
459bb8023b5Sdarran 	 * We know that we did not come through a trap to get into
460bb8023b5Sdarran 	 * dtrace_probe() -- the provider simply called dtrace_probe()
461bb8023b5Sdarran 	 * directly.  As this is the case, we need to shift the argument
462bb8023b5Sdarran 	 * that we're looking for:  the probe ID is the first argument to
463bb8023b5Sdarran 	 * dtrace_probe(), so the argument n will actually be found where
464bb8023b5Sdarran 	 * one would expect to find argument (n + 1).
465bb8023b5Sdarran 	 */
466bb8023b5Sdarran 	arg++;
467bb8023b5Sdarran 
46880dd0070Schs 	stack = (uintptr_t *)fp + 2;
469bb8023b5Sdarran 
470bb8023b5Sdarran load:
471bb8023b5Sdarran 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
472bb8023b5Sdarran 	val = stack[arg];
473bb8023b5Sdarran 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
474bb8023b5Sdarran 
475bb8023b5Sdarran 	return (val);
476bb8023b5Sdarran }
477bb8023b5Sdarran 
478bb8023b5Sdarran int
dtrace_getstackdepth(int aframes)479bb8023b5Sdarran dtrace_getstackdepth(int aframes)
480bb8023b5Sdarran {
481bb8023b5Sdarran 	int depth = 0;
482bb8023b5Sdarran 	struct i386_frame *frame;
483bb8023b5Sdarran 	vm_offset_t ebp;
484bb8023b5Sdarran 
485bb8023b5Sdarran 	aframes++;
486bb8023b5Sdarran 	ebp = dtrace_getfp();
487bb8023b5Sdarran 	frame = (struct i386_frame *)ebp;
488bb8023b5Sdarran 	depth++;
489bb8023b5Sdarran 	for(;;) {
490bb8023b5Sdarran 		if (!INKERNEL((long) frame))
491bb8023b5Sdarran 			break;
492bb8023b5Sdarran 		if (!INKERNEL((long) frame->f_frame))
493bb8023b5Sdarran 			break;
494bb8023b5Sdarran 		depth++;
495bb8023b5Sdarran 		if (frame->f_frame <= frame ||
496bb8023b5Sdarran 		    (vm_offset_t)frame->f_frame >=
49701c9547eSdarran 		    (vm_offset_t)ebp + KSTACK_SIZE)
498bb8023b5Sdarran 			break;
499bb8023b5Sdarran 		frame = frame->f_frame;
500bb8023b5Sdarran 	}
501bb8023b5Sdarran 	if (depth < aframes)
502bb8023b5Sdarran 		return 0;
503bb8023b5Sdarran 	else
504bb8023b5Sdarran 		return depth - aframes;
505bb8023b5Sdarran }
506bb8023b5Sdarran 
507bb8023b5Sdarran ulong_t
dtrace_getreg(struct trapframe * rp,uint_t reg)508*eada09acSchs dtrace_getreg(struct trapframe *rp, uint_t reg)
509bb8023b5Sdarran {
510*eada09acSchs 	struct pcb *pcb;
511*eada09acSchs 	int regmap[] = {  /* Order is dependent on reg.d */
512*eada09acSchs 		REG_GS,		/* 0  GS */
513*eada09acSchs 		REG_FS,		/* 1  FS */
514*eada09acSchs 		REG_ES,		/* 2  ES */
515*eada09acSchs 		REG_DS,		/* 3  DS */
516*eada09acSchs 		REG_RDI,	/* 4  EDI */
517*eada09acSchs 		REG_RSI,	/* 5  ESI */
518*eada09acSchs 		REG_RBP,	/* 6  EBP, REG_FP */
519*eada09acSchs 		REG_RSP,	/* 7  ESP */
520*eada09acSchs 		REG_RBX,	/* 8  EBX */
521*eada09acSchs 		REG_RDX,	/* 9  EDX, REG_R1 */
522*eada09acSchs 		REG_RCX,	/* 10 ECX */
523*eada09acSchs 		REG_RAX,	/* 11 EAX, REG_R0 */
524*eada09acSchs 		REG_TRAPNO,	/* 12 TRAPNO */
525*eada09acSchs 		REG_ERR,	/* 13 ERR */
526*eada09acSchs 		REG_RIP,	/* 14 EIP, REG_PC */
527*eada09acSchs 		REG_CS,		/* 15 CS */
528*eada09acSchs 		REG_RFL,	/* 16 EFL, REG_PS */
529*eada09acSchs 		REG_RSP,	/* 17 UESP, REG_SP */
530*eada09acSchs 		REG_SS		/* 18 SS */
531bb8023b5Sdarran 	};
532bb8023b5Sdarran 
533*eada09acSchs 	if (reg > SS) {
534*eada09acSchs 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
535*eada09acSchs 		return (0);
536*eada09acSchs 	}
537*eada09acSchs 
538bb8023b5Sdarran 	if (reg >= sizeof (regmap) / sizeof (int)) {
539bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
540bb8023b5Sdarran 		return (0);
541bb8023b5Sdarran 	}
542bb8023b5Sdarran 
543bb8023b5Sdarran 	reg = regmap[reg];
544bb8023b5Sdarran 
545bb8023b5Sdarran 	switch(reg) {
546bb8023b5Sdarran 	case REG_GS:
547*eada09acSchs #ifdef __FreeBSD__
548*eada09acSchs 		if ((pcb = curthread->td_pcb) == NULL) {
549*eada09acSchs 			DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
550*eada09acSchs 			return (0);
551*eada09acSchs 		}
552*eada09acSchs 		return (pcb->pcb_gs);
553*eada09acSchs #endif
554*eada09acSchs #ifdef __NetBSD__
555*eada09acSchs 		return (rp->tf_gs);
556*eada09acSchs #endif
557*eada09acSchs 	case REG_FS:
558*eada09acSchs 		return (rp->tf_fs);
559*eada09acSchs 	case REG_ES:
560*eada09acSchs 		return (rp->tf_es);
561*eada09acSchs 	case REG_DS:
562*eada09acSchs 		return (rp->tf_ds);
563*eada09acSchs 	case REG_RDI:
564*eada09acSchs 		return (rp->tf_edi);
565*eada09acSchs 	case REG_RSI:
566*eada09acSchs 		return (rp->tf_esi);
567*eada09acSchs 	case REG_RBP:
568*eada09acSchs 		return (rp->tf_ebp);
569bb8023b5Sdarran 	case REG_RSP:
570*eada09acSchs #ifdef __FreeBSD__
571*eada09acSchs 		return (rp->tf_isp);
572*eada09acSchs #endif
573*eada09acSchs #ifdef __NetBSD__
574*eada09acSchs 		return (rp->tf_esp);
575*eada09acSchs #endif
576*eada09acSchs 	case REG_RBX:
577*eada09acSchs 		return (rp->tf_ebx);
578*eada09acSchs 	case REG_RCX:
579*eada09acSchs 		return (rp->tf_ecx);
580*eada09acSchs 	case REG_RAX:
581*eada09acSchs 		return (rp->tf_eax);
582*eada09acSchs 	case REG_TRAPNO:
583*eada09acSchs 		return (rp->tf_trapno);
584*eada09acSchs 	case REG_ERR:
585*eada09acSchs 		return (rp->tf_err);
586*eada09acSchs 	case REG_RIP:
587*eada09acSchs 		return (rp->tf_eip);
588*eada09acSchs 	case REG_CS:
589*eada09acSchs 		return (rp->tf_cs);
590*eada09acSchs 	case REG_RFL:
591*eada09acSchs 		return (rp->tf_eflags);
592*eada09acSchs #if 0
593*eada09acSchs 	case REG_RSP:
594*eada09acSchs 		return (rp->tf_esp);
595*eada09acSchs #endif
596*eada09acSchs 	case REG_SS:
597*eada09acSchs 		return (rp->tf_ss);
598bb8023b5Sdarran 	default:
599bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
600bb8023b5Sdarran 		return (0);
601bb8023b5Sdarran 	}
602bb8023b5Sdarran }
603bb8023b5Sdarran 
604bb8023b5Sdarran static int
dtrace_copycheck(uintptr_t uaddr,uintptr_t kaddr,size_t size)605bb8023b5Sdarran dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
606bb8023b5Sdarran {
607bb8023b5Sdarran 	ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr);
608bb8023b5Sdarran 
609bb8023b5Sdarran 	if (uaddr + size >= kernelbase || uaddr + size < uaddr) {
610bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
61101c9547eSdarran 		cpu_core[cpu_number()].cpuc_dtrace_illval = uaddr;
612bb8023b5Sdarran 		return (0);
613bb8023b5Sdarran 	}
614bb8023b5Sdarran 
615bb8023b5Sdarran 	return (1);
616bb8023b5Sdarran }
617bb8023b5Sdarran 
618bb8023b5Sdarran void
dtrace_copyin(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)619bb8023b5Sdarran dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
620bb8023b5Sdarran     volatile uint16_t *flags)
621bb8023b5Sdarran {
622bb8023b5Sdarran 	if (dtrace_copycheck(uaddr, kaddr, size))
623bb8023b5Sdarran 		dtrace_copy(uaddr, kaddr, size);
624bb8023b5Sdarran }
625bb8023b5Sdarran 
626bb8023b5Sdarran void
dtrace_copyout(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)627bb8023b5Sdarran dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
628bb8023b5Sdarran     volatile uint16_t *flags)
629bb8023b5Sdarran {
630bb8023b5Sdarran 	if (dtrace_copycheck(uaddr, kaddr, size))
631bb8023b5Sdarran 		dtrace_copy(kaddr, uaddr, size);
632bb8023b5Sdarran }
633bb8023b5Sdarran 
634bb8023b5Sdarran void
dtrace_copyinstr(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)635bb8023b5Sdarran dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
636bb8023b5Sdarran     volatile uint16_t *flags)
637bb8023b5Sdarran {
638bb8023b5Sdarran 	if (dtrace_copycheck(uaddr, kaddr, size))
639bb8023b5Sdarran 		dtrace_copystr(uaddr, kaddr, size, flags);
640bb8023b5Sdarran }
641bb8023b5Sdarran 
642bb8023b5Sdarran void
dtrace_copyoutstr(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)643bb8023b5Sdarran dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
644bb8023b5Sdarran     volatile uint16_t *flags)
645bb8023b5Sdarran {
646bb8023b5Sdarran 	if (dtrace_copycheck(uaddr, kaddr, size))
647bb8023b5Sdarran 		dtrace_copystr(kaddr, uaddr, size, flags);
648bb8023b5Sdarran }
649bb8023b5Sdarran 
650bb8023b5Sdarran uint8_t
dtrace_fuword8(void * uaddr)651bb8023b5Sdarran dtrace_fuword8(void *uaddr)
652bb8023b5Sdarran {
653bb8023b5Sdarran 	if ((uintptr_t)uaddr >= kernelbase) {
654bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
65501c9547eSdarran 		cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
656bb8023b5Sdarran 		return (0);
657bb8023b5Sdarran 	}
658bb8023b5Sdarran 	return (dtrace_fuword8_nocheck(uaddr));
659bb8023b5Sdarran }
660bb8023b5Sdarran 
661bb8023b5Sdarran uint16_t
dtrace_fuword16(void * uaddr)662bb8023b5Sdarran dtrace_fuword16(void *uaddr)
663bb8023b5Sdarran {
664bb8023b5Sdarran 	if ((uintptr_t)uaddr >= kernelbase) {
665bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
66601c9547eSdarran 		cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
667bb8023b5Sdarran 		return (0);
668bb8023b5Sdarran 	}
669bb8023b5Sdarran 	return (dtrace_fuword16_nocheck(uaddr));
670bb8023b5Sdarran }
671bb8023b5Sdarran 
672bb8023b5Sdarran uint32_t
dtrace_fuword32(void * uaddr)673bb8023b5Sdarran dtrace_fuword32(void *uaddr)
674bb8023b5Sdarran {
675bb8023b5Sdarran 	if ((uintptr_t)uaddr >= kernelbase) {
676bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
67701c9547eSdarran 		cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
678bb8023b5Sdarran 		return (0);
679bb8023b5Sdarran 	}
680bb8023b5Sdarran 	return (dtrace_fuword32_nocheck(uaddr));
681bb8023b5Sdarran }
682bb8023b5Sdarran 
683bb8023b5Sdarran uint64_t
dtrace_fuword64(void * uaddr)684bb8023b5Sdarran dtrace_fuword64(void *uaddr)
685bb8023b5Sdarran {
686bb8023b5Sdarran 	if ((uintptr_t)uaddr >= kernelbase) {
687bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
68801c9547eSdarran 		cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
689bb8023b5Sdarran 		return (0);
690bb8023b5Sdarran 	}
691bb8023b5Sdarran 	return (dtrace_fuword64_nocheck(uaddr));
692bb8023b5Sdarran }
693