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