1*affd5374Schristos /*	$NetBSD: dtrace_isa.c,v 1.10 2018/08/16 14:14:51 christos 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  *
24eada09acSchs  * $FreeBSD: head/sys/cddl/dev/dtrace/amd64/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 
36bb8023b5Sdarran #include <machine/frame.h>
37bb8023b5Sdarran #include <machine/reg.h>
38bb8023b5Sdarran 
39958e171bSchristos #include <machine/vmparam.h>
40bb8023b5Sdarran 
41eada09acSchs #include "regset.h"
42eada09acSchs 
43bb8023b5Sdarran uint8_t dtrace_fuword8_nocheck(void *);
44bb8023b5Sdarran uint16_t dtrace_fuword16_nocheck(void *);
45bb8023b5Sdarran uint32_t dtrace_fuword32_nocheck(void *);
46bb8023b5Sdarran uint64_t dtrace_fuword64_nocheck(void *);
47bb8023b5Sdarran 
48ea15ab1fSmaxv #define INKERNEL(va) ((intptr_t)(va) < 0) /* XXX horror */
49958e171bSchristos 
50958e171bSchristos struct amd64_frame {
51958e171bSchristos 	struct amd64_frame	*f_frame;
5231e28111Schs 	uintptr_t		 f_retaddr;
53958e171bSchristos };
54958e171bSchristos 
55958e171bSchristos typedef unsigned long vm_offset_t;
56958e171bSchristos 
57eada09acSchs int	dtrace_ustackdepth_max = 2048;
58eada09acSchs 
59bb8023b5Sdarran void
dtrace_getpcstack(pc_t * pcstack,int pcstack_limit,int aframes,uint32_t * intrpc)60bb8023b5Sdarran dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
61bb8023b5Sdarran     uint32_t *intrpc)
62bb8023b5Sdarran {
63bb8023b5Sdarran 	int depth = 0;
64bb8023b5Sdarran 	register_t rbp;
65bb8023b5Sdarran 	struct amd64_frame *frame;
66bb8023b5Sdarran 	vm_offset_t callpc;
67958e171bSchristos 	pc_t caller = (pc_t) solaris_cpu[cpu_number()].cpu_dtrace_caller;
68bb8023b5Sdarran 
69bb8023b5Sdarran 	if (intrpc != 0)
70bb8023b5Sdarran 		pcstack[depth++] = (pc_t) intrpc;
71bb8023b5Sdarran 
72bb8023b5Sdarran 	aframes++;
73bb8023b5Sdarran 
74bb8023b5Sdarran 	__asm __volatile("movq %%rbp,%0" : "=r" (rbp));
75bb8023b5Sdarran 
76bb8023b5Sdarran 	frame = (struct amd64_frame *)rbp;
77bb8023b5Sdarran 	while (depth < pcstack_limit) {
78bb8023b5Sdarran 		if (!INKERNEL((long) frame))
79bb8023b5Sdarran 			break;
80bb8023b5Sdarran 
81bb8023b5Sdarran 		callpc = frame->f_retaddr;
82bb8023b5Sdarran 
83bb8023b5Sdarran 		if (!INKERNEL(callpc))
84bb8023b5Sdarran 			break;
85bb8023b5Sdarran 
86bb8023b5Sdarran 		if (aframes > 0) {
87bb8023b5Sdarran 			aframes--;
88bb8023b5Sdarran 			if ((aframes == 0) && (caller != 0)) {
89bb8023b5Sdarran 				pcstack[depth++] = caller;
90bb8023b5Sdarran 			}
91bb8023b5Sdarran 		}
92bb8023b5Sdarran 		else {
93bb8023b5Sdarran 			pcstack[depth++] = callpc;
94bb8023b5Sdarran 		}
95bb8023b5Sdarran 
96bb8023b5Sdarran 		if (frame->f_frame <= frame ||
97bb8023b5Sdarran 		    (vm_offset_t)frame->f_frame >=
98958e171bSchristos 		    (vm_offset_t)rbp + KSTACK_SIZE)
99bb8023b5Sdarran 			break;
100bb8023b5Sdarran 		frame = frame->f_frame;
101bb8023b5Sdarran 	}
102bb8023b5Sdarran 
103bb8023b5Sdarran 	for (; depth < pcstack_limit; depth++) {
104bb8023b5Sdarran 		pcstack[depth] = 0;
105bb8023b5Sdarran 	}
106bb8023b5Sdarran }
107bb8023b5Sdarran 
108bb8023b5Sdarran static int
dtrace_getustack_common(uint64_t * pcstack,int pcstack_limit,uintptr_t pc,uintptr_t sp)109bb8023b5Sdarran dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
110bb8023b5Sdarran     uintptr_t sp)
111bb8023b5Sdarran {
112eada09acSchs 	uintptr_t oldsp;
113bb8023b5Sdarran 	volatile uint16_t *flags =
114958e171bSchristos 	    (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags;
115bb8023b5Sdarran 	int ret = 0;
116bb8023b5Sdarran 
117bb8023b5Sdarran 	ASSERT(pcstack == NULL || pcstack_limit > 0);
118eada09acSchs 	ASSERT(dtrace_ustackdepth_max > 0);
119bb8023b5Sdarran 
12080dd0070Schs 	while (pc != 0) {
121eada09acSchs 		/*
122eada09acSchs 		 * We limit the number of times we can go around this
123eada09acSchs 		 * loop to account for a circular stack.
124eada09acSchs 		 */
125eada09acSchs 		if (ret++ >= dtrace_ustackdepth_max) {
126eada09acSchs 			*flags |= CPU_DTRACE_BADSTACK;
127eada09acSchs 			cpu_core[cpu_number()].cpuc_dtrace_illval = sp;
128eada09acSchs 			break;
129eada09acSchs 		}
130eada09acSchs 
131bb8023b5Sdarran 		if (pcstack != NULL) {
132bb8023b5Sdarran 			*pcstack++ = (uint64_t)pc;
133bb8023b5Sdarran 			pcstack_limit--;
134bb8023b5Sdarran 			if (pcstack_limit <= 0)
135bb8023b5Sdarran 				break;
136bb8023b5Sdarran 		}
137bb8023b5Sdarran 
13880dd0070Schs 		if (sp == 0)
13980dd0070Schs 			break;
140bb8023b5Sdarran 
141eada09acSchs 		oldsp = sp;
142eada09acSchs 
14380dd0070Schs 		pc = dtrace_fuword64((void *)(sp +
14480dd0070Schs 			offsetof(struct amd64_frame, f_retaddr)));
14580dd0070Schs 		sp = dtrace_fuword64((void *)sp);
146bb8023b5Sdarran 
147eada09acSchs 		if (sp == oldsp) {
148eada09acSchs 			*flags |= CPU_DTRACE_BADSTACK;
149eada09acSchs 			cpu_core[cpu_number()].cpuc_dtrace_illval = sp;
150eada09acSchs 			break;
151eada09acSchs 		}
152eada09acSchs 
153bb8023b5Sdarran 		/*
154bb8023b5Sdarran 		 * This is totally bogus:  if we faulted, we're going to clear
155bb8023b5Sdarran 		 * the fault and break.  This is to deal with the apparently
156bb8023b5Sdarran 		 * broken Java stacks on x86.
157bb8023b5Sdarran 		 */
158bb8023b5Sdarran 		if (*flags & CPU_DTRACE_FAULT) {
159bb8023b5Sdarran 			*flags &= ~CPU_DTRACE_FAULT;
160bb8023b5Sdarran 			break;
161bb8023b5Sdarran 		}
162bb8023b5Sdarran 	}
163bb8023b5Sdarran 
164bb8023b5Sdarran 	return (ret);
165bb8023b5Sdarran }
166bb8023b5Sdarran 
167bb8023b5Sdarran void
dtrace_getupcstack(uint64_t * pcstack,int pcstack_limit)168bb8023b5Sdarran dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
169bb8023b5Sdarran {
170bb8023b5Sdarran 	proc_t *p = curproc;
17180dd0070Schs 	struct trapframe *tf;
17280dd0070Schs 	uintptr_t pc, sp, fp;
173bb8023b5Sdarran 	volatile uint16_t *flags =
174958e171bSchristos 	    (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags;
175bb8023b5Sdarran 	int n;
176bb8023b5Sdarran 
177bb8023b5Sdarran 	if (*flags & CPU_DTRACE_FAULT)
178bb8023b5Sdarran 		return;
179bb8023b5Sdarran 
180bb8023b5Sdarran 	if (pcstack_limit <= 0)
181bb8023b5Sdarran 		return;
182bb8023b5Sdarran 
183bb8023b5Sdarran 	/*
184bb8023b5Sdarran 	 * If there's no user context we still need to zero the stack.
185bb8023b5Sdarran 	 */
18680dd0070Schs 	if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL)
187bb8023b5Sdarran 		goto zero;
188bb8023b5Sdarran 
189bb8023b5Sdarran 	*pcstack++ = (uint64_t)p->p_pid;
190bb8023b5Sdarran 	pcstack_limit--;
191bb8023b5Sdarran 
192bb8023b5Sdarran 	if (pcstack_limit <= 0)
193bb8023b5Sdarran 		return;
194bb8023b5Sdarran 
19580dd0070Schs 	pc = tf->tf_rip;
19680dd0070Schs 	fp = tf->tf_rbp;
19780dd0070Schs 	sp = tf->tf_rsp;
198bb8023b5Sdarran 
199bb8023b5Sdarran 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
20080dd0070Schs 		/*
20180dd0070Schs 		 * In an entry probe.  The frame pointer has not yet been
20280dd0070Schs 		 * pushed (that happens in the function prologue).  The
20380dd0070Schs 		 * best approach is to add the current pc as a missing top
20480dd0070Schs 		 * of stack and back the pc up to the caller, which is stored
20580dd0070Schs 		 * at the current stack pointer address since the call
20680dd0070Schs 		 * instruction puts it there right before the branch.
20780dd0070Schs 		 */
20880dd0070Schs 
209bb8023b5Sdarran 		*pcstack++ = (uint64_t)pc;
210bb8023b5Sdarran 		pcstack_limit--;
211bb8023b5Sdarran 		if (pcstack_limit <= 0)
212bb8023b5Sdarran 			return;
213bb8023b5Sdarran 
21480dd0070Schs 		pc = dtrace_fuword64((void *) sp);
215bb8023b5Sdarran 	}
216bb8023b5Sdarran 
21780dd0070Schs 	n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp);
218bb8023b5Sdarran 	ASSERT(n >= 0);
219bb8023b5Sdarran 	ASSERT(n <= pcstack_limit);
220bb8023b5Sdarran 
221bb8023b5Sdarran 	pcstack += n;
222bb8023b5Sdarran 	pcstack_limit -= n;
223bb8023b5Sdarran 
224bb8023b5Sdarran zero:
225bb8023b5Sdarran 	while (pcstack_limit-- > 0)
226bb8023b5Sdarran 		*pcstack++ = 0;
227bb8023b5Sdarran }
228bb8023b5Sdarran 
229bb8023b5Sdarran int
dtrace_getustackdepth(void)230bb8023b5Sdarran dtrace_getustackdepth(void)
231bb8023b5Sdarran {
23280dd0070Schs 	proc_t *p = curproc;
23380dd0070Schs 	struct trapframe *tf;
23480dd0070Schs 	uintptr_t pc, fp, sp;
23580dd0070Schs 	int n = 0;
23680dd0070Schs 
23780dd0070Schs 	if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL)
23880dd0070Schs 		return (0);
23980dd0070Schs 
24080dd0070Schs 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
24180dd0070Schs 		return (-1);
24280dd0070Schs 
24380dd0070Schs 	pc = tf->tf_rip;
24480dd0070Schs 	fp = tf->tf_rbp;
24580dd0070Schs 	sp = tf->tf_rsp;
24680dd0070Schs 
24780dd0070Schs 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
24880dd0070Schs 		/*
24980dd0070Schs 		 * In an entry probe.  The frame pointer has not yet been
25080dd0070Schs 		 * pushed (that happens in the function prologue).  The
25180dd0070Schs 		 * best approach is to add the current pc as a missing top
25280dd0070Schs 		 * of stack and back the pc up to the caller, which is stored
25380dd0070Schs 		 * at the current stack pointer address since the call
25480dd0070Schs 		 * instruction puts it there right before the branch.
25580dd0070Schs 		 */
25680dd0070Schs 
25780dd0070Schs 		pc = dtrace_fuword64((void *) sp);
25880dd0070Schs 		n++;
25980dd0070Schs 	}
26080dd0070Schs 
26180dd0070Schs 	n += dtrace_getustack_common(NULL, 0, pc, fp);
26280dd0070Schs 
26380dd0070Schs 	return (n);
264bb8023b5Sdarran }
265bb8023b5Sdarran 
266bb8023b5Sdarran void
dtrace_getufpstack(uint64_t * pcstack,uint64_t * fpstack,int pcstack_limit)267bb8023b5Sdarran dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
268bb8023b5Sdarran {
269bb8023b5Sdarran 	proc_t *p = curproc;
27080dd0070Schs 	struct trapframe *tf;
27180dd0070Schs 	uintptr_t pc, sp, fp;
272bb8023b5Sdarran 	volatile uint16_t *flags =
273958e171bSchristos 	    (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags;
27480dd0070Schs #ifdef notyet	/* XXX signal stack */
27580dd0070Schs 	uintptr_t oldcontext;
276bb8023b5Sdarran 	size_t s1, s2;
27780dd0070Schs #endif
278bb8023b5Sdarran 
279bb8023b5Sdarran 	if (*flags & CPU_DTRACE_FAULT)
280bb8023b5Sdarran 		return;
281bb8023b5Sdarran 
282bb8023b5Sdarran 	if (pcstack_limit <= 0)
283bb8023b5Sdarran 		return;
284bb8023b5Sdarran 
285bb8023b5Sdarran 	/*
286bb8023b5Sdarran 	 * If there's no user context we still need to zero the stack.
287bb8023b5Sdarran 	 */
28880dd0070Schs 	if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL)
289bb8023b5Sdarran 		goto zero;
290bb8023b5Sdarran 
291bb8023b5Sdarran 	*pcstack++ = (uint64_t)p->p_pid;
292bb8023b5Sdarran 	pcstack_limit--;
293bb8023b5Sdarran 
294bb8023b5Sdarran 	if (pcstack_limit <= 0)
295bb8023b5Sdarran 		return;
296bb8023b5Sdarran 
29780dd0070Schs 	pc = tf->tf_rip;
29880dd0070Schs 	sp = tf->tf_rsp;
29980dd0070Schs 	fp = tf->tf_rbp;
300bb8023b5Sdarran 
30180dd0070Schs #ifdef notyet /* XXX signal stack */
30280dd0070Schs 	oldcontext = lwp->lwp_oldcontext;
303bb8023b5Sdarran 	s1 = sizeof (struct xframe) + 2 * sizeof (long);
304bb8023b5Sdarran 	s2 = s1 + sizeof (siginfo_t);
30580dd0070Schs #endif
306bb8023b5Sdarran 
307bb8023b5Sdarran 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
308bb8023b5Sdarran 		*pcstack++ = (uint64_t)pc;
309bb8023b5Sdarran 		*fpstack++ = 0;
310bb8023b5Sdarran 		pcstack_limit--;
311bb8023b5Sdarran 		if (pcstack_limit <= 0)
312bb8023b5Sdarran 			return;
313bb8023b5Sdarran 
31480dd0070Schs 		pc = dtrace_fuword64((void *)sp);
315bb8023b5Sdarran 	}
316bb8023b5Sdarran 
31780dd0070Schs 	while (pc != 0) {
318bb8023b5Sdarran 		*pcstack++ = (uint64_t)pc;
31980dd0070Schs 		*fpstack++ = fp;
320bb8023b5Sdarran 		pcstack_limit--;
321bb8023b5Sdarran 		if (pcstack_limit <= 0)
322bb8023b5Sdarran 			break;
323bb8023b5Sdarran 
32480dd0070Schs 		if (fp == 0)
32580dd0070Schs 			break;
32680dd0070Schs 
32780dd0070Schs #ifdef notyet /* XXX signal stack */
328bb8023b5Sdarran 		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
329bb8023b5Sdarran 			ucontext_t *ucp = (ucontext_t *)oldcontext;
330bb8023b5Sdarran 			greg_t *gregs = ucp->uc_mcontext.gregs;
331bb8023b5Sdarran 
332bb8023b5Sdarran 			sp = dtrace_fulword(&gregs[REG_FP]);
333bb8023b5Sdarran 			pc = dtrace_fulword(&gregs[REG_PC]);
334bb8023b5Sdarran 
335bb8023b5Sdarran 			oldcontext = dtrace_fulword(&ucp->uc_link);
33680dd0070Schs 		} else
33780dd0070Schs #endif /* XXX */
33880dd0070Schs 		{
33980dd0070Schs 			pc = dtrace_fuword64((void *)(fp +
34080dd0070Schs 				offsetof(struct amd64_frame, f_retaddr)));
34180dd0070Schs 			fp = dtrace_fuword64((void *)fp);
342bb8023b5Sdarran 		}
343bb8023b5Sdarran 
344bb8023b5Sdarran 		/*
345bb8023b5Sdarran 		 * This is totally bogus:  if we faulted, we're going to clear
346bb8023b5Sdarran 		 * the fault and break.  This is to deal with the apparently
347bb8023b5Sdarran 		 * broken Java stacks on x86.
348bb8023b5Sdarran 		 */
349bb8023b5Sdarran 		if (*flags & CPU_DTRACE_FAULT) {
350bb8023b5Sdarran 			*flags &= ~CPU_DTRACE_FAULT;
351bb8023b5Sdarran 			break;
352bb8023b5Sdarran 		}
353bb8023b5Sdarran 	}
354bb8023b5Sdarran 
355bb8023b5Sdarran zero:
356bb8023b5Sdarran 	while (pcstack_limit-- > 0)
35780dd0070Schs 		*pcstack++ = 0;
358bb8023b5Sdarran }
359bb8023b5Sdarran 
360bb8023b5Sdarran /*ARGSUSED*/
361bb8023b5Sdarran uint64_t
dtrace_getarg(int arg,int aframes)362bb8023b5Sdarran dtrace_getarg(int arg, int aframes)
363bb8023b5Sdarran {
364bb8023b5Sdarran 	uintptr_t val;
365bb8023b5Sdarran 	struct amd64_frame *fp = (struct amd64_frame *)dtrace_getfp();
366bb8023b5Sdarran 	uintptr_t *stack;
367bb8023b5Sdarran 	int i;
368bb8023b5Sdarran 
369bb8023b5Sdarran 	/*
370bb8023b5Sdarran 	 * A total of 6 arguments are passed via registers; any argument with
371bb8023b5Sdarran 	 * index of 5 or lower is therefore in a register.
372bb8023b5Sdarran 	 */
373bb8023b5Sdarran 	int inreg = 5;
374bb8023b5Sdarran 
375bb8023b5Sdarran 	for (i = 1; i <= aframes; i++) {
376bb8023b5Sdarran 		fp = fp->f_frame;
377bb8023b5Sdarran 
3780fa27af2Schs 		if (P2ROUNDUP(fp->f_retaddr, 16) ==
3790fa27af2Schs 		    (long)dtrace_invop_callsite) {
380bb8023b5Sdarran 			/*
381bb8023b5Sdarran 			 * In the case of amd64, we will use the pointer to the
382bb8023b5Sdarran 			 * regs structure that was pushed when we took the
383bb8023b5Sdarran 			 * trap.  To get this structure, we must increment
384bb8023b5Sdarran 			 * beyond the frame structure, and then again beyond
385bb8023b5Sdarran 			 * the calling RIP stored in dtrace_invop().  If the
386bb8023b5Sdarran 			 * argument that we're seeking is passed on the stack,
387bb8023b5Sdarran 			 * we'll pull the true stack pointer out of the saved
388bb8023b5Sdarran 			 * registers and decrement our argument by the number
389bb8023b5Sdarran 			 * of arguments passed in registers; if the argument
39080dd0070Schs 			 * we're seeking is passed in registers, we can just
391bb8023b5Sdarran 			 * load it directly.
392bb8023b5Sdarran 			 */
3930fa27af2Schs 			struct trapframe *tf = (struct trapframe *)&fp[1];
394bb8023b5Sdarran 
395bb8023b5Sdarran 			if (arg <= inreg) {
3960fa27af2Schs 				switch (arg) {
3970fa27af2Schs 				case 0:
3980fa27af2Schs 					stack = (uintptr_t *)&tf->tf_rdi;
3990fa27af2Schs 					break;
4000fa27af2Schs 				case 1:
4010fa27af2Schs 					stack = (uintptr_t *)&tf->tf_rsi;
4020fa27af2Schs 					break;
4030fa27af2Schs 				case 2:
4040fa27af2Schs 					stack = (uintptr_t *)&tf->tf_rdx;
4050fa27af2Schs 					break;
4060fa27af2Schs 				case 3:
4070fa27af2Schs 					stack = (uintptr_t *)&tf->tf_rcx;
4080fa27af2Schs 					break;
4090fa27af2Schs 				case 4:
4100fa27af2Schs 					stack = (uintptr_t *)&tf->tf_r8;
4110fa27af2Schs 					break;
4120fa27af2Schs 				case 5:
4130fa27af2Schs 					stack = (uintptr_t *)&tf->tf_r9;
4140fa27af2Schs 					break;
4150fa27af2Schs 				default:
4160fa27af2Schs 					KASSERT(0);
4170fa27af2Schs 					stack = NULL;
4180fa27af2Schs 					break;
4190fa27af2Schs 				}
4200fa27af2Schs 				arg = 0;
421bb8023b5Sdarran 			} else {
4220fa27af2Schs 				stack = (uintptr_t *)(tf->tf_rsp);
423bb8023b5Sdarran 				arg -= inreg;
424bb8023b5Sdarran 			}
425bb8023b5Sdarran 			goto load;
426bb8023b5Sdarran 		}
427bb8023b5Sdarran 
428bb8023b5Sdarran 	}
429bb8023b5Sdarran 
430bb8023b5Sdarran 	/*
431bb8023b5Sdarran 	 * We know that we did not come through a trap to get into
432bb8023b5Sdarran 	 * dtrace_probe() -- the provider simply called dtrace_probe()
433bb8023b5Sdarran 	 * directly.  As this is the case, we need to shift the argument
434bb8023b5Sdarran 	 * that we're looking for:  the probe ID is the first argument to
435bb8023b5Sdarran 	 * dtrace_probe(), so the argument n will actually be found where
436bb8023b5Sdarran 	 * one would expect to find argument (n + 1).
437bb8023b5Sdarran 	 */
438bb8023b5Sdarran 	arg++;
439bb8023b5Sdarran 
440bb8023b5Sdarran 	if (arg <= inreg) {
441bb8023b5Sdarran 		/*
442bb8023b5Sdarran 		 * This shouldn't happen.  If the argument is passed in a
443bb8023b5Sdarran 		 * register then it should have been, well, passed in a
444bb8023b5Sdarran 		 * register...
445bb8023b5Sdarran 		 */
446bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
447bb8023b5Sdarran 		return (0);
448bb8023b5Sdarran 	}
449bb8023b5Sdarran 
450bb8023b5Sdarran 	arg -= (inreg + 1);
451bb8023b5Sdarran 	stack = (uintptr_t *)&fp[1];
452bb8023b5Sdarran 
453bb8023b5Sdarran load:
454bb8023b5Sdarran 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
455bb8023b5Sdarran 	val = stack[arg];
456bb8023b5Sdarran 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
457bb8023b5Sdarran 
458bb8023b5Sdarran 	return (val);
459bb8023b5Sdarran 	return (0);
460bb8023b5Sdarran }
461bb8023b5Sdarran 
462bb8023b5Sdarran int
dtrace_getstackdepth(int aframes)463bb8023b5Sdarran dtrace_getstackdepth(int aframes)
464bb8023b5Sdarran {
465bb8023b5Sdarran 	int depth = 0;
466bb8023b5Sdarran 	struct amd64_frame *frame;
467bb8023b5Sdarran 	vm_offset_t rbp;
468bb8023b5Sdarran 
469bb8023b5Sdarran 	aframes++;
470bb8023b5Sdarran 	rbp = dtrace_getfp();
471bb8023b5Sdarran 	frame = (struct amd64_frame *)rbp;
472bb8023b5Sdarran 	depth++;
473bb8023b5Sdarran 	for(;;) {
474bb8023b5Sdarran 		if (!INKERNEL((long) frame))
475bb8023b5Sdarran 			break;
476bb8023b5Sdarran 		if (!INKERNEL((long) frame->f_frame))
477bb8023b5Sdarran 			break;
478bb8023b5Sdarran 		depth++;
479bb8023b5Sdarran 		if (frame->f_frame <= frame ||
480bb8023b5Sdarran 		    (vm_offset_t)frame->f_frame >=
481958e171bSchristos 		    (vm_offset_t)rbp + KSTACK_SIZE)
482bb8023b5Sdarran 			break;
483bb8023b5Sdarran 		frame = frame->f_frame;
484bb8023b5Sdarran 	}
485bb8023b5Sdarran 	if (depth < aframes)
486bb8023b5Sdarran 		return 0;
487bb8023b5Sdarran 	else
488bb8023b5Sdarran 		return depth - aframes;
489bb8023b5Sdarran }
490bb8023b5Sdarran 
491bb8023b5Sdarran ulong_t
dtrace_getreg(struct trapframe * rp,uint_t reg)492eada09acSchs dtrace_getreg(struct trapframe *rp, uint_t reg)
493bb8023b5Sdarran {
494bb8023b5Sdarran 	int regmap[] = {
495bb8023b5Sdarran 		REG_GS,		/* GS */
496bb8023b5Sdarran 		REG_FS,		/* FS */
497bb8023b5Sdarran 		REG_ES,		/* ES */
498bb8023b5Sdarran 		REG_DS,		/* DS */
499bb8023b5Sdarran 		REG_RDI,	/* EDI */
500bb8023b5Sdarran 		REG_RSI,	/* ESI */
501bb8023b5Sdarran 		REG_RBP,	/* EBP */
502bb8023b5Sdarran 		REG_RSP,	/* ESP */
503bb8023b5Sdarran 		REG_RBX,	/* EBX */
504bb8023b5Sdarran 		REG_RDX,	/* EDX */
505bb8023b5Sdarran 		REG_RCX,	/* ECX */
506bb8023b5Sdarran 		REG_RAX,	/* EAX */
507bb8023b5Sdarran 		REG_TRAPNO,	/* TRAPNO */
508bb8023b5Sdarran 		REG_ERR,	/* ERR */
509bb8023b5Sdarran 		REG_RIP,	/* EIP */
510bb8023b5Sdarran 		REG_CS,		/* CS */
511bb8023b5Sdarran 		REG_RFL,	/* EFL */
512bb8023b5Sdarran 		REG_RSP,	/* UESP */
513bb8023b5Sdarran 		REG_SS		/* SS */
514bb8023b5Sdarran 	};
515bb8023b5Sdarran 
516bb8023b5Sdarran 	if (reg <= SS) {
517bb8023b5Sdarran 		if (reg >= sizeof (regmap) / sizeof (int)) {
518bb8023b5Sdarran 			DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
519bb8023b5Sdarran 			return (0);
520bb8023b5Sdarran 		}
521bb8023b5Sdarran 
522bb8023b5Sdarran 		reg = regmap[reg];
523bb8023b5Sdarran 	} else {
524bb8023b5Sdarran 		reg -= SS + 1;
525bb8023b5Sdarran 	}
526bb8023b5Sdarran 
527bb8023b5Sdarran 	switch (reg) {
528bb8023b5Sdarran 	case REG_RDI:
529eada09acSchs 		return (rp->tf_rdi);
530bb8023b5Sdarran 	case REG_RSI:
531eada09acSchs 		return (rp->tf_rsi);
532bb8023b5Sdarran 	case REG_RDX:
533eada09acSchs 		return (rp->tf_rdx);
534bb8023b5Sdarran 	case REG_RCX:
535eada09acSchs 		return (rp->tf_rcx);
536bb8023b5Sdarran 	case REG_R8:
537eada09acSchs 		return (rp->tf_r8);
538bb8023b5Sdarran 	case REG_R9:
539eada09acSchs 		return (rp->tf_r9);
540bb8023b5Sdarran 	case REG_RAX:
541eada09acSchs 		return (rp->tf_rax);
542bb8023b5Sdarran 	case REG_RBX:
543eada09acSchs 		return (rp->tf_rbx);
544bb8023b5Sdarran 	case REG_RBP:
545eada09acSchs 		return (rp->tf_rbp);
546bb8023b5Sdarran 	case REG_R10:
547eada09acSchs 		return (rp->tf_r10);
548bb8023b5Sdarran 	case REG_R11:
549eada09acSchs 		return (rp->tf_r11);
550bb8023b5Sdarran 	case REG_R12:
551eada09acSchs 		return (rp->tf_r12);
552bb8023b5Sdarran 	case REG_R13:
553eada09acSchs 		return (rp->tf_r13);
554bb8023b5Sdarran 	case REG_R14:
555eada09acSchs 		return (rp->tf_r14);
556bb8023b5Sdarran 	case REG_R15:
557eada09acSchs 		return (rp->tf_r15);
558bb8023b5Sdarran 	case REG_DS:
559eada09acSchs 		return (rp->tf_ds);
560bb8023b5Sdarran 	case REG_ES:
561eada09acSchs 		return (rp->tf_es);
562bb8023b5Sdarran 	case REG_FS:
563eada09acSchs 		return (rp->tf_fs);
564bb8023b5Sdarran 	case REG_GS:
565eada09acSchs 		return (rp->tf_gs);
566bb8023b5Sdarran 	case REG_TRAPNO:
567eada09acSchs 		return (rp->tf_trapno);
568bb8023b5Sdarran 	case REG_ERR:
569eada09acSchs 		return (rp->tf_err);
570bb8023b5Sdarran 	case REG_RIP:
571eada09acSchs 		return (rp->tf_rip);
572bb8023b5Sdarran 	case REG_CS:
573eada09acSchs 		return (rp->tf_cs);
574bb8023b5Sdarran 	case REG_SS:
575eada09acSchs 		return (rp->tf_ss);
576bb8023b5Sdarran 	case REG_RFL:
577eada09acSchs 		return (rp->tf_rflags);
578bb8023b5Sdarran 	case REG_RSP:
579eada09acSchs 		return (rp->tf_rsp);
580bb8023b5Sdarran 	default:
581bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
582bb8023b5Sdarran 		return (0);
583bb8023b5Sdarran 	}
584bb8023b5Sdarran }
585bb8023b5Sdarran 
586bb8023b5Sdarran static int
dtrace_copycheck(uintptr_t uaddr,uintptr_t kaddr,size_t size)587bb8023b5Sdarran dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
588bb8023b5Sdarran {
589bb8023b5Sdarran 	ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
590bb8023b5Sdarran 
591bb8023b5Sdarran 	if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
592bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
593958e171bSchristos 		cpu_core[cpu_number()].cpuc_dtrace_illval = uaddr;
594bb8023b5Sdarran 		return (0);
595bb8023b5Sdarran 	}
596bb8023b5Sdarran 
597bb8023b5Sdarran 	return (1);
598bb8023b5Sdarran }
599bb8023b5Sdarran 
600bb8023b5Sdarran void
dtrace_copyin(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)601bb8023b5Sdarran dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
602bb8023b5Sdarran     volatile uint16_t *flags)
603bb8023b5Sdarran {
604bb8023b5Sdarran 	if (dtrace_copycheck(uaddr, kaddr, size))
605bb8023b5Sdarran 		dtrace_copy(uaddr, kaddr, size);
606bb8023b5Sdarran }
607bb8023b5Sdarran 
608bb8023b5Sdarran void
dtrace_copyout(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)609bb8023b5Sdarran dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
610bb8023b5Sdarran     volatile uint16_t *flags)
611bb8023b5Sdarran {
612bb8023b5Sdarran 	if (dtrace_copycheck(uaddr, kaddr, size))
613bb8023b5Sdarran 		dtrace_copy(kaddr, uaddr, size);
614bb8023b5Sdarran }
615bb8023b5Sdarran 
616bb8023b5Sdarran void
dtrace_copyinstr(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)617bb8023b5Sdarran dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
618bb8023b5Sdarran     volatile uint16_t *flags)
619bb8023b5Sdarran {
620bb8023b5Sdarran 	if (dtrace_copycheck(uaddr, kaddr, size))
621bb8023b5Sdarran 		dtrace_copystr(uaddr, kaddr, size, flags);
622bb8023b5Sdarran }
623bb8023b5Sdarran 
624bb8023b5Sdarran void
dtrace_copyoutstr(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)625bb8023b5Sdarran dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
626bb8023b5Sdarran     volatile uint16_t *flags)
627bb8023b5Sdarran {
628bb8023b5Sdarran 	if (dtrace_copycheck(uaddr, kaddr, size))
629bb8023b5Sdarran 		dtrace_copystr(kaddr, uaddr, size, flags);
630bb8023b5Sdarran }
631bb8023b5Sdarran 
632bb8023b5Sdarran uint8_t
dtrace_fuword8(void * uaddr)633bb8023b5Sdarran dtrace_fuword8(void *uaddr)
634bb8023b5Sdarran {
635bb8023b5Sdarran 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
636bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
637958e171bSchristos 		cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
638bb8023b5Sdarran 		return (0);
639bb8023b5Sdarran 	}
640bb8023b5Sdarran 	return (dtrace_fuword8_nocheck(uaddr));
641bb8023b5Sdarran }
642bb8023b5Sdarran 
643bb8023b5Sdarran uint16_t
dtrace_fuword16(void * uaddr)644bb8023b5Sdarran dtrace_fuword16(void *uaddr)
645bb8023b5Sdarran {
646bb8023b5Sdarran 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
647bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
648958e171bSchristos 		cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
649bb8023b5Sdarran 		return (0);
650bb8023b5Sdarran 	}
651bb8023b5Sdarran 	return (dtrace_fuword16_nocheck(uaddr));
652bb8023b5Sdarran }
653bb8023b5Sdarran 
654bb8023b5Sdarran uint32_t
dtrace_fuword32(void * uaddr)655bb8023b5Sdarran dtrace_fuword32(void *uaddr)
656bb8023b5Sdarran {
657bb8023b5Sdarran 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
658bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
659958e171bSchristos 		cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
660bb8023b5Sdarran 		return (0);
661bb8023b5Sdarran 	}
662bb8023b5Sdarran 	return (dtrace_fuword32_nocheck(uaddr));
663bb8023b5Sdarran }
664bb8023b5Sdarran 
665bb8023b5Sdarran uint64_t
dtrace_fuword64(void * uaddr)666bb8023b5Sdarran dtrace_fuword64(void *uaddr)
667bb8023b5Sdarran {
668bb8023b5Sdarran 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
669bb8023b5Sdarran 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
670958e171bSchristos 		cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr;
671bb8023b5Sdarran 		return (0);
672bb8023b5Sdarran 	}
673bb8023b5Sdarran 	return (dtrace_fuword64_nocheck(uaddr));
674bb8023b5Sdarran }
675