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