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 (!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 108 static int 109 dtrace_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 167 void 168 dtrace_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 224 zero: 225 while (pcstack_limit-- > 0) 226 *pcstack++ = 0; 227 } 228 229 int 230 dtrace_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 266 void 267 dtrace_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 355 zero: 356 while (pcstack_limit-- > 0) 357 *pcstack++ = 0; 358 } 359 360 /*ARGSUSED*/ 361 uint64_t 362 dtrace_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 449 load: 450 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 451 val = stack[arg]; 452 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); 453 454 return (val); 455 } 456 457 int 458 dtrace_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 486 ulong_t 487 dtrace_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 #ifdef illumos 513 if (reg <= SS) { 514 #else /* !illumos */ 515 if (reg <= GS) { 516 #endif 517 if (reg >= sizeof (regmap) / sizeof (int)) { 518 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 519 return (0); 520 } 521 522 reg = regmap[reg]; 523 } else { 524 /* This is dependent on reg.d. */ 525 #ifdef illumos 526 reg -= SS + 1; 527 #else /* !illumos */ 528 reg -= GS + 1; 529 #endif 530 } 531 532 switch (reg) { 533 case REG_RDI: 534 return (rp->tf_rdi); 535 case REG_RSI: 536 return (rp->tf_rsi); 537 case REG_RDX: 538 return (rp->tf_rdx); 539 case REG_RCX: 540 return (rp->tf_rcx); 541 case REG_R8: 542 return (rp->tf_r8); 543 case REG_R9: 544 return (rp->tf_r9); 545 case REG_RAX: 546 return (rp->tf_rax); 547 case REG_RBX: 548 return (rp->tf_rbx); 549 case REG_RBP: 550 return (rp->tf_rbp); 551 case REG_R10: 552 return (rp->tf_r10); 553 case REG_R11: 554 return (rp->tf_r11); 555 case REG_R12: 556 return (rp->tf_r12); 557 case REG_R13: 558 return (rp->tf_r13); 559 case REG_R14: 560 return (rp->tf_r14); 561 case REG_R15: 562 return (rp->tf_r15); 563 case REG_DS: 564 return (rp->tf_ds); 565 case REG_ES: 566 return (rp->tf_es); 567 case REG_FS: 568 return (rp->tf_fs); 569 case REG_GS: 570 return (rp->tf_gs); 571 case REG_TRAPNO: 572 return (rp->tf_trapno); 573 case REG_ERR: 574 return (rp->tf_err); 575 case REG_RIP: 576 return (rp->tf_rip); 577 case REG_CS: 578 return (rp->tf_cs); 579 case REG_SS: 580 return (rp->tf_ss); 581 case REG_RFL: 582 return (rp->tf_rflags); 583 case REG_RSP: 584 return (rp->tf_rsp); 585 default: 586 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 587 return (0); 588 } 589 } 590 591 static int 592 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 593 { 594 ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr); 595 596 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 597 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 598 cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 599 return (0); 600 } 601 602 return (1); 603 } 604 605 void 606 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 607 volatile uint16_t *flags) 608 { 609 if (dtrace_copycheck(uaddr, kaddr, size)) 610 dtrace_copy(uaddr, kaddr, size); 611 } 612 613 void 614 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 615 volatile uint16_t *flags) 616 { 617 if (dtrace_copycheck(uaddr, kaddr, size)) 618 dtrace_copy(kaddr, uaddr, size); 619 } 620 621 void 622 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 623 volatile uint16_t *flags) 624 { 625 if (dtrace_copycheck(uaddr, kaddr, size)) 626 dtrace_copystr(uaddr, kaddr, size, flags); 627 } 628 629 void 630 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 631 volatile uint16_t *flags) 632 { 633 if (dtrace_copycheck(uaddr, kaddr, size)) 634 dtrace_copystr(kaddr, uaddr, size, flags); 635 } 636 637 uint8_t 638 dtrace_fuword8(void *uaddr) 639 { 640 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 641 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 642 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 643 return (0); 644 } 645 return (dtrace_fuword8_nocheck(uaddr)); 646 } 647 648 uint16_t 649 dtrace_fuword16(void *uaddr) 650 { 651 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 652 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 653 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 654 return (0); 655 } 656 return (dtrace_fuword16_nocheck(uaddr)); 657 } 658 659 uint32_t 660 dtrace_fuword32(void *uaddr) 661 { 662 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 663 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 664 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 665 return (0); 666 } 667 return (dtrace_fuword32_nocheck(uaddr)); 668 } 669 670 uint64_t 671 dtrace_fuword64(void *uaddr) 672 { 673 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 674 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 675 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 676 return (0); 677 } 678 return (dtrace_fuword64_nocheck(uaddr)); 679 } 680 681 /* 682 * ifunc resolvers for SMAP support 683 */ 684 void dtrace_copy_nosmap(uintptr_t, uintptr_t, size_t); 685 void dtrace_copy_smap(uintptr_t, uintptr_t, size_t); 686 DEFINE_IFUNC(, void, dtrace_copy, (uintptr_t, uintptr_t, size_t)) 687 { 688 689 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 690 dtrace_copy_smap : dtrace_copy_nosmap); 691 } 692 693 void dtrace_copystr_nosmap(uintptr_t, uintptr_t, size_t, volatile uint16_t *); 694 void dtrace_copystr_smap(uintptr_t, uintptr_t, size_t, volatile uint16_t *); 695 DEFINE_IFUNC(, void, dtrace_copystr, (uintptr_t, uintptr_t, size_t, 696 volatile uint16_t *)) 697 { 698 699 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 700 dtrace_copystr_smap : dtrace_copystr_nosmap); 701 } 702 703 uintptr_t dtrace_fulword_nosmap(void *); 704 uintptr_t dtrace_fulword_smap(void *); 705 DEFINE_IFUNC(, uintptr_t, dtrace_fulword, (void *)) 706 { 707 708 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 709 dtrace_fulword_smap : dtrace_fulword_nosmap); 710 } 711 712 uint8_t dtrace_fuword8_nocheck_nosmap(void *); 713 uint8_t dtrace_fuword8_nocheck_smap(void *); 714 DEFINE_IFUNC(, uint8_t, dtrace_fuword8_nocheck, (void *)) 715 { 716 717 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 718 dtrace_fuword8_nocheck_smap : dtrace_fuword8_nocheck_nosmap); 719 } 720 721 uint16_t dtrace_fuword16_nocheck_nosmap(void *); 722 uint16_t dtrace_fuword16_nocheck_smap(void *); 723 DEFINE_IFUNC(, uint16_t, dtrace_fuword16_nocheck, (void *)) 724 { 725 726 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 727 dtrace_fuword16_nocheck_smap : dtrace_fuword16_nocheck_nosmap); 728 } 729 730 uint32_t dtrace_fuword32_nocheck_nosmap(void *); 731 uint32_t dtrace_fuword32_nocheck_smap(void *); 732 DEFINE_IFUNC(, uint32_t, dtrace_fuword32_nocheck, (void *)) 733 { 734 735 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 736 dtrace_fuword32_nocheck_smap : dtrace_fuword32_nocheck_nosmap); 737 } 738 739 uint64_t dtrace_fuword64_nocheck_nosmap(void *); 740 uint64_t dtrace_fuword64_nocheck_smap(void *); 741 DEFINE_IFUNC(, uint64_t, dtrace_fuword64_nocheck, (void *)) 742 { 743 744 return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? 745 dtrace_fuword64_nocheck_smap : dtrace_fuword64_nocheck_nosmap); 746 } 747