xref: /freebsd/sys/cddl/dev/dtrace/amd64/dtrace_isa.c (revision fdeb273d49bf2fa2544d3c98114859db10385550)
191eaf3e1SJohn Birrell /*
291eaf3e1SJohn Birrell  * CDDL HEADER START
391eaf3e1SJohn Birrell  *
491eaf3e1SJohn Birrell  * The contents of this file are subject to the terms of the
591eaf3e1SJohn Birrell  * Common Development and Distribution License, Version 1.0 only
691eaf3e1SJohn Birrell  * (the "License").  You may not use this file except in compliance
791eaf3e1SJohn Birrell  * with the License.
891eaf3e1SJohn Birrell  *
991eaf3e1SJohn Birrell  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1091eaf3e1SJohn Birrell  * or http://www.opensolaris.org/os/licensing.
1191eaf3e1SJohn Birrell  * See the License for the specific language governing permissions
1291eaf3e1SJohn Birrell  * and limitations under the License.
1391eaf3e1SJohn Birrell  *
1491eaf3e1SJohn Birrell  * When distributing Covered Code, include this CDDL HEADER in each
1591eaf3e1SJohn Birrell  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1691eaf3e1SJohn Birrell  * If applicable, add the following below this CDDL HEADER, with the
1791eaf3e1SJohn Birrell  * fields enclosed by brackets "[]" replaced with your own identifying
1891eaf3e1SJohn Birrell  * information: Portions Copyright [yyyy] [name of copyright owner]
1991eaf3e1SJohn Birrell  *
2091eaf3e1SJohn Birrell  * CDDL HEADER END
2191eaf3e1SJohn Birrell  */
2291eaf3e1SJohn Birrell /*
2391eaf3e1SJohn Birrell  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
2491eaf3e1SJohn Birrell  * Use is subject to license terms.
2591eaf3e1SJohn Birrell  */
2691eaf3e1SJohn Birrell #include <sys/cdefs.h>
2791eaf3e1SJohn Birrell 
2891eaf3e1SJohn Birrell #include <sys/param.h>
2991eaf3e1SJohn Birrell #include <sys/systm.h>
3082283cadSMark Johnston #include <sys/dtrace_impl.h>
3191eaf3e1SJohn Birrell #include <sys/kernel.h>
32*fdeb273dSMark Johnston #include <sys/msan.h>
3391eaf3e1SJohn Birrell #include <sys/stack.h>
3491eaf3e1SJohn Birrell #include <sys/pcpu.h>
3591eaf3e1SJohn Birrell 
369aabab09SMark Johnston #include <cddl/dev/dtrace/dtrace_cddl.h>
379aabab09SMark Johnston 
3891eaf3e1SJohn Birrell #include <machine/frame.h>
3991eaf3e1SJohn Birrell #include <machine/md_var.h>
4091eaf3e1SJohn Birrell #include <machine/stack.h>
418ca79fbdSMateusz Guzik #include <x86/ifunc.h>
4291eaf3e1SJohn Birrell 
4391eaf3e1SJohn Birrell #include <vm/vm.h>
4491eaf3e1SJohn Birrell #include <vm/vm_param.h>
4591eaf3e1SJohn Birrell #include <vm/pmap.h>
4691eaf3e1SJohn Birrell 
47c6f5742fSRui Paulo #include "regset.h"
4891eaf3e1SJohn Birrell 
4991eaf3e1SJohn Birrell uint8_t dtrace_fuword8_nocheck(void *);
5091eaf3e1SJohn Birrell uint16_t dtrace_fuword16_nocheck(void *);
5191eaf3e1SJohn Birrell uint32_t dtrace_fuword32_nocheck(void *);
5291eaf3e1SJohn Birrell uint64_t dtrace_fuword64_nocheck(void *);
5391eaf3e1SJohn Birrell 
5409a15aa3SMark Johnston int	dtrace_ustackdepth_max = 2048;
5509a15aa3SMark Johnston 
5691eaf3e1SJohn Birrell void
dtrace_getpcstack(pc_t * pcstack,int pcstack_limit,int aframes,uint32_t * intrpc)5791eaf3e1SJohn Birrell dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
5891eaf3e1SJohn Birrell     uint32_t *intrpc)
5991eaf3e1SJohn Birrell {
60fcc0db17SMark Johnston 	struct thread *td;
6191eaf3e1SJohn Birrell 	int depth = 0;
6291eaf3e1SJohn Birrell 	register_t rbp;
6391eaf3e1SJohn Birrell 	struct amd64_frame *frame;
6491eaf3e1SJohn Birrell 	vm_offset_t callpc;
6591eaf3e1SJohn Birrell 	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
6691eaf3e1SJohn Birrell 
6791eaf3e1SJohn Birrell 	if (intrpc != 0)
6891eaf3e1SJohn Birrell 		pcstack[depth++] = (pc_t) intrpc;
6991eaf3e1SJohn Birrell 
7091eaf3e1SJohn Birrell 	aframes++;
7191eaf3e1SJohn Birrell 
7291eaf3e1SJohn Birrell 	__asm __volatile("movq %%rbp,%0" : "=r" (rbp));
7391eaf3e1SJohn Birrell 
7491eaf3e1SJohn Birrell 	frame = (struct amd64_frame *)rbp;
75fcc0db17SMark Johnston 	td = curthread;
7691eaf3e1SJohn Birrell 	while (depth < pcstack_limit) {
77*fdeb273dSMark Johnston 		kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
78*fdeb273dSMark Johnston 
795941edfcSJohn Baldwin 		if (!kstack_contains(curthread, (vm_offset_t)frame,
8024f10b03SKonstantin Belousov 		    sizeof(*frame)))
81fcc0db17SMark Johnston 			break;
82fcc0db17SMark Johnston 
8391eaf3e1SJohn Birrell 		callpc = frame->f_retaddr;
8491eaf3e1SJohn Birrell 
8591eaf3e1SJohn Birrell 		if (!INKERNEL(callpc))
8691eaf3e1SJohn Birrell 			break;
8791eaf3e1SJohn Birrell 
8891eaf3e1SJohn Birrell 		if (aframes > 0) {
8991eaf3e1SJohn Birrell 			aframes--;
9091eaf3e1SJohn Birrell 			if ((aframes == 0) && (caller != 0)) {
9191eaf3e1SJohn Birrell 				pcstack[depth++] = caller;
9291eaf3e1SJohn Birrell 			}
93fcc0db17SMark Johnston 		} else {
9491eaf3e1SJohn Birrell 			pcstack[depth++] = callpc;
9591eaf3e1SJohn Birrell 		}
9691eaf3e1SJohn Birrell 
97fcc0db17SMark Johnston 		if ((vm_offset_t)frame->f_frame <= (vm_offset_t)frame)
9891eaf3e1SJohn Birrell 			break;
9991eaf3e1SJohn Birrell 		frame = frame->f_frame;
10091eaf3e1SJohn Birrell 	}
10191eaf3e1SJohn Birrell 
10291eaf3e1SJohn Birrell 	for (; depth < pcstack_limit; depth++) {
10391eaf3e1SJohn Birrell 		pcstack[depth] = 0;
10491eaf3e1SJohn Birrell 	}
105*fdeb273dSMark Johnston 	kmsan_check(pcstack, pcstack_limit * sizeof(*pcstack), "dtrace");
10691eaf3e1SJohn Birrell }
10791eaf3e1SJohn Birrell 
10891eaf3e1SJohn Birrell static int
dtrace_getustack_common(uint64_t * pcstack,int pcstack_limit,uintptr_t pc,uintptr_t sp)10991eaf3e1SJohn Birrell dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
11091eaf3e1SJohn Birrell     uintptr_t sp)
11191eaf3e1SJohn Birrell {
11209a15aa3SMark Johnston 	uintptr_t oldsp;
11391eaf3e1SJohn Birrell 	volatile uint16_t *flags =
11491eaf3e1SJohn Birrell 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
11591eaf3e1SJohn Birrell 	int ret = 0;
11691eaf3e1SJohn Birrell 
11791eaf3e1SJohn Birrell 	ASSERT(pcstack == NULL || pcstack_limit > 0);
11809a15aa3SMark Johnston 	ASSERT(dtrace_ustackdepth_max > 0);
11991eaf3e1SJohn Birrell 
120c6f5742fSRui Paulo 	while (pc != 0) {
12109a15aa3SMark Johnston 		/*
12209a15aa3SMark Johnston 		 * We limit the number of times we can go around this
12309a15aa3SMark Johnston 		 * loop to account for a circular stack.
12409a15aa3SMark Johnston 		 */
12509a15aa3SMark Johnston 		if (ret++ >= dtrace_ustackdepth_max) {
12609a15aa3SMark Johnston 			*flags |= CPU_DTRACE_BADSTACK;
12709a15aa3SMark Johnston 			cpu_core[curcpu].cpuc_dtrace_illval = sp;
12809a15aa3SMark Johnston 			break;
12909a15aa3SMark Johnston 		}
13009a15aa3SMark Johnston 
13191eaf3e1SJohn Birrell 		if (pcstack != NULL) {
13291eaf3e1SJohn Birrell 			*pcstack++ = (uint64_t)pc;
13391eaf3e1SJohn Birrell 			pcstack_limit--;
13491eaf3e1SJohn Birrell 			if (pcstack_limit <= 0)
13591eaf3e1SJohn Birrell 				break;
13691eaf3e1SJohn Birrell 		}
13791eaf3e1SJohn Birrell 
138c6f5742fSRui Paulo 		if (sp == 0)
139c6f5742fSRui Paulo 			break;
14091eaf3e1SJohn Birrell 
14109a15aa3SMark Johnston 		oldsp = sp;
14209a15aa3SMark Johnston 
143c6f5742fSRui Paulo 		pc = dtrace_fuword64((void *)(sp +
144c6f5742fSRui Paulo 			offsetof(struct amd64_frame, f_retaddr)));
145c6f5742fSRui Paulo 		sp = dtrace_fuword64((void *)sp);
14691eaf3e1SJohn Birrell 
14709a15aa3SMark Johnston 		if (sp == oldsp) {
14809a15aa3SMark Johnston 			*flags |= CPU_DTRACE_BADSTACK;
14909a15aa3SMark Johnston 			cpu_core[curcpu].cpuc_dtrace_illval = sp;
15009a15aa3SMark Johnston 			break;
15109a15aa3SMark Johnston 		}
15209a15aa3SMark Johnston 
15391eaf3e1SJohn Birrell 		/*
15491eaf3e1SJohn Birrell 		 * This is totally bogus:  if we faulted, we're going to clear
15591eaf3e1SJohn Birrell 		 * the fault and break.  This is to deal with the apparently
15691eaf3e1SJohn Birrell 		 * broken Java stacks on x86.
15791eaf3e1SJohn Birrell 		 */
15891eaf3e1SJohn Birrell 		if (*flags & CPU_DTRACE_FAULT) {
15991eaf3e1SJohn Birrell 			*flags &= ~CPU_DTRACE_FAULT;
16091eaf3e1SJohn Birrell 			break;
16191eaf3e1SJohn Birrell 		}
16291eaf3e1SJohn Birrell 	}
16391eaf3e1SJohn Birrell 
16491eaf3e1SJohn Birrell 	return (ret);
16591eaf3e1SJohn Birrell }
16691eaf3e1SJohn Birrell 
16791eaf3e1SJohn Birrell void
dtrace_getupcstack(uint64_t * pcstack,int pcstack_limit)16891eaf3e1SJohn Birrell dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
16991eaf3e1SJohn Birrell {
17091eaf3e1SJohn Birrell 	proc_t *p = curproc;
17191eaf3e1SJohn Birrell 	struct trapframe *tf;
172c6f5742fSRui Paulo 	uintptr_t pc, sp, fp;
17391eaf3e1SJohn Birrell 	volatile uint16_t *flags =
17491eaf3e1SJohn Birrell 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
17591eaf3e1SJohn Birrell 	int n;
17691eaf3e1SJohn Birrell 
17791eaf3e1SJohn Birrell 	if (*flags & CPU_DTRACE_FAULT)
17891eaf3e1SJohn Birrell 		return;
17991eaf3e1SJohn Birrell 
18091eaf3e1SJohn Birrell 	if (pcstack_limit <= 0)
18191eaf3e1SJohn Birrell 		return;
18291eaf3e1SJohn Birrell 
18391eaf3e1SJohn Birrell 	/*
18491eaf3e1SJohn Birrell 	 * If there's no user context we still need to zero the stack.
18591eaf3e1SJohn Birrell 	 */
18691eaf3e1SJohn Birrell 	if (p == NULL || (tf = curthread->td_frame) == NULL)
18791eaf3e1SJohn Birrell 		goto zero;
18891eaf3e1SJohn Birrell 
18991eaf3e1SJohn Birrell 	*pcstack++ = (uint64_t)p->p_pid;
19091eaf3e1SJohn Birrell 	pcstack_limit--;
19191eaf3e1SJohn Birrell 
19291eaf3e1SJohn Birrell 	if (pcstack_limit <= 0)
19391eaf3e1SJohn Birrell 		return;
19491eaf3e1SJohn Birrell 
19591eaf3e1SJohn Birrell 	pc = tf->tf_rip;
196c6f5742fSRui Paulo 	fp = tf->tf_rbp;
19791eaf3e1SJohn Birrell 	sp = tf->tf_rsp;
19891eaf3e1SJohn Birrell 
19991eaf3e1SJohn Birrell 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
200c6f5742fSRui Paulo 		/*
201c6f5742fSRui Paulo 		 * In an entry probe.  The frame pointer has not yet been
202c6f5742fSRui Paulo 		 * pushed (that happens in the function prologue).  The
203c6f5742fSRui Paulo 		 * best approach is to add the current pc as a missing top
204c6f5742fSRui Paulo 		 * of stack and back the pc up to the caller, which is stored
205c6f5742fSRui Paulo 		 * at the current stack pointer address since the call
206c6f5742fSRui Paulo 		 * instruction puts it there right before the branch.
207c6f5742fSRui Paulo 		 */
208c6f5742fSRui Paulo 
20991eaf3e1SJohn Birrell 		*pcstack++ = (uint64_t)pc;
21091eaf3e1SJohn Birrell 		pcstack_limit--;
21191eaf3e1SJohn Birrell 		if (pcstack_limit <= 0)
21291eaf3e1SJohn Birrell 			return;
21391eaf3e1SJohn Birrell 
214c6f5742fSRui Paulo 		pc = dtrace_fuword64((void *) sp);
21591eaf3e1SJohn Birrell 	}
21691eaf3e1SJohn Birrell 
217c6f5742fSRui Paulo 	n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp);
21891eaf3e1SJohn Birrell 	ASSERT(n >= 0);
21991eaf3e1SJohn Birrell 	ASSERT(n <= pcstack_limit);
22091eaf3e1SJohn Birrell 
22191eaf3e1SJohn Birrell 	pcstack += n;
22291eaf3e1SJohn Birrell 	pcstack_limit -= n;
22391eaf3e1SJohn Birrell 
22491eaf3e1SJohn Birrell zero:
22591eaf3e1SJohn Birrell 	while (pcstack_limit-- > 0)
22691eaf3e1SJohn Birrell 		*pcstack++ = 0;
22791eaf3e1SJohn Birrell }
22891eaf3e1SJohn Birrell 
22991eaf3e1SJohn Birrell int
dtrace_getustackdepth(void)23091eaf3e1SJohn Birrell dtrace_getustackdepth(void)
23191eaf3e1SJohn Birrell {
23291eaf3e1SJohn Birrell 	proc_t *p = curproc;
23391eaf3e1SJohn Birrell 	struct trapframe *tf;
234c6f5742fSRui Paulo 	uintptr_t pc, fp, sp;
23591eaf3e1SJohn Birrell 	int n = 0;
23691eaf3e1SJohn Birrell 
23791eaf3e1SJohn Birrell 	if (p == NULL || (tf = curthread->td_frame) == NULL)
23891eaf3e1SJohn Birrell 		return (0);
23991eaf3e1SJohn Birrell 
24091eaf3e1SJohn Birrell 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
24191eaf3e1SJohn Birrell 		return (-1);
24291eaf3e1SJohn Birrell 
24391eaf3e1SJohn Birrell 	pc = tf->tf_rip;
244c6f5742fSRui Paulo 	fp = tf->tf_rbp;
24591eaf3e1SJohn Birrell 	sp = tf->tf_rsp;
24691eaf3e1SJohn Birrell 
24791eaf3e1SJohn Birrell 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
248c6f5742fSRui Paulo 		/*
249c6f5742fSRui Paulo 		 * In an entry probe.  The frame pointer has not yet been
250c6f5742fSRui Paulo 		 * pushed (that happens in the function prologue).  The
251c6f5742fSRui Paulo 		 * best approach is to add the current pc as a missing top
252c6f5742fSRui Paulo 		 * of stack and back the pc up to the caller, which is stored
253c6f5742fSRui Paulo 		 * at the current stack pointer address since the call
254c6f5742fSRui Paulo 		 * instruction puts it there right before the branch.
255c6f5742fSRui Paulo 		 */
25691eaf3e1SJohn Birrell 
257c6f5742fSRui Paulo 		pc = dtrace_fuword64((void *) sp);
258c6f5742fSRui Paulo 		n++;
25991eaf3e1SJohn Birrell 	}
26091eaf3e1SJohn Birrell 
261c6f5742fSRui Paulo 	n += dtrace_getustack_common(NULL, 0, pc, fp);
26291eaf3e1SJohn Birrell 
26391eaf3e1SJohn Birrell 	return (n);
26491eaf3e1SJohn Birrell }
26591eaf3e1SJohn Birrell 
26691eaf3e1SJohn Birrell void
dtrace_getufpstack(uint64_t * pcstack,uint64_t * fpstack,int pcstack_limit)26791eaf3e1SJohn Birrell dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
26891eaf3e1SJohn Birrell {
26991eaf3e1SJohn Birrell 	proc_t *p = curproc;
270c6f5742fSRui Paulo 	struct trapframe *tf;
271c6f5742fSRui Paulo 	uintptr_t pc, sp, fp;
27291eaf3e1SJohn Birrell 	volatile uint16_t *flags =
27391eaf3e1SJohn Birrell 	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
274c6f5742fSRui Paulo #ifdef notyet	/* XXX signal stack */
275c6f5742fSRui Paulo 	uintptr_t oldcontext;
27691eaf3e1SJohn Birrell 	size_t s1, s2;
277c6f5742fSRui Paulo #endif
27891eaf3e1SJohn Birrell 
27991eaf3e1SJohn Birrell 	if (*flags & CPU_DTRACE_FAULT)
28091eaf3e1SJohn Birrell 		return;
28191eaf3e1SJohn Birrell 
28291eaf3e1SJohn Birrell 	if (pcstack_limit <= 0)
28391eaf3e1SJohn Birrell 		return;
28491eaf3e1SJohn Birrell 
28591eaf3e1SJohn Birrell 	/*
28691eaf3e1SJohn Birrell 	 * If there's no user context we still need to zero the stack.
28791eaf3e1SJohn Birrell 	 */
288c6f5742fSRui Paulo 	if (p == NULL || (tf = curthread->td_frame) == NULL)
28991eaf3e1SJohn Birrell 		goto zero;
29091eaf3e1SJohn Birrell 
29191eaf3e1SJohn Birrell 	*pcstack++ = (uint64_t)p->p_pid;
29291eaf3e1SJohn Birrell 	pcstack_limit--;
29391eaf3e1SJohn Birrell 
29491eaf3e1SJohn Birrell 	if (pcstack_limit <= 0)
29591eaf3e1SJohn Birrell 		return;
29691eaf3e1SJohn Birrell 
297c6f5742fSRui Paulo 	pc = tf->tf_rip;
298c6f5742fSRui Paulo 	sp = tf->tf_rsp;
299c6f5742fSRui Paulo 	fp = tf->tf_rbp;
30091eaf3e1SJohn Birrell 
301c6f5742fSRui Paulo #ifdef notyet /* XXX signal stack */
302c6f5742fSRui Paulo 	oldcontext = lwp->lwp_oldcontext;
30391eaf3e1SJohn Birrell 	s1 = sizeof (struct xframe) + 2 * sizeof (long);
30491eaf3e1SJohn Birrell 	s2 = s1 + sizeof (siginfo_t);
305c6f5742fSRui Paulo #endif
30691eaf3e1SJohn Birrell 
30791eaf3e1SJohn Birrell 	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
30891eaf3e1SJohn Birrell 		*pcstack++ = (uint64_t)pc;
30991eaf3e1SJohn Birrell 		*fpstack++ = 0;
31091eaf3e1SJohn Birrell 		pcstack_limit--;
31191eaf3e1SJohn Birrell 		if (pcstack_limit <= 0)
31291eaf3e1SJohn Birrell 			return;
31391eaf3e1SJohn Birrell 
314c6f5742fSRui Paulo 		pc = dtrace_fuword64((void *)sp);
31591eaf3e1SJohn Birrell 	}
31691eaf3e1SJohn Birrell 
317c6f5742fSRui Paulo 	while (pc != 0) {
31891eaf3e1SJohn Birrell 		*pcstack++ = (uint64_t)pc;
319c6f5742fSRui Paulo 		*fpstack++ = fp;
32091eaf3e1SJohn Birrell 		pcstack_limit--;
32191eaf3e1SJohn Birrell 		if (pcstack_limit <= 0)
32291eaf3e1SJohn Birrell 			break;
32391eaf3e1SJohn Birrell 
324c6f5742fSRui Paulo 		if (fp == 0)
325c6f5742fSRui Paulo 			break;
326c6f5742fSRui Paulo 
327c6f5742fSRui Paulo #ifdef notyet /* XXX signal stack */
32891eaf3e1SJohn Birrell 		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
32991eaf3e1SJohn Birrell 			ucontext_t *ucp = (ucontext_t *)oldcontext;
33091eaf3e1SJohn Birrell 			greg_t *gregs = ucp->uc_mcontext.gregs;
33191eaf3e1SJohn Birrell 
33291eaf3e1SJohn Birrell 			sp = dtrace_fulword(&gregs[REG_FP]);
33391eaf3e1SJohn Birrell 			pc = dtrace_fulword(&gregs[REG_PC]);
33491eaf3e1SJohn Birrell 
33591eaf3e1SJohn Birrell 			oldcontext = dtrace_fulword(&ucp->uc_link);
336c6f5742fSRui Paulo 		} else
337c6f5742fSRui Paulo #endif /* XXX */
338c6f5742fSRui Paulo 		{
339c6f5742fSRui Paulo 			pc = dtrace_fuword64((void *)(fp +
340c6f5742fSRui Paulo 				offsetof(struct amd64_frame, f_retaddr)));
341c6f5742fSRui Paulo 			fp = dtrace_fuword64((void *)fp);
34291eaf3e1SJohn Birrell 		}
34391eaf3e1SJohn Birrell 
34491eaf3e1SJohn Birrell 		/*
34591eaf3e1SJohn Birrell 		 * This is totally bogus:  if we faulted, we're going to clear
34691eaf3e1SJohn Birrell 		 * the fault and break.  This is to deal with the apparently
34791eaf3e1SJohn Birrell 		 * broken Java stacks on x86.
34891eaf3e1SJohn Birrell 		 */
34991eaf3e1SJohn Birrell 		if (*flags & CPU_DTRACE_FAULT) {
35091eaf3e1SJohn Birrell 			*flags &= ~CPU_DTRACE_FAULT;
35191eaf3e1SJohn Birrell 			break;
35291eaf3e1SJohn Birrell 		}
35391eaf3e1SJohn Birrell 	}
35491eaf3e1SJohn Birrell 
35591eaf3e1SJohn Birrell zero:
35691eaf3e1SJohn Birrell 	while (pcstack_limit-- > 0)
357c6f5742fSRui Paulo 		*pcstack++ = 0;
35891eaf3e1SJohn Birrell }
35991eaf3e1SJohn Birrell 
36091eaf3e1SJohn Birrell /*ARGSUSED*/
36191eaf3e1SJohn Birrell uint64_t
dtrace_getarg(int arg,int aframes)36291eaf3e1SJohn Birrell dtrace_getarg(int arg, int aframes)
36391eaf3e1SJohn Birrell {
3649aabab09SMark Johnston 	struct thread *td;
36591eaf3e1SJohn Birrell 	uintptr_t val;
36691eaf3e1SJohn Birrell 	struct amd64_frame *fp = (struct amd64_frame *)dtrace_getfp();
36791eaf3e1SJohn Birrell 	uintptr_t *stack;
36891eaf3e1SJohn Birrell 	int i;
36991eaf3e1SJohn Birrell 
37091eaf3e1SJohn Birrell 	/*
37191eaf3e1SJohn Birrell 	 * A total of 6 arguments are passed via registers; any argument with
37291eaf3e1SJohn Birrell 	 * index of 5 or lower is therefore in a register.
37391eaf3e1SJohn Birrell 	 */
37491eaf3e1SJohn Birrell 	int inreg = 5;
37591eaf3e1SJohn Birrell 
37691eaf3e1SJohn Birrell 	/*
3779aabab09SMark Johnston 	 * Did we arrive here via dtrace_invop()?  We can simply fetch arguments
3789aabab09SMark Johnston 	 * from the trap frame if so.
37991eaf3e1SJohn Birrell 	 */
3809aabab09SMark Johnston 	td = curthread;
3819aabab09SMark Johnston 	if (td->t_dtrace_trapframe != NULL) {
3829aabab09SMark Johnston 		struct trapframe *tf = td->t_dtrace_trapframe;
38391eaf3e1SJohn Birrell 
38491eaf3e1SJohn Birrell 		if (arg <= inreg) {
3857e75d586SMark Johnston 			switch (arg) {
3867e75d586SMark Johnston 			case 0:
3879aabab09SMark Johnston 				return (tf->tf_rdi);
3887e75d586SMark Johnston 			case 1:
3899aabab09SMark Johnston 				return (tf->tf_rsi);
3907e75d586SMark Johnston 			case 2:
3919aabab09SMark Johnston 				return (tf->tf_rdx);
3927e75d586SMark Johnston 			case 3:
3939aabab09SMark Johnston 				return (tf->tf_rcx);
3947e75d586SMark Johnston 			case 4:
3959aabab09SMark Johnston 				return (tf->tf_r8);
3967e75d586SMark Johnston 			case 5:
3979aabab09SMark Johnston 				return (tf->tf_r9);
3987e75d586SMark Johnston 			}
3999aabab09SMark Johnston 		}
4009aabab09SMark Johnston 
40191eaf3e1SJohn Birrell 		arg -= inreg;
4029aabab09SMark Johnston 		stack = (uintptr_t *)tf->tf_rsp;
40391eaf3e1SJohn Birrell 		goto load;
40491eaf3e1SJohn Birrell 	}
40591eaf3e1SJohn Birrell 
406*fdeb273dSMark Johnston 	for (i = 1; i <= aframes; i++) {
407*fdeb273dSMark Johnston 		kmsan_mark(fp, sizeof(*fp), KMSAN_STATE_INITED);
4089aabab09SMark Johnston 		fp = fp->f_frame;
409*fdeb273dSMark Johnston 	}
41091eaf3e1SJohn Birrell 
41191eaf3e1SJohn Birrell 	/*
41291eaf3e1SJohn Birrell 	 * We know that we did not come through a trap to get into
41391eaf3e1SJohn Birrell 	 * dtrace_probe() -- the provider simply called dtrace_probe()
41491eaf3e1SJohn Birrell 	 * directly.  As this is the case, we need to shift the argument
41591eaf3e1SJohn Birrell 	 * that we're looking for:  the probe ID is the first argument to
41691eaf3e1SJohn Birrell 	 * dtrace_probe(), so the argument n will actually be found where
41791eaf3e1SJohn Birrell 	 * one would expect to find argument (n + 1).
41891eaf3e1SJohn Birrell 	 */
41991eaf3e1SJohn Birrell 	arg++;
42091eaf3e1SJohn Birrell 
42191eaf3e1SJohn Birrell 	if (arg <= inreg) {
42291eaf3e1SJohn Birrell 		/*
42391eaf3e1SJohn Birrell 		 * This shouldn't happen.  If the argument is passed in a
42491eaf3e1SJohn Birrell 		 * register then it should have been, well, passed in a
42591eaf3e1SJohn Birrell 		 * register...
42691eaf3e1SJohn Birrell 		 */
42791eaf3e1SJohn Birrell 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
42891eaf3e1SJohn Birrell 		return (0);
42991eaf3e1SJohn Birrell 	}
43091eaf3e1SJohn Birrell 
43191eaf3e1SJohn Birrell 	arg -= (inreg + 1);
4321e954a7cSMark Johnston 	stack = (uintptr_t *)&fp[1];
43391eaf3e1SJohn Birrell 
43491eaf3e1SJohn Birrell load:
43591eaf3e1SJohn Birrell 	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
43691eaf3e1SJohn Birrell 	val = stack[arg];
43791eaf3e1SJohn Birrell 	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
43891eaf3e1SJohn Birrell 
439*fdeb273dSMark Johnston 	kmsan_mark(&val, sizeof(val), KMSAN_STATE_INITED);
440*fdeb273dSMark Johnston 
44191eaf3e1SJohn Birrell 	return (val);
44291eaf3e1SJohn Birrell }
44391eaf3e1SJohn Birrell 
44491eaf3e1SJohn Birrell int
dtrace_getstackdepth(int aframes)44591eaf3e1SJohn Birrell dtrace_getstackdepth(int aframes)
44691eaf3e1SJohn Birrell {
44791eaf3e1SJohn Birrell 	int depth = 0;
44891eaf3e1SJohn Birrell 	struct amd64_frame *frame;
44991eaf3e1SJohn Birrell 	vm_offset_t rbp;
45091eaf3e1SJohn Birrell 
45191eaf3e1SJohn Birrell 	aframes++;
45291eaf3e1SJohn Birrell 	rbp = dtrace_getfp();
45391eaf3e1SJohn Birrell 	frame = (struct amd64_frame *)rbp;
45491eaf3e1SJohn Birrell 	depth++;
45591eaf3e1SJohn Birrell 	for (;;) {
456*fdeb273dSMark Johnston 		kmsan_mark(frame, sizeof(*frame), KMSAN_STATE_INITED);
457*fdeb273dSMark Johnston 
4585941edfcSJohn Baldwin 		if (!kstack_contains(curthread, (vm_offset_t)frame,
45924f10b03SKonstantin Belousov 		    sizeof(*frame)))
46091eaf3e1SJohn Birrell 			break;
461*fdeb273dSMark Johnston 
46291eaf3e1SJohn Birrell 		depth++;
4635941edfcSJohn Baldwin 		if (frame->f_frame <= frame)
46491eaf3e1SJohn Birrell 			break;
46591eaf3e1SJohn Birrell 		frame = frame->f_frame;
46691eaf3e1SJohn Birrell 	}
46791eaf3e1SJohn Birrell 	if (depth < aframes)
46891eaf3e1SJohn Birrell 		return 0;
46991eaf3e1SJohn Birrell 	else
47091eaf3e1SJohn Birrell 		return depth - aframes;
47191eaf3e1SJohn Birrell }
47291eaf3e1SJohn Birrell 
47391eaf3e1SJohn Birrell ulong_t
dtrace_getreg(struct trapframe * frame,uint_t reg)47498ab9802SChristos Margiolis dtrace_getreg(struct trapframe *frame, uint_t reg)
47591eaf3e1SJohn Birrell {
476c6f5742fSRui Paulo 	/* This table is dependent on reg.d. */
47791eaf3e1SJohn Birrell 	int regmap[] = {
478c6f5742fSRui Paulo 		REG_GS,		/* 0  GS */
479c6f5742fSRui Paulo 		REG_FS,		/* 1  FS */
480c6f5742fSRui Paulo 		REG_ES,		/* 2  ES */
481c6f5742fSRui Paulo 		REG_DS,		/* 3  DS */
482c6f5742fSRui Paulo 		REG_RDI,	/* 4  EDI */
483c6f5742fSRui Paulo 		REG_RSI,	/* 5  ESI */
484c6f5742fSRui Paulo 		REG_RBP,	/* 6  EBP, REG_FP */
485c6f5742fSRui Paulo 		REG_RSP,	/* 7  ESP */
486c6f5742fSRui Paulo 		REG_RBX,	/* 8  EBX, REG_R1 */
487c6f5742fSRui Paulo 		REG_RDX,	/* 9  EDX */
488c6f5742fSRui Paulo 		REG_RCX,	/* 10 ECX */
489c6f5742fSRui Paulo 		REG_RAX,	/* 11 EAX, REG_R0 */
490c6f5742fSRui Paulo 		REG_TRAPNO,	/* 12 TRAPNO */
491c6f5742fSRui Paulo 		REG_ERR,	/* 13 ERR */
492c6f5742fSRui Paulo 		REG_RIP,	/* 14 EIP, REG_PC */
493c6f5742fSRui Paulo 		REG_CS,		/* 15 CS */
494c6f5742fSRui Paulo 		REG_RFL,	/* 16 EFL, REG_PS */
495c6f5742fSRui Paulo 		REG_RSP,	/* 17 UESP, REG_SP */
496c6f5742fSRui Paulo 		REG_SS		/* 18 SS */
49791eaf3e1SJohn Birrell 	};
49891eaf3e1SJohn Birrell 
4995eb65c4cSMariusz Zaborski 	if (reg <= GS) {
50091eaf3e1SJohn Birrell 		if (reg >= sizeof (regmap) / sizeof (int)) {
50191eaf3e1SJohn Birrell 			DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
50291eaf3e1SJohn Birrell 			return (0);
50391eaf3e1SJohn Birrell 		}
50491eaf3e1SJohn Birrell 
50591eaf3e1SJohn Birrell 		reg = regmap[reg];
50691eaf3e1SJohn Birrell 	} else {
507c6f5742fSRui Paulo 		/* This is dependent on reg.d. */
5088da024d9SMariusz Zaborski 		reg -= GS + 1;
50991eaf3e1SJohn Birrell 	}
51091eaf3e1SJohn Birrell 
51191eaf3e1SJohn Birrell 	switch (reg) {
51291eaf3e1SJohn Birrell 	case REG_RDI:
51398ab9802SChristos Margiolis 		return (frame->tf_rdi);
51491eaf3e1SJohn Birrell 	case REG_RSI:
51598ab9802SChristos Margiolis 		return (frame->tf_rsi);
51691eaf3e1SJohn Birrell 	case REG_RDX:
51798ab9802SChristos Margiolis 		return (frame->tf_rdx);
51891eaf3e1SJohn Birrell 	case REG_RCX:
51998ab9802SChristos Margiolis 		return (frame->tf_rcx);
52091eaf3e1SJohn Birrell 	case REG_R8:
52198ab9802SChristos Margiolis 		return (frame->tf_r8);
52291eaf3e1SJohn Birrell 	case REG_R9:
52398ab9802SChristos Margiolis 		return (frame->tf_r9);
52491eaf3e1SJohn Birrell 	case REG_RAX:
52598ab9802SChristos Margiolis 		return (frame->tf_rax);
52691eaf3e1SJohn Birrell 	case REG_RBX:
52798ab9802SChristos Margiolis 		return (frame->tf_rbx);
52891eaf3e1SJohn Birrell 	case REG_RBP:
52998ab9802SChristos Margiolis 		return (frame->tf_rbp);
53091eaf3e1SJohn Birrell 	case REG_R10:
53198ab9802SChristos Margiolis 		return (frame->tf_r10);
53291eaf3e1SJohn Birrell 	case REG_R11:
53398ab9802SChristos Margiolis 		return (frame->tf_r11);
53491eaf3e1SJohn Birrell 	case REG_R12:
53598ab9802SChristos Margiolis 		return (frame->tf_r12);
53691eaf3e1SJohn Birrell 	case REG_R13:
53798ab9802SChristos Margiolis 		return (frame->tf_r13);
53891eaf3e1SJohn Birrell 	case REG_R14:
53998ab9802SChristos Margiolis 		return (frame->tf_r14);
54091eaf3e1SJohn Birrell 	case REG_R15:
54198ab9802SChristos Margiolis 		return (frame->tf_r15);
54291eaf3e1SJohn Birrell 	case REG_DS:
54398ab9802SChristos Margiolis 		return (frame->tf_ds);
54491eaf3e1SJohn Birrell 	case REG_ES:
54598ab9802SChristos Margiolis 		return (frame->tf_es);
54691eaf3e1SJohn Birrell 	case REG_FS:
54798ab9802SChristos Margiolis 		return (frame->tf_fs);
54891eaf3e1SJohn Birrell 	case REG_GS:
54998ab9802SChristos Margiolis 		return (frame->tf_gs);
55091eaf3e1SJohn Birrell 	case REG_TRAPNO:
55198ab9802SChristos Margiolis 		return (frame->tf_trapno);
55291eaf3e1SJohn Birrell 	case REG_ERR:
55398ab9802SChristos Margiolis 		return (frame->tf_err);
55491eaf3e1SJohn Birrell 	case REG_RIP:
55598ab9802SChristos Margiolis 		return (frame->tf_rip);
55691eaf3e1SJohn Birrell 	case REG_CS:
55798ab9802SChristos Margiolis 		return (frame->tf_cs);
55891eaf3e1SJohn Birrell 	case REG_SS:
55998ab9802SChristos Margiolis 		return (frame->tf_ss);
56091eaf3e1SJohn Birrell 	case REG_RFL:
56198ab9802SChristos Margiolis 		return (frame->tf_rflags);
56291eaf3e1SJohn Birrell 	case REG_RSP:
56398ab9802SChristos Margiolis 		return (frame->tf_rsp);
56491eaf3e1SJohn Birrell 	default:
56591eaf3e1SJohn Birrell 		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
56691eaf3e1SJohn Birrell 		return (0);
56791eaf3e1SJohn Birrell 	}
56891eaf3e1SJohn Birrell }
56991eaf3e1SJohn Birrell 
57091eaf3e1SJohn Birrell static int
dtrace_copycheck(uintptr_t uaddr,uintptr_t kaddr,size_t size)57191eaf3e1SJohn Birrell dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
57291eaf3e1SJohn Birrell {
573f340e9feSAndriy Gapon 	ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
57491eaf3e1SJohn Birrell 
575f340e9feSAndriy Gapon 	if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
57691eaf3e1SJohn Birrell 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
57791eaf3e1SJohn Birrell 		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
57891eaf3e1SJohn Birrell 		return (0);
57991eaf3e1SJohn Birrell 	}
58091eaf3e1SJohn Birrell 
58191eaf3e1SJohn Birrell 	return (1);
58291eaf3e1SJohn Birrell }
58391eaf3e1SJohn Birrell 
58491eaf3e1SJohn Birrell void
dtrace_copyin(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)58591eaf3e1SJohn Birrell dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
58691eaf3e1SJohn Birrell     volatile uint16_t *flags)
58791eaf3e1SJohn Birrell {
588*fdeb273dSMark Johnston 	if (dtrace_copycheck(uaddr, kaddr, size)) {
58991eaf3e1SJohn Birrell 		dtrace_copy(uaddr, kaddr, size);
590*fdeb273dSMark Johnston 		kmsan_mark((void *)kaddr, size, KMSAN_STATE_INITED);
591*fdeb273dSMark Johnston 	}
59291eaf3e1SJohn Birrell }
59391eaf3e1SJohn Birrell 
59491eaf3e1SJohn Birrell void
dtrace_copyout(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)59591eaf3e1SJohn Birrell dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
59691eaf3e1SJohn Birrell     volatile uint16_t *flags)
59791eaf3e1SJohn Birrell {
598*fdeb273dSMark Johnston 	if (dtrace_copycheck(uaddr, kaddr, size)) {
599*fdeb273dSMark Johnston 		kmsan_check((void *)kaddr, size, "dtrace_copyout");
60091eaf3e1SJohn Birrell 		dtrace_copy(kaddr, uaddr, size);
60191eaf3e1SJohn Birrell 	}
602*fdeb273dSMark Johnston }
60391eaf3e1SJohn Birrell 
60491eaf3e1SJohn Birrell void
dtrace_copyinstr(uintptr_t uaddr,uintptr_t kaddr,size_t size,volatile uint16_t * flags)60591eaf3e1SJohn Birrell dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
60691eaf3e1SJohn Birrell     volatile uint16_t *flags)
60791eaf3e1SJohn Birrell {
608*fdeb273dSMark Johnston 	if (dtrace_copycheck(uaddr, kaddr, size)) {
60991eaf3e1SJohn Birrell 		dtrace_copystr(uaddr, kaddr, size, flags);
610*fdeb273dSMark Johnston 		kmsan_mark((void *)kaddr, size, KMSAN_STATE_INITED);
611*fdeb273dSMark Johnston 	}
61291eaf3e1SJohn Birrell }
61391eaf3e1SJohn Birrell 
61491eaf3e1SJohn Birrell void
dtrace_copyoutstr(uintptr_t kaddr,uintptr_t uaddr,size_t size,volatile uint16_t * flags)61591eaf3e1SJohn Birrell dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
61691eaf3e1SJohn Birrell     volatile uint16_t *flags)
61791eaf3e1SJohn Birrell {
618*fdeb273dSMark Johnston 	if (dtrace_copycheck(uaddr, kaddr, size)) {
619*fdeb273dSMark Johnston 		kmsan_check((void *)kaddr, size, "dtrace_copyoutstr");
62091eaf3e1SJohn Birrell 		dtrace_copystr(kaddr, uaddr, size, flags);
62191eaf3e1SJohn Birrell 	}
622*fdeb273dSMark Johnston }
62391eaf3e1SJohn Birrell 
62491eaf3e1SJohn Birrell uint8_t
dtrace_fuword8(void * uaddr)62591eaf3e1SJohn Birrell dtrace_fuword8(void *uaddr)
62691eaf3e1SJohn Birrell {
627*fdeb273dSMark Johnston 	uint8_t val;
628*fdeb273dSMark Johnston 
629f340e9feSAndriy Gapon 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
63091eaf3e1SJohn Birrell 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
63191eaf3e1SJohn Birrell 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
63291eaf3e1SJohn Birrell 		return (0);
63391eaf3e1SJohn Birrell 	}
634*fdeb273dSMark Johnston 	val = dtrace_fuword8_nocheck(uaddr);
635*fdeb273dSMark Johnston 	kmsan_mark(&val, sizeof(val), KMSAN_STATE_INITED);
636*fdeb273dSMark Johnston 	return (val);
63791eaf3e1SJohn Birrell }
63891eaf3e1SJohn Birrell 
63991eaf3e1SJohn Birrell uint16_t
dtrace_fuword16(void * uaddr)64091eaf3e1SJohn Birrell dtrace_fuword16(void *uaddr)
64191eaf3e1SJohn Birrell {
642*fdeb273dSMark Johnston 	uint16_t val;
643*fdeb273dSMark Johnston 
644f340e9feSAndriy Gapon 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
64591eaf3e1SJohn Birrell 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
64691eaf3e1SJohn Birrell 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
64791eaf3e1SJohn Birrell 		return (0);
64891eaf3e1SJohn Birrell 	}
649*fdeb273dSMark Johnston 	val = dtrace_fuword16_nocheck(uaddr);
650*fdeb273dSMark Johnston 	kmsan_mark(&val, sizeof(val), KMSAN_STATE_INITED);
651*fdeb273dSMark Johnston 	return (val);
65291eaf3e1SJohn Birrell }
65391eaf3e1SJohn Birrell 
65491eaf3e1SJohn Birrell uint32_t
dtrace_fuword32(void * uaddr)65591eaf3e1SJohn Birrell dtrace_fuword32(void *uaddr)
65691eaf3e1SJohn Birrell {
657*fdeb273dSMark Johnston 	uint32_t val;
658*fdeb273dSMark Johnston 
659f340e9feSAndriy Gapon 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
66091eaf3e1SJohn Birrell 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
66191eaf3e1SJohn Birrell 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
66291eaf3e1SJohn Birrell 		return (0);
66391eaf3e1SJohn Birrell 	}
664*fdeb273dSMark Johnston 	val = dtrace_fuword32_nocheck(uaddr);
665*fdeb273dSMark Johnston 	kmsan_mark(&val, sizeof(val), KMSAN_STATE_INITED);
666*fdeb273dSMark Johnston 	return (val);
66791eaf3e1SJohn Birrell }
66891eaf3e1SJohn Birrell 
66991eaf3e1SJohn Birrell uint64_t
dtrace_fuword64(void * uaddr)67091eaf3e1SJohn Birrell dtrace_fuword64(void *uaddr)
67191eaf3e1SJohn Birrell {
672*fdeb273dSMark Johnston 	uint64_t val;
673*fdeb273dSMark Johnston 
674f340e9feSAndriy Gapon 	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
67591eaf3e1SJohn Birrell 		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
67691eaf3e1SJohn Birrell 		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
67791eaf3e1SJohn Birrell 		return (0);
67891eaf3e1SJohn Birrell 	}
679*fdeb273dSMark Johnston 	val = dtrace_fuword64_nocheck(uaddr);
680*fdeb273dSMark Johnston 	kmsan_mark(&val, sizeof(val), KMSAN_STATE_INITED);
681*fdeb273dSMark Johnston 	return (val);
68291eaf3e1SJohn Birrell }
6838ca79fbdSMateusz Guzik 
6848ca79fbdSMateusz Guzik /*
6858ca79fbdSMateusz Guzik  * ifunc resolvers for SMAP support
6868ca79fbdSMateusz Guzik  */
6878ca79fbdSMateusz Guzik void dtrace_copy_nosmap(uintptr_t, uintptr_t, size_t);
6888ca79fbdSMateusz Guzik void dtrace_copy_smap(uintptr_t, uintptr_t, size_t);
6897c5a46a1SKonstantin Belousov DEFINE_IFUNC(, void, dtrace_copy, (uintptr_t, uintptr_t, size_t))
6908ca79fbdSMateusz Guzik {
6918ca79fbdSMateusz Guzik 
6928ca79fbdSMateusz Guzik 	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
6938ca79fbdSMateusz Guzik 	    dtrace_copy_smap : dtrace_copy_nosmap);
6948ca79fbdSMateusz Guzik }
6958ca79fbdSMateusz Guzik 
6968ca79fbdSMateusz Guzik void dtrace_copystr_nosmap(uintptr_t, uintptr_t, size_t, volatile uint16_t *);
6978ca79fbdSMateusz Guzik void dtrace_copystr_smap(uintptr_t, uintptr_t, size_t, volatile uint16_t *);
6988ca79fbdSMateusz Guzik DEFINE_IFUNC(, void, dtrace_copystr, (uintptr_t, uintptr_t, size_t,
6997c5a46a1SKonstantin Belousov     volatile uint16_t *))
7008ca79fbdSMateusz Guzik {
7018ca79fbdSMateusz Guzik 
7028ca79fbdSMateusz Guzik 	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
7038ca79fbdSMateusz Guzik 	    dtrace_copystr_smap : dtrace_copystr_nosmap);
7048ca79fbdSMateusz Guzik }
7058ca79fbdSMateusz Guzik 
7068ca79fbdSMateusz Guzik uintptr_t dtrace_fulword_nosmap(void *);
7078ca79fbdSMateusz Guzik uintptr_t dtrace_fulword_smap(void *);
7087c5a46a1SKonstantin Belousov DEFINE_IFUNC(, uintptr_t, dtrace_fulword, (void *))
7098ca79fbdSMateusz Guzik {
7108ca79fbdSMateusz Guzik 
7118ca79fbdSMateusz Guzik 	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
7128ca79fbdSMateusz Guzik 	    dtrace_fulword_smap : dtrace_fulword_nosmap);
7138ca79fbdSMateusz Guzik }
7148ca79fbdSMateusz Guzik 
7158ca79fbdSMateusz Guzik uint8_t dtrace_fuword8_nocheck_nosmap(void *);
7168ca79fbdSMateusz Guzik uint8_t dtrace_fuword8_nocheck_smap(void *);
7177c5a46a1SKonstantin Belousov DEFINE_IFUNC(, uint8_t, dtrace_fuword8_nocheck, (void *))
7188ca79fbdSMateusz Guzik {
7198ca79fbdSMateusz Guzik 
7208ca79fbdSMateusz Guzik 	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
7218ca79fbdSMateusz Guzik 	    dtrace_fuword8_nocheck_smap : dtrace_fuword8_nocheck_nosmap);
7228ca79fbdSMateusz Guzik }
7238ca79fbdSMateusz Guzik 
7248ca79fbdSMateusz Guzik uint16_t dtrace_fuword16_nocheck_nosmap(void *);
7258ca79fbdSMateusz Guzik uint16_t dtrace_fuword16_nocheck_smap(void *);
7267c5a46a1SKonstantin Belousov DEFINE_IFUNC(, uint16_t, dtrace_fuword16_nocheck, (void *))
7278ca79fbdSMateusz Guzik {
7288ca79fbdSMateusz Guzik 
7298ca79fbdSMateusz Guzik 	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
7308ca79fbdSMateusz Guzik 	    dtrace_fuword16_nocheck_smap : dtrace_fuword16_nocheck_nosmap);
7318ca79fbdSMateusz Guzik }
7328ca79fbdSMateusz Guzik 
7338ca79fbdSMateusz Guzik uint32_t dtrace_fuword32_nocheck_nosmap(void *);
7348ca79fbdSMateusz Guzik uint32_t dtrace_fuword32_nocheck_smap(void *);
7357c5a46a1SKonstantin Belousov DEFINE_IFUNC(, uint32_t, dtrace_fuword32_nocheck, (void *))
7368ca79fbdSMateusz Guzik {
7378ca79fbdSMateusz Guzik 
7388ca79fbdSMateusz Guzik 	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
7398ca79fbdSMateusz Guzik 	    dtrace_fuword32_nocheck_smap : dtrace_fuword32_nocheck_nosmap);
7408ca79fbdSMateusz Guzik }
7418ca79fbdSMateusz Guzik 
7428ca79fbdSMateusz Guzik uint64_t dtrace_fuword64_nocheck_nosmap(void *);
7438ca79fbdSMateusz Guzik uint64_t dtrace_fuword64_nocheck_smap(void *);
7447c5a46a1SKonstantin Belousov DEFINE_IFUNC(, uint64_t, dtrace_fuword64_nocheck, (void *))
7458ca79fbdSMateusz Guzik {
7468ca79fbdSMateusz Guzik 
7478ca79fbdSMateusz Guzik 	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
7488ca79fbdSMateusz Guzik 	    dtrace_fuword64_nocheck_smap : dtrace_fuword64_nocheck_nosmap);
7498ca79fbdSMateusz Guzik }
750