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