1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 *
22 * $FreeBSD$
23 */
24/*
25 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26 * Use is subject to license terms.
27 */
28#include <sys/cdefs.h>
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/kernel.h>
33#include <sys/stack.h>
34#include <sys/pcpu.h>
35
36#include <machine/frame.h>
37#include <machine/md_var.h>
38#include <machine/reg.h>
39#include <machine/stack.h>
40#include <x86/ifunc.h>
41
42#include <vm/vm.h>
43#include <vm/vm_param.h>
44#include <vm/pmap.h>
45
46#include "regset.h"
47
48uint8_t dtrace_fuword8_nocheck(void *);
49uint16_t dtrace_fuword16_nocheck(void *);
50uint32_t dtrace_fuword32_nocheck(void *);
51uint64_t dtrace_fuword64_nocheck(void *);
52
53int	dtrace_ustackdepth_max = 2048;
54
55void
56dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
57    uint32_t *intrpc)
58{
59	struct thread *td;
60	int depth = 0;
61	register_t rbp;
62	struct amd64_frame *frame;
63	vm_offset_t callpc;
64	pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller;
65
66	if (intrpc != 0)
67		pcstack[depth++] = (pc_t) intrpc;
68
69	aframes++;
70
71	__asm __volatile("movq %%rbp,%0" : "=r" (rbp));
72
73	frame = (struct amd64_frame *)rbp;
74	td = curthread;
75	while (depth < pcstack_limit) {
76		if (!INKERNEL((long) frame))
77			break;
78
79		if ((vm_offset_t)frame >=
80		    td->td_kstack + ptoa(td->td_kstack_pages) ||
81		    (vm_offset_t)frame < td->td_kstack)
82			break;
83
84		callpc = frame->f_retaddr;
85
86		if (!INKERNEL(callpc))
87			break;
88
89		if (aframes > 0) {
90			aframes--;
91			if ((aframes == 0) && (caller != 0)) {
92				pcstack[depth++] = caller;
93			}
94		} else {
95			pcstack[depth++] = callpc;
96		}
97
98		if ((vm_offset_t)frame->f_frame <= (vm_offset_t)frame)
99			break;
100		frame = frame->f_frame;
101	}
102
103	for (; depth < pcstack_limit; depth++) {
104		pcstack[depth] = 0;
105	}
106}
107
108static int
109dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
110    uintptr_t sp)
111{
112	uintptr_t oldsp;
113	volatile uint16_t *flags =
114	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
115	int ret = 0;
116
117	ASSERT(pcstack == NULL || pcstack_limit > 0);
118	ASSERT(dtrace_ustackdepth_max > 0);
119
120	while (pc != 0) {
121		/*
122		 * We limit the number of times we can go around this
123		 * loop to account for a circular stack.
124		 */
125		if (ret++ >= dtrace_ustackdepth_max) {
126			*flags |= CPU_DTRACE_BADSTACK;
127			cpu_core[curcpu].cpuc_dtrace_illval = sp;
128			break;
129		}
130
131		if (pcstack != NULL) {
132			*pcstack++ = (uint64_t)pc;
133			pcstack_limit--;
134			if (pcstack_limit <= 0)
135				break;
136		}
137
138		if (sp == 0)
139			break;
140
141		oldsp = sp;
142
143		pc = dtrace_fuword64((void *)(sp +
144			offsetof(struct amd64_frame, f_retaddr)));
145		sp = dtrace_fuword64((void *)sp);
146
147		if (sp == oldsp) {
148			*flags |= CPU_DTRACE_BADSTACK;
149			cpu_core[curcpu].cpuc_dtrace_illval = sp;
150			break;
151		}
152
153		/*
154		 * This is totally bogus:  if we faulted, we're going to clear
155		 * the fault and break.  This is to deal with the apparently
156		 * broken Java stacks on x86.
157		 */
158		if (*flags & CPU_DTRACE_FAULT) {
159			*flags &= ~CPU_DTRACE_FAULT;
160			break;
161		}
162	}
163
164	return (ret);
165}
166
167void
168dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
169{
170	proc_t *p = curproc;
171	struct trapframe *tf;
172	uintptr_t pc, sp, fp;
173	volatile uint16_t *flags =
174	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
175	int n;
176
177	if (*flags & CPU_DTRACE_FAULT)
178		return;
179
180	if (pcstack_limit <= 0)
181		return;
182
183	/*
184	 * If there's no user context we still need to zero the stack.
185	 */
186	if (p == NULL || (tf = curthread->td_frame) == NULL)
187		goto zero;
188
189	*pcstack++ = (uint64_t)p->p_pid;
190	pcstack_limit--;
191
192	if (pcstack_limit <= 0)
193		return;
194
195	pc = tf->tf_rip;
196	fp = tf->tf_rbp;
197	sp = tf->tf_rsp;
198
199	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
200		/*
201		 * In an entry probe.  The frame pointer has not yet been
202		 * pushed (that happens in the function prologue).  The
203		 * best approach is to add the current pc as a missing top
204		 * of stack and back the pc up to the caller, which is stored
205		 * at the current stack pointer address since the call
206		 * instruction puts it there right before the branch.
207		 */
208
209		*pcstack++ = (uint64_t)pc;
210		pcstack_limit--;
211		if (pcstack_limit <= 0)
212			return;
213
214		pc = dtrace_fuword64((void *) sp);
215	}
216
217	n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp);
218	ASSERT(n >= 0);
219	ASSERT(n <= pcstack_limit);
220
221	pcstack += n;
222	pcstack_limit -= n;
223
224zero:
225	while (pcstack_limit-- > 0)
226		*pcstack++ = 0;
227}
228
229int
230dtrace_getustackdepth(void)
231{
232	proc_t *p = curproc;
233	struct trapframe *tf;
234	uintptr_t pc, fp, sp;
235	int n = 0;
236
237	if (p == NULL || (tf = curthread->td_frame) == NULL)
238		return (0);
239
240	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT))
241		return (-1);
242
243	pc = tf->tf_rip;
244	fp = tf->tf_rbp;
245	sp = tf->tf_rsp;
246
247	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
248		/*
249		 * In an entry probe.  The frame pointer has not yet been
250		 * pushed (that happens in the function prologue).  The
251		 * best approach is to add the current pc as a missing top
252		 * of stack and back the pc up to the caller, which is stored
253		 * at the current stack pointer address since the call
254		 * instruction puts it there right before the branch.
255		 */
256
257		pc = dtrace_fuword64((void *) sp);
258		n++;
259	}
260
261	n += dtrace_getustack_common(NULL, 0, pc, fp);
262
263	return (n);
264}
265
266void
267dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit)
268{
269	proc_t *p = curproc;
270	struct trapframe *tf;
271	uintptr_t pc, sp, fp;
272	volatile uint16_t *flags =
273	    (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
274#ifdef notyet	/* XXX signal stack */
275	uintptr_t oldcontext;
276	size_t s1, s2;
277#endif
278
279	if (*flags & CPU_DTRACE_FAULT)
280		return;
281
282	if (pcstack_limit <= 0)
283		return;
284
285	/*
286	 * If there's no user context we still need to zero the stack.
287	 */
288	if (p == NULL || (tf = curthread->td_frame) == NULL)
289		goto zero;
290
291	*pcstack++ = (uint64_t)p->p_pid;
292	pcstack_limit--;
293
294	if (pcstack_limit <= 0)
295		return;
296
297	pc = tf->tf_rip;
298	sp = tf->tf_rsp;
299	fp = tf->tf_rbp;
300
301#ifdef notyet /* XXX signal stack */
302	oldcontext = lwp->lwp_oldcontext;
303	s1 = sizeof (struct xframe) + 2 * sizeof (long);
304	s2 = s1 + sizeof (siginfo_t);
305#endif
306
307	if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
308		*pcstack++ = (uint64_t)pc;
309		*fpstack++ = 0;
310		pcstack_limit--;
311		if (pcstack_limit <= 0)
312			return;
313
314		pc = dtrace_fuword64((void *)sp);
315	}
316
317	while (pc != 0) {
318		*pcstack++ = (uint64_t)pc;
319		*fpstack++ = fp;
320		pcstack_limit--;
321		if (pcstack_limit <= 0)
322			break;
323
324		if (fp == 0)
325			break;
326
327#ifdef notyet /* XXX signal stack */
328		if (oldcontext == sp + s1 || oldcontext == sp + s2) {
329			ucontext_t *ucp = (ucontext_t *)oldcontext;
330			greg_t *gregs = ucp->uc_mcontext.gregs;
331
332			sp = dtrace_fulword(&gregs[REG_FP]);
333			pc = dtrace_fulword(&gregs[REG_PC]);
334
335			oldcontext = dtrace_fulword(&ucp->uc_link);
336		} else
337#endif /* XXX */
338		{
339			pc = dtrace_fuword64((void *)(fp +
340				offsetof(struct amd64_frame, f_retaddr)));
341			fp = dtrace_fuword64((void *)fp);
342		}
343
344		/*
345		 * This is totally bogus:  if we faulted, we're going to clear
346		 * the fault and break.  This is to deal with the apparently
347		 * broken Java stacks on x86.
348		 */
349		if (*flags & CPU_DTRACE_FAULT) {
350			*flags &= ~CPU_DTRACE_FAULT;
351			break;
352		}
353	}
354
355zero:
356	while (pcstack_limit-- > 0)
357		*pcstack++ = 0;
358}
359
360/*ARGSUSED*/
361uint64_t
362dtrace_getarg(int arg, int aframes)
363{
364	uintptr_t val;
365	struct amd64_frame *fp = (struct amd64_frame *)dtrace_getfp();
366	uintptr_t *stack;
367	int i;
368
369	/*
370	 * A total of 6 arguments are passed via registers; any argument with
371	 * index of 5 or lower is therefore in a register.
372	 */
373	int inreg = 5;
374
375	for (i = 1; i <= aframes; i++) {
376		fp = fp->f_frame;
377
378		if (P2ROUNDUP(fp->f_retaddr, 16) ==
379		    (long)dtrace_invop_callsite) {
380			/*
381			 * In the case of amd64, we will use the pointer to the
382			 * regs structure that was pushed when we took the
383			 * trap.  To get this structure, we must increment
384			 * beyond the frame structure, and then again beyond
385			 * the calling RIP stored in dtrace_invop().  If the
386			 * argument that we're seeking is passed on the stack,
387			 * we'll pull the true stack pointer out of the saved
388			 * registers and decrement our argument by the number
389			 * of arguments passed in registers; if the argument
390			 * we're seeking is passed in registers, we can just
391			 * load it directly.
392			 */
393			struct trapframe *tf = (struct trapframe *)&fp[1];
394
395			if (arg <= inreg) {
396				switch (arg) {
397				case 0:
398					stack = (uintptr_t *)&tf->tf_rdi;
399					break;
400				case 1:
401					stack = (uintptr_t *)&tf->tf_rsi;
402					break;
403				case 2:
404					stack = (uintptr_t *)&tf->tf_rdx;
405					break;
406				case 3:
407					stack = (uintptr_t *)&tf->tf_rcx;
408					break;
409				case 4:
410					stack = (uintptr_t *)&tf->tf_r8;
411					break;
412				case 5:
413					stack = (uintptr_t *)&tf->tf_r9;
414					break;
415				}
416				arg = 0;
417			} else {
418				stack = (uintptr_t *)(tf->tf_rsp);
419				arg -= inreg;
420			}
421			goto load;
422		}
423
424	}
425
426	/*
427	 * We know that we did not come through a trap to get into
428	 * dtrace_probe() -- the provider simply called dtrace_probe()
429	 * directly.  As this is the case, we need to shift the argument
430	 * that we're looking for:  the probe ID is the first argument to
431	 * dtrace_probe(), so the argument n will actually be found where
432	 * one would expect to find argument (n + 1).
433	 */
434	arg++;
435
436	if (arg <= inreg) {
437		/*
438		 * This shouldn't happen.  If the argument is passed in a
439		 * register then it should have been, well, passed in a
440		 * register...
441		 */
442		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
443		return (0);
444	}
445
446	arg -= (inreg + 1);
447	stack = (uintptr_t *)&fp[1];
448
449load:
450	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
451	val = stack[arg];
452	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
453
454	return (val);
455}
456
457int
458dtrace_getstackdepth(int aframes)
459{
460	int depth = 0;
461	struct amd64_frame *frame;
462	vm_offset_t rbp;
463
464	aframes++;
465	rbp = dtrace_getfp();
466	frame = (struct amd64_frame *)rbp;
467	depth++;
468	for(;;) {
469		if (!INKERNEL((long) frame))
470			break;
471		if (!INKERNEL((long) frame->f_frame))
472			break;
473		depth++;
474		if (frame->f_frame <= frame ||
475		    (vm_offset_t)frame->f_frame >= curthread->td_kstack +
476		    curthread->td_kstack_pages * PAGE_SIZE)
477			break;
478		frame = frame->f_frame;
479	}
480	if (depth < aframes)
481		return 0;
482	else
483		return depth - aframes;
484}
485
486ulong_t
487dtrace_getreg(struct trapframe *rp, uint_t reg)
488{
489	/* This table is dependent on reg.d. */
490	int regmap[] = {
491		REG_GS,		/* 0  GS */
492		REG_FS,		/* 1  FS */
493		REG_ES,		/* 2  ES */
494		REG_DS,		/* 3  DS */
495		REG_RDI,	/* 4  EDI */
496		REG_RSI,	/* 5  ESI */
497		REG_RBP,	/* 6  EBP, REG_FP */
498		REG_RSP,	/* 7  ESP */
499		REG_RBX,	/* 8  EBX, REG_R1 */
500		REG_RDX,	/* 9  EDX */
501		REG_RCX,	/* 10 ECX */
502		REG_RAX,	/* 11 EAX, REG_R0 */
503		REG_TRAPNO,	/* 12 TRAPNO */
504		REG_ERR,	/* 13 ERR */
505		REG_RIP,	/* 14 EIP, REG_PC */
506		REG_CS,		/* 15 CS */
507		REG_RFL,	/* 16 EFL, REG_PS */
508		REG_RSP,	/* 17 UESP, REG_SP */
509		REG_SS		/* 18 SS */
510	};
511
512	if (reg <= SS) {
513		if (reg >= sizeof (regmap) / sizeof (int)) {
514			DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
515			return (0);
516		}
517
518		reg = regmap[reg];
519	} else {
520		/* This is dependent on reg.d. */
521		reg -= SS + 1;
522	}
523
524	switch (reg) {
525	case REG_RDI:
526		return (rp->tf_rdi);
527	case REG_RSI:
528		return (rp->tf_rsi);
529	case REG_RDX:
530		return (rp->tf_rdx);
531	case REG_RCX:
532		return (rp->tf_rcx);
533	case REG_R8:
534		return (rp->tf_r8);
535	case REG_R9:
536		return (rp->tf_r9);
537	case REG_RAX:
538		return (rp->tf_rax);
539	case REG_RBX:
540		return (rp->tf_rbx);
541	case REG_RBP:
542		return (rp->tf_rbp);
543	case REG_R10:
544		return (rp->tf_r10);
545	case REG_R11:
546		return (rp->tf_r11);
547	case REG_R12:
548		return (rp->tf_r12);
549	case REG_R13:
550		return (rp->tf_r13);
551	case REG_R14:
552		return (rp->tf_r14);
553	case REG_R15:
554		return (rp->tf_r15);
555	case REG_DS:
556		return (rp->tf_ds);
557	case REG_ES:
558		return (rp->tf_es);
559	case REG_FS:
560		return (rp->tf_fs);
561	case REG_GS:
562		return (rp->tf_gs);
563	case REG_TRAPNO:
564		return (rp->tf_trapno);
565	case REG_ERR:
566		return (rp->tf_err);
567	case REG_RIP:
568		return (rp->tf_rip);
569	case REG_CS:
570		return (rp->tf_cs);
571	case REG_SS:
572		return (rp->tf_ss);
573	case REG_RFL:
574		return (rp->tf_rflags);
575	case REG_RSP:
576		return (rp->tf_rsp);
577	default:
578		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
579		return (0);
580	}
581}
582
583static int
584dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size)
585{
586	ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr);
587
588	if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) {
589		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
590		cpu_core[curcpu].cpuc_dtrace_illval = uaddr;
591		return (0);
592	}
593
594	return (1);
595}
596
597void
598dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size,
599    volatile uint16_t *flags)
600{
601	if (dtrace_copycheck(uaddr, kaddr, size))
602		dtrace_copy(uaddr, kaddr, size);
603}
604
605void
606dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size,
607    volatile uint16_t *flags)
608{
609	if (dtrace_copycheck(uaddr, kaddr, size))
610		dtrace_copy(kaddr, uaddr, size);
611}
612
613void
614dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
615    volatile uint16_t *flags)
616{
617	if (dtrace_copycheck(uaddr, kaddr, size))
618		dtrace_copystr(uaddr, kaddr, size, flags);
619}
620
621void
622dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size,
623    volatile uint16_t *flags)
624{
625	if (dtrace_copycheck(uaddr, kaddr, size))
626		dtrace_copystr(kaddr, uaddr, size, flags);
627}
628
629uint8_t
630dtrace_fuword8(void *uaddr)
631{
632	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
633		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
634		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
635		return (0);
636	}
637	return (dtrace_fuword8_nocheck(uaddr));
638}
639
640uint16_t
641dtrace_fuword16(void *uaddr)
642{
643	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
644		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
645		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
646		return (0);
647	}
648	return (dtrace_fuword16_nocheck(uaddr));
649}
650
651uint32_t
652dtrace_fuword32(void *uaddr)
653{
654	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
655		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
656		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
657		return (0);
658	}
659	return (dtrace_fuword32_nocheck(uaddr));
660}
661
662uint64_t
663dtrace_fuword64(void *uaddr)
664{
665	if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) {
666		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
667		cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr;
668		return (0);
669	}
670	return (dtrace_fuword64_nocheck(uaddr));
671}
672
673/*
674 * ifunc resolvers for SMAP support
675 */
676void dtrace_copy_nosmap(uintptr_t, uintptr_t, size_t);
677void dtrace_copy_smap(uintptr_t, uintptr_t, size_t);
678DEFINE_IFUNC(, void, dtrace_copy, (uintptr_t, uintptr_t, size_t), static)
679{
680
681	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
682	    dtrace_copy_smap : dtrace_copy_nosmap);
683}
684
685void dtrace_copystr_nosmap(uintptr_t, uintptr_t, size_t, volatile uint16_t *);
686void dtrace_copystr_smap(uintptr_t, uintptr_t, size_t, volatile uint16_t *);
687DEFINE_IFUNC(, void, dtrace_copystr, (uintptr_t, uintptr_t, size_t,
688    volatile uint16_t *), static)
689{
690
691	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
692	    dtrace_copystr_smap : dtrace_copystr_nosmap);
693}
694
695uintptr_t dtrace_fulword_nosmap(void *);
696uintptr_t dtrace_fulword_smap(void *);
697DEFINE_IFUNC(, uintptr_t, dtrace_fulword, (void *), static)
698{
699
700	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
701	    dtrace_fulword_smap : dtrace_fulword_nosmap);
702}
703
704uint8_t dtrace_fuword8_nocheck_nosmap(void *);
705uint8_t dtrace_fuword8_nocheck_smap(void *);
706DEFINE_IFUNC(, uint8_t, dtrace_fuword8_nocheck, (void *), static)
707{
708
709	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
710	    dtrace_fuword8_nocheck_smap : dtrace_fuword8_nocheck_nosmap);
711}
712
713uint16_t dtrace_fuword16_nocheck_nosmap(void *);
714uint16_t dtrace_fuword16_nocheck_smap(void *);
715DEFINE_IFUNC(, uint16_t, dtrace_fuword16_nocheck, (void *), static)
716{
717
718	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
719	    dtrace_fuword16_nocheck_smap : dtrace_fuword16_nocheck_nosmap);
720}
721
722uint32_t dtrace_fuword32_nocheck_nosmap(void *);
723uint32_t dtrace_fuword32_nocheck_smap(void *);
724DEFINE_IFUNC(, uint32_t, dtrace_fuword32_nocheck, (void *), static)
725{
726
727	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
728	    dtrace_fuword32_nocheck_smap : dtrace_fuword32_nocheck_nosmap);
729}
730
731uint64_t dtrace_fuword64_nocheck_nosmap(void *);
732uint64_t dtrace_fuword64_nocheck_smap(void *);
733DEFINE_IFUNC(, uint64_t, dtrace_fuword64_nocheck, (void *), static)
734{
735
736	return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ?
737	    dtrace_fuword64_nocheck_smap : dtrace_fuword64_nocheck_nosmap);
738}
739