1 /* $NetBSD: dtrace_isa.c,v 1.5 2017/02/27 06:47:00 chs Exp $ */ 2 3 /* 4 * CDDL HEADER START 5 * 6 * The contents of this file are subject to the terms of the 7 * Common Development and Distribution License, Version 1.0 only 8 * (the "License"). You may not use this file except in compliance 9 * with the License. 10 * 11 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 12 * or http://www.opensolaris.org/os/licensing. 13 * See the License for the specific language governing permissions 14 * and limitations under the License. 15 * 16 * When distributing Covered Code, include this CDDL HEADER in each 17 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 18 * If applicable, add the following below this CDDL HEADER, with the 19 * fields enclosed by brackets "[]" replaced with your own identifying 20 * information: Portions Copyright [yyyy] [name of copyright owner] 21 * 22 * CDDL HEADER END 23 * 24 * $FreeBSD: src/sys/cddl/dev/dtrace/i386/dtrace_isa.c,v 1.1.4.1 2009/08/03 08:13:06 kensmith Exp $ 25 */ 26 /* 27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 #include <sys/cdefs.h> 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 36 #include <machine/vmparam.h> 37 #include <machine/pmap.h> 38 39 uintptr_t kernelbase = (uintptr_t)KERNBASE; 40 41 #define INKERNEL(va) \ 42 (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS && \ 43 ((vm_offset_t)(va)) < VM_MAX_KERNEL_ADDRESS) 44 45 struct i386_frame { 46 struct i386_frame *f_frame; 47 int f_retaddr; 48 }; 49 50 typedef unsigned long vm_offset_t; 51 52 uint8_t dtrace_fuword8_nocheck(void *); 53 uint16_t dtrace_fuword16_nocheck(void *); 54 uint32_t dtrace_fuword32_nocheck(void *); 55 uint64_t dtrace_fuword64_nocheck(void *); 56 57 void 58 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 59 uint32_t *intrpc) 60 { 61 int depth = 0; 62 register_t ebp; 63 struct i386_frame *frame; 64 vm_offset_t callpc; 65 pc_t caller = (pc_t) solaris_cpu[cpu_number()].cpu_dtrace_caller; 66 67 if (intrpc != 0) 68 pcstack[depth++] = (pc_t) intrpc; 69 70 aframes++; 71 72 __asm __volatile("movl %%ebp,%0" : "=r" (ebp)); 73 74 frame = (struct i386_frame *)ebp; 75 while (depth < pcstack_limit) { 76 if (!INKERNEL(frame)) 77 break; 78 79 callpc = frame->f_retaddr; 80 81 if (!INKERNEL(callpc)) 82 break; 83 84 if (aframes > 0) { 85 aframes--; 86 if ((aframes == 0) && (caller != 0)) { 87 pcstack[depth++] = caller; 88 } 89 } 90 else { 91 pcstack[depth++] = callpc; 92 } 93 94 if (frame->f_frame <= frame || 95 (vm_offset_t)frame->f_frame >= 96 (vm_offset_t)ebp + KSTACK_SIZE) 97 break; 98 frame = frame->f_frame; 99 } 100 101 for (; depth < pcstack_limit; depth++) { 102 pcstack[depth] = 0; 103 } 104 } 105 106 static int 107 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 108 uintptr_t sp) 109 { 110 #ifdef notyet 111 proc_t *p = curproc; 112 uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */ 113 size_t s1, s2; 114 #endif 115 volatile uint16_t *flags = 116 (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags; 117 int ret = 0; 118 119 ASSERT(pcstack == NULL || pcstack_limit > 0); 120 121 #ifdef notyet /* XXX signal stack. */ 122 if (p->p_model == DATAMODEL_NATIVE) { 123 s1 = sizeof (struct frame) + 2 * sizeof (long); 124 s2 = s1 + sizeof (siginfo_t); 125 } else { 126 s1 = sizeof (struct frame32) + 3 * sizeof (int); 127 s2 = s1 + sizeof (siginfo32_t); 128 } 129 #endif 130 131 while (pc != 0) { 132 ret++; 133 if (pcstack != NULL) { 134 *pcstack++ = (uint64_t)pc; 135 pcstack_limit--; 136 if (pcstack_limit <= 0) 137 break; 138 } 139 140 if (sp == 0) 141 break; 142 143 #ifdef notyet /* XXX signal stack. */ 144 if (oldcontext == sp + s1 || oldcontext == sp + s2) { 145 if (p->p_model == DATAMODEL_NATIVE) { 146 ucontext_t *ucp = (ucontext_t *)oldcontext; 147 greg_t *gregs = ucp->uc_mcontext.gregs; 148 149 sp = dtrace_fulword(&gregs[REG_FP]); 150 pc = dtrace_fulword(&gregs[REG_PC]); 151 152 oldcontext = dtrace_fulword(&ucp->uc_link); 153 } else { 154 ucontext32_t *ucp = (ucontext32_t *)oldcontext; 155 greg32_t *gregs = ucp->uc_mcontext.gregs; 156 157 sp = dtrace_fuword32(&gregs[EBP]); 158 pc = dtrace_fuword32(&gregs[EIP]); 159 160 oldcontext = dtrace_fuword32(&ucp->uc_link); 161 } 162 } else { 163 if (p->p_model == DATAMODEL_NATIVE) { 164 struct frame *fr = (struct frame *)sp; 165 166 pc = dtrace_fulword(&fr->fr_savpc); 167 sp = dtrace_fulword(&fr->fr_savfp); 168 } else { 169 struct frame32 *fr = (struct frame32 *)sp; 170 171 pc = dtrace_fuword32(&fr->fr_savpc); 172 sp = dtrace_fuword32(&fr->fr_savfp); 173 } 174 } 175 #else 176 pc = dtrace_fuword32((void *)(sp + 177 offsetof(struct i386_frame, f_retaddr))); 178 sp = dtrace_fuword32((void *)sp); 179 #endif /* ! notyet */ 180 181 /* 182 * This is totally bogus: if we faulted, we're going to clear 183 * the fault and break. This is to deal with the apparently 184 * broken Java stacks on x86. 185 */ 186 if (*flags & CPU_DTRACE_FAULT) { 187 *flags &= ~CPU_DTRACE_FAULT; 188 break; 189 } 190 } 191 192 return (ret); 193 } 194 195 void 196 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 197 { 198 proc_t *p = curproc; 199 struct trapframe *tf; 200 uintptr_t pc, sp, fp; 201 volatile uint16_t *flags = 202 (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags; 203 int n; 204 205 if (*flags & CPU_DTRACE_FAULT) 206 return; 207 208 if (pcstack_limit <= 0) 209 return; 210 211 /* 212 * If there's no user context we still need to zero the stack. 213 */ 214 if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL) 215 goto zero; 216 217 *pcstack++ = (uint64_t)p->p_pid; 218 pcstack_limit--; 219 220 if (pcstack_limit <= 0) 221 return; 222 223 pc = tf->tf_eip; 224 fp = tf->tf_ebp; 225 sp = tf->tf_esp; 226 227 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 228 /* 229 * In an entry probe. The frame pointer has not yet been 230 * pushed (that happens in the function prologue). The 231 * best approach is to add the current pc as a missing top 232 * of stack and back the pc up to the caller, which is stored 233 * at the current stack pointer address since the call 234 * instruction puts it there right before the branch. 235 */ 236 237 *pcstack++ = (uint64_t)pc; 238 pcstack_limit--; 239 if (pcstack_limit <= 0) 240 return; 241 242 pc = dtrace_fuword32((void *) sp); 243 } 244 245 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp); 246 ASSERT(n >= 0); 247 ASSERT(n <= pcstack_limit); 248 249 pcstack += n; 250 pcstack_limit -= n; 251 252 zero: 253 while (pcstack_limit-- > 0) 254 *pcstack++ = 0; 255 } 256 257 int 258 dtrace_getustackdepth(void) 259 { 260 proc_t *p = curproc; 261 struct trapframe *tf; 262 uintptr_t pc, fp, sp; 263 int n = 0; 264 265 if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL) 266 return (0); 267 268 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) 269 return (-1); 270 271 pc = tf->tf_eip; 272 fp = tf->tf_ebp; 273 sp = tf->tf_esp; 274 275 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 276 /* 277 * In an entry probe. The frame pointer has not yet been 278 * pushed (that happens in the function prologue). The 279 * best approach is to add the current pc as a missing top 280 * of stack and back the pc up to the caller, which is stored 281 * at the current stack pointer address since the call 282 * instruction puts it there right before the branch. 283 */ 284 285 pc = dtrace_fuword32((void *) sp); 286 n++; 287 } 288 289 n += dtrace_getustack_common(NULL, 0, pc, fp); 290 291 return (n); 292 } 293 294 void 295 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 296 { 297 proc_t *p = curproc; 298 struct trapframe *tf; 299 uintptr_t pc, sp, fp; 300 volatile uint16_t *flags = 301 (volatile uint16_t *)&cpu_core[cpu_number()].cpuc_dtrace_flags; 302 #ifdef notyet /* XXX signal stack */ 303 uintptr_t oldcontext; 304 size_t s1, s2; 305 #endif 306 307 if (*flags & CPU_DTRACE_FAULT) 308 return; 309 310 if (pcstack_limit <= 0) 311 return; 312 313 /* 314 * If there's no user context we still need to zero the stack. 315 */ 316 if (p == NULL || (tf = curlwp->l_md.md_regs) == NULL) 317 goto zero; 318 319 *pcstack++ = (uint64_t)p->p_pid; 320 pcstack_limit--; 321 322 if (pcstack_limit <= 0) 323 return; 324 325 pc = tf->tf_eip; 326 fp = tf->tf_ebp; 327 sp = tf->tf_esp; 328 329 #ifdef notyet /* XXX signal stack */ 330 oldcontext = lwp->lwp_oldcontext; 331 332 if (p->p_model == DATAMODEL_NATIVE) { 333 s1 = sizeof (struct frame) + 2 * sizeof (long); 334 s2 = s1 + sizeof (siginfo_t); 335 } else { 336 s1 = sizeof (struct frame32) + 3 * sizeof (int); 337 s2 = s1 + sizeof (siginfo32_t); 338 } 339 #endif 340 341 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 342 *pcstack++ = (uint64_t)pc; 343 *fpstack++ = 0; 344 pcstack_limit--; 345 if (pcstack_limit <= 0) 346 return; 347 348 pc = dtrace_fuword32((void *)sp); 349 } 350 351 while (pc != 0) { 352 *pcstack++ = (uint64_t)pc; 353 *fpstack++ = fp; 354 pcstack_limit--; 355 if (pcstack_limit <= 0) 356 break; 357 358 if (fp == 0) 359 break; 360 361 #ifdef notyet /* XXX signal stack */ 362 if (oldcontext == sp + s1 || oldcontext == sp + s2) { 363 if (p->p_model == DATAMODEL_NATIVE) { 364 ucontext_t *ucp = (ucontext_t *)oldcontext; 365 greg_t *gregs = ucp->uc_mcontext.gregs; 366 367 sp = dtrace_fulword(&gregs[REG_FP]); 368 pc = dtrace_fulword(&gregs[REG_PC]); 369 370 oldcontext = dtrace_fulword(&ucp->uc_link); 371 } else { 372 ucontext_t *ucp = (ucontext_t *)oldcontext; 373 greg_t *gregs = ucp->uc_mcontext.gregs; 374 375 sp = dtrace_fuword32(&gregs[EBP]); 376 pc = dtrace_fuword32(&gregs[EIP]); 377 378 oldcontext = dtrace_fuword32(&ucp->uc_link); 379 } 380 } else 381 #endif /* XXX */ 382 { 383 pc = dtrace_fuword32((void *)(fp + 384 offsetof(struct i386_frame, f_retaddr))); 385 fp = dtrace_fuword32((void *)fp); 386 } 387 388 /* 389 * This is totally bogus: if we faulted, we're going to clear 390 * the fault and break. This is to deal with the apparently 391 * broken Java stacks on x86. 392 */ 393 if (*flags & CPU_DTRACE_FAULT) { 394 *flags &= ~CPU_DTRACE_FAULT; 395 break; 396 } 397 } 398 399 zero: 400 while (pcstack_limit-- > 0) 401 *pcstack++ = 0; 402 } 403 404 uint64_t 405 dtrace_getarg(int arg, int aframes) 406 { 407 struct trapframe *frame; 408 struct i386_frame *fp = (struct i386_frame *)dtrace_getfp(); 409 uintptr_t *stack, val; 410 int i; 411 412 for (i = 1; i <= aframes; i++) { 413 fp = fp->f_frame; 414 415 if (P2ROUNDUP(fp->f_retaddr, 16) == 416 (long)dtrace_invop_callsite) { 417 /* 418 * If we pass through the invalid op handler, we will 419 * use the trap frame pointer that it pushed on the 420 * stack as the second argument to dtrace_invop() as 421 * the pointer to the stack. 422 */ 423 frame = (struct trapframe *)(((uintptr_t **)&fp[1])[1]); 424 425 /* 426 * Skip the three hardware-saved registers and the 427 * return address. 428 */ 429 stack = (uintptr_t *)&frame->tf_esp + 1; 430 goto load; 431 } 432 } 433 434 /* 435 * We know that we did not come through a trap to get into 436 * dtrace_probe() -- the provider simply called dtrace_probe() 437 * directly. As this is the case, we need to shift the argument 438 * that we're looking for: the probe ID is the first argument to 439 * dtrace_probe(), so the argument n will actually be found where 440 * one would expect to find argument (n + 1). 441 */ 442 arg++; 443 444 stack = (uintptr_t *)fp + 2; 445 446 load: 447 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 448 val = stack[arg]; 449 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); 450 451 return (val); 452 } 453 454 int 455 dtrace_getstackdepth(int aframes) 456 { 457 int depth = 0; 458 struct i386_frame *frame; 459 vm_offset_t ebp; 460 461 aframes++; 462 ebp = dtrace_getfp(); 463 frame = (struct i386_frame *)ebp; 464 depth++; 465 for(;;) { 466 if (!INKERNEL((long) frame)) 467 break; 468 if (!INKERNEL((long) frame->f_frame)) 469 break; 470 depth++; 471 if (frame->f_frame <= frame || 472 (vm_offset_t)frame->f_frame >= 473 (vm_offset_t)ebp + KSTACK_SIZE) 474 break; 475 frame = frame->f_frame; 476 } 477 if (depth < aframes) 478 return 0; 479 else 480 return depth - aframes; 481 } 482 483 #ifdef notyet 484 ulong_t 485 dtrace_getreg(struct regs *rp, uint_t reg) 486 { 487 #if defined(__amd64) 488 int regmap[] = { 489 REG_GS, /* GS */ 490 REG_FS, /* FS */ 491 REG_ES, /* ES */ 492 REG_DS, /* DS */ 493 REG_RDI, /* EDI */ 494 REG_RSI, /* ESI */ 495 REG_RBP, /* EBP */ 496 REG_RSP, /* ESP */ 497 REG_RBX, /* EBX */ 498 REG_RDX, /* EDX */ 499 REG_RCX, /* ECX */ 500 REG_RAX, /* EAX */ 501 REG_TRAPNO, /* TRAPNO */ 502 REG_ERR, /* ERR */ 503 REG_RIP, /* EIP */ 504 REG_CS, /* CS */ 505 REG_RFL, /* EFL */ 506 REG_RSP, /* UESP */ 507 REG_SS /* SS */ 508 }; 509 510 if (reg <= SS) { 511 if (reg >= sizeof (regmap) / sizeof (int)) { 512 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 513 return (0); 514 } 515 516 reg = regmap[reg]; 517 } else { 518 reg -= SS + 1; 519 } 520 521 switch (reg) { 522 case REG_RDI: 523 return (rp->r_rdi); 524 case REG_RSI: 525 return (rp->r_rsi); 526 case REG_RDX: 527 return (rp->r_rdx); 528 case REG_RCX: 529 return (rp->r_rcx); 530 case REG_R8: 531 return (rp->r_r8); 532 case REG_R9: 533 return (rp->r_r9); 534 case REG_RAX: 535 return (rp->r_rax); 536 case REG_RBX: 537 return (rp->r_rbx); 538 case REG_RBP: 539 return (rp->r_rbp); 540 case REG_R10: 541 return (rp->r_r10); 542 case REG_R11: 543 return (rp->r_r11); 544 case REG_R12: 545 return (rp->r_r12); 546 case REG_R13: 547 return (rp->r_r13); 548 case REG_R14: 549 return (rp->r_r14); 550 case REG_R15: 551 return (rp->r_r15); 552 case REG_DS: 553 return (rp->r_ds); 554 case REG_ES: 555 return (rp->r_es); 556 case REG_FS: 557 return (rp->r_fs); 558 case REG_GS: 559 return (rp->r_gs); 560 case REG_TRAPNO: 561 return (rp->r_trapno); 562 case REG_ERR: 563 return (rp->r_err); 564 case REG_RIP: 565 return (rp->r_rip); 566 case REG_CS: 567 return (rp->r_cs); 568 case REG_SS: 569 return (rp->r_ss); 570 case REG_RFL: 571 return (rp->r_rfl); 572 case REG_RSP: 573 return (rp->r_rsp); 574 default: 575 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 576 return (0); 577 } 578 579 #else 580 if (reg > SS) { 581 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 582 return (0); 583 } 584 585 return ((&rp->r_gs)[reg]); 586 #endif 587 } 588 #endif 589 590 static int 591 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 592 { 593 ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr); 594 595 if (uaddr + size >= kernelbase || uaddr + size < uaddr) { 596 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 597 cpu_core[cpu_number()].cpuc_dtrace_illval = uaddr; 598 return (0); 599 } 600 601 return (1); 602 } 603 604 void 605 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 606 volatile uint16_t *flags) 607 { 608 if (dtrace_copycheck(uaddr, kaddr, size)) 609 dtrace_copy(uaddr, kaddr, size); 610 } 611 612 void 613 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 614 volatile uint16_t *flags) 615 { 616 if (dtrace_copycheck(uaddr, kaddr, size)) 617 dtrace_copy(kaddr, uaddr, size); 618 } 619 620 void 621 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 622 volatile uint16_t *flags) 623 { 624 if (dtrace_copycheck(uaddr, kaddr, size)) 625 dtrace_copystr(uaddr, kaddr, size, flags); 626 } 627 628 void 629 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 630 volatile uint16_t *flags) 631 { 632 if (dtrace_copycheck(uaddr, kaddr, size)) 633 dtrace_copystr(kaddr, uaddr, size, flags); 634 } 635 636 uint8_t 637 dtrace_fuword8(void *uaddr) 638 { 639 if ((uintptr_t)uaddr >= kernelbase) { 640 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 641 cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr; 642 return (0); 643 } 644 return (dtrace_fuword8_nocheck(uaddr)); 645 } 646 647 uint16_t 648 dtrace_fuword16(void *uaddr) 649 { 650 if ((uintptr_t)uaddr >= kernelbase) { 651 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 652 cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr; 653 return (0); 654 } 655 return (dtrace_fuword16_nocheck(uaddr)); 656 } 657 658 uint32_t 659 dtrace_fuword32(void *uaddr) 660 { 661 if ((uintptr_t)uaddr >= kernelbase) { 662 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 663 cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr; 664 return (0); 665 } 666 return (dtrace_fuword32_nocheck(uaddr)); 667 } 668 669 uint64_t 670 dtrace_fuword64(void *uaddr) 671 { 672 if ((uintptr_t)uaddr >= kernelbase) { 673 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 674 cpu_core[cpu_number()].cpuc_dtrace_illval = (uintptr_t)uaddr; 675 return (0); 676 } 677 return (dtrace_fuword64_nocheck(uaddr)); 678 } 679