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 * Portions Copyright 2012,2013 Justin Hibbits <jhibbits@freebsd.org> 23 * 24 * $FreeBSD$ 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 #include <sys/stack.h> 36 #include <sys/sysent.h> 37 #include <sys/pcpu.h> 38 39 #include <machine/frame.h> 40 #include <machine/md_var.h> 41 #include <machine/reg.h> 42 #include <machine/stack.h> 43 44 #include <vm/vm.h> 45 #include <vm/vm_param.h> 46 #include <vm/pmap.h> 47 48 #include "regset.h" 49 50 /* Offset to the LR Save word (ppc32) */ 51 #define RETURN_OFFSET 4 52 /* Offset to LR Save word (ppc64). CR Save area sits between back chain and LR */ 53 #define RETURN_OFFSET64 16 54 55 #ifdef __powerpc64__ 56 #define OFFSET 4 /* Account for the TOC reload slot */ 57 #else 58 #define OFFSET 0 59 #endif 60 61 #define INKERNEL(x) ((x) <= VM_MAX_KERNEL_ADDRESS && \ 62 (x) >= VM_MIN_KERNEL_ADDRESS) 63 64 static __inline int 65 dtrace_sp_inkernel(uintptr_t sp, int aframes) 66 { 67 vm_offset_t callpc; 68 69 #ifdef __powerpc64__ 70 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); 71 #else 72 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); 73 #endif 74 if ((callpc & 3) || (callpc < 0x100)) 75 return (0); 76 77 /* 78 * trapexit() and asttrapexit() are sentinels 79 * for kernel stack tracing. 80 * 81 * Special-case this for 'aframes == 0', because fbt sets aframes to the 82 * trap callchain depth, so we want to break out of it. 83 */ 84 if ((callpc + OFFSET == (vm_offset_t) &trapexit || 85 callpc + OFFSET == (vm_offset_t) &asttrapexit) && 86 aframes != 0) 87 return (0); 88 89 return (1); 90 } 91 92 static __inline uintptr_t 93 dtrace_next_sp(uintptr_t sp) 94 { 95 vm_offset_t callpc; 96 97 #ifdef __powerpc64__ 98 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); 99 #else 100 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); 101 #endif 102 103 /* 104 * trapexit() and asttrapexit() are sentinels 105 * for kernel stack tracing. 106 * 107 * Special-case this for 'aframes == 0', because fbt sets aframes to the 108 * trap callchain depth, so we want to break out of it. 109 */ 110 if ((callpc + OFFSET == (vm_offset_t) &trapexit || 111 callpc + OFFSET == (vm_offset_t) &asttrapexit)) 112 /* Access the trap frame */ 113 #ifdef __powerpc64__ 114 return (*(uintptr_t *)sp + 48 + sizeof(register_t)); 115 #else 116 return (*(uintptr_t *)sp + 8 + sizeof(register_t)); 117 #endif 118 119 return (*(uintptr_t*)sp); 120 } 121 122 static __inline uintptr_t 123 dtrace_get_pc(uintptr_t sp) 124 { 125 vm_offset_t callpc; 126 127 #ifdef __powerpc64__ 128 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); 129 #else 130 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); 131 #endif 132 133 /* 134 * trapexit() and asttrapexit() are sentinels 135 * for kernel stack tracing. 136 * 137 * Special-case this for 'aframes == 0', because fbt sets aframes to the 138 * trap callchain depth, so we want to break out of it. 139 */ 140 if ((callpc + OFFSET == (vm_offset_t) &trapexit || 141 callpc + OFFSET == (vm_offset_t) &asttrapexit)) 142 /* Access the trap frame */ 143 #ifdef __powerpc64__ 144 return (*(uintptr_t *)sp + 48 + offsetof(struct trapframe, lr)); 145 #else 146 return (*(uintptr_t *)sp + 8 + offsetof(struct trapframe, lr)); 147 #endif 148 149 return (callpc); 150 } 151 152 greg_t 153 dtrace_getfp(void) 154 { 155 return (greg_t)__builtin_frame_address(0); 156 } 157 158 void 159 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 160 uint32_t *intrpc) 161 { 162 int depth = 0; 163 uintptr_t osp, sp; 164 vm_offset_t callpc; 165 pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 166 167 osp = PAGE_SIZE; 168 if (intrpc != 0) 169 pcstack[depth++] = (pc_t) intrpc; 170 171 aframes++; 172 173 sp = dtrace_getfp(); 174 175 while (depth < pcstack_limit) { 176 if (sp <= osp) 177 break; 178 179 if (!dtrace_sp_inkernel(sp, aframes)) 180 break; 181 callpc = dtrace_get_pc(sp); 182 183 if (aframes > 0) { 184 aframes--; 185 if ((aframes == 0) && (caller != 0)) { 186 pcstack[depth++] = caller; 187 } 188 } 189 else { 190 pcstack[depth++] = callpc; 191 } 192 193 osp = sp; 194 sp = dtrace_next_sp(sp); 195 } 196 197 for (; depth < pcstack_limit; depth++) { 198 pcstack[depth] = 0; 199 } 200 } 201 202 static int 203 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 204 uintptr_t sp) 205 { 206 proc_t *p = curproc; 207 int ret = 0; 208 209 ASSERT(pcstack == NULL || pcstack_limit > 0); 210 211 while (pc != 0) { 212 ret++; 213 if (pcstack != NULL) { 214 *pcstack++ = (uint64_t)pc; 215 pcstack_limit--; 216 if (pcstack_limit <= 0) 217 break; 218 } 219 220 if (sp == 0) 221 break; 222 223 if (SV_PROC_FLAG(p, SV_ILP32)) { 224 pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); 225 sp = dtrace_fuword32((void *)sp); 226 } 227 else { 228 pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); 229 sp = dtrace_fuword64((void *)sp); 230 } 231 } 232 233 return (ret); 234 } 235 236 void 237 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 238 { 239 proc_t *p = curproc; 240 struct trapframe *tf; 241 uintptr_t pc, sp; 242 volatile uint16_t *flags = 243 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 244 int n; 245 246 if (*flags & CPU_DTRACE_FAULT) 247 return; 248 249 if (pcstack_limit <= 0) 250 return; 251 252 /* 253 * If there's no user context we still need to zero the stack. 254 */ 255 if (p == NULL || (tf = curthread->td_frame) == NULL) 256 goto zero; 257 258 *pcstack++ = (uint64_t)p->p_pid; 259 pcstack_limit--; 260 261 if (pcstack_limit <= 0) 262 return; 263 264 pc = tf->srr0; 265 sp = tf->fixreg[1]; 266 267 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 268 /* 269 * In an entry probe. The frame pointer has not yet been 270 * pushed (that happens in the function prologue). The 271 * best approach is to add the current pc as a missing top 272 * of stack and back the pc up to the caller, which is stored 273 * at the current stack pointer address since the call 274 * instruction puts it there right before the branch. 275 */ 276 277 *pcstack++ = (uint64_t)pc; 278 pcstack_limit--; 279 if (pcstack_limit <= 0) 280 return; 281 282 pc = tf->lr; 283 } 284 285 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); 286 ASSERT(n >= 0); 287 ASSERT(n <= pcstack_limit); 288 289 pcstack += n; 290 pcstack_limit -= n; 291 292 zero: 293 while (pcstack_limit-- > 0) 294 *pcstack++ = 0; 295 } 296 297 int 298 dtrace_getustackdepth(void) 299 { 300 proc_t *p = curproc; 301 struct trapframe *tf; 302 uintptr_t pc, sp; 303 int n = 0; 304 305 if (p == NULL || (tf = curthread->td_frame) == NULL) 306 return (0); 307 308 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) 309 return (-1); 310 311 pc = tf->srr0; 312 sp = tf->fixreg[1]; 313 314 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 315 /* 316 * In an entry probe. The frame pointer has not yet been 317 * pushed (that happens in the function prologue). The 318 * best approach is to add the current pc as a missing top 319 * of stack and back the pc up to the caller, which is stored 320 * at the current stack pointer address since the call 321 * instruction puts it there right before the branch. 322 */ 323 324 if (SV_PROC_FLAG(p, SV_ILP32)) { 325 pc = dtrace_fuword32((void *) sp); 326 } 327 else 328 pc = dtrace_fuword64((void *) sp); 329 n++; 330 } 331 332 n += dtrace_getustack_common(NULL, 0, pc, sp); 333 334 return (n); 335 } 336 337 void 338 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 339 { 340 proc_t *p = curproc; 341 struct trapframe *tf; 342 uintptr_t pc, sp; 343 volatile uint16_t *flags = 344 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 345 #ifdef notyet /* XXX signal stack */ 346 uintptr_t oldcontext; 347 size_t s1, s2; 348 #endif 349 350 if (*flags & CPU_DTRACE_FAULT) 351 return; 352 353 if (pcstack_limit <= 0) 354 return; 355 356 /* 357 * If there's no user context we still need to zero the stack. 358 */ 359 if (p == NULL || (tf = curthread->td_frame) == NULL) 360 goto zero; 361 362 *pcstack++ = (uint64_t)p->p_pid; 363 pcstack_limit--; 364 365 if (pcstack_limit <= 0) 366 return; 367 368 pc = tf->srr0; 369 sp = tf->fixreg[1]; 370 371 #ifdef notyet /* XXX signal stack */ 372 oldcontext = lwp->lwp_oldcontext; 373 s1 = sizeof (struct xframe) + 2 * sizeof (long); 374 s2 = s1 + sizeof (siginfo_t); 375 #endif 376 377 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 378 *pcstack++ = (uint64_t)pc; 379 *fpstack++ = 0; 380 pcstack_limit--; 381 if (pcstack_limit <= 0) 382 return; 383 384 if (SV_PROC_FLAG(p, SV_ILP32)) { 385 pc = dtrace_fuword32((void *)sp); 386 } 387 else { 388 pc = dtrace_fuword64((void *)sp); 389 } 390 } 391 392 while (pc != 0) { 393 *pcstack++ = (uint64_t)pc; 394 *fpstack++ = sp; 395 pcstack_limit--; 396 if (pcstack_limit <= 0) 397 break; 398 399 if (sp == 0) 400 break; 401 402 #ifdef notyet /* XXX signal stack */ 403 if (oldcontext == sp + s1 || oldcontext == sp + s2) { 404 ucontext_t *ucp = (ucontext_t *)oldcontext; 405 greg_t *gregs = ucp->uc_mcontext.gregs; 406 407 sp = dtrace_fulword(&gregs[REG_FP]); 408 pc = dtrace_fulword(&gregs[REG_PC]); 409 410 oldcontext = dtrace_fulword(&ucp->uc_link); 411 } else 412 #endif /* XXX */ 413 { 414 if (SV_PROC_FLAG(p, SV_ILP32)) { 415 pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); 416 sp = dtrace_fuword32((void *)sp); 417 } 418 else { 419 pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); 420 sp = dtrace_fuword64((void *)sp); 421 } 422 } 423 424 /* 425 * This is totally bogus: if we faulted, we're going to clear 426 * the fault and break. This is to deal with the apparently 427 * broken Java stacks on x86. 428 */ 429 if (*flags & CPU_DTRACE_FAULT) { 430 *flags &= ~CPU_DTRACE_FAULT; 431 break; 432 } 433 } 434 435 zero: 436 while (pcstack_limit-- > 0) 437 *pcstack++ = 0; 438 } 439 440 /*ARGSUSED*/ 441 uint64_t 442 dtrace_getarg(int arg, int aframes) 443 { 444 uintptr_t val; 445 uintptr_t *fp = (uintptr_t *)dtrace_getfp(); 446 uintptr_t *stack; 447 int i; 448 449 /* 450 * A total of 8 arguments are passed via registers; any argument with 451 * index of 7 or lower is therefore in a register. 452 */ 453 int inreg = 7; 454 455 for (i = 1; i <= aframes; i++) { 456 fp = (uintptr_t *)*fp; 457 458 /* 459 * On ppc32 AIM, and booke, trapexit() is the immediately following 460 * label. On ppc64 AIM trapexit() follows a nop. 461 */ 462 #ifdef __powerpc64__ 463 if ((long)(fp[2]) + 4 == (long)trapexit) { 464 #else 465 if ((long)(fp[1]) == (long)trapexit) { 466 #endif 467 /* 468 * In the case of powerpc, we will use the pointer to the regs 469 * structure that was pushed when we took the trap. To get this 470 * structure, we must increment beyond the frame structure. If the 471 * argument that we're seeking is passed on the stack, we'll pull 472 * the true stack pointer out of the saved registers and decrement 473 * our argument by the number of arguments passed in registers; if 474 * the argument we're seeking is passed in regsiters, we can just 475 * load it directly. 476 */ 477 #ifdef __powerpc64__ 478 struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48); 479 #else 480 struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8); 481 #endif 482 483 if (arg <= inreg) { 484 stack = &rp->fixreg[3]; 485 } else { 486 stack = (uintptr_t *)(rp->fixreg[1]); 487 arg -= inreg; 488 } 489 goto load; 490 } 491 492 } 493 494 /* 495 * We know that we did not come through a trap to get into 496 * dtrace_probe() -- the provider simply called dtrace_probe() 497 * directly. As this is the case, we need to shift the argument 498 * that we're looking for: the probe ID is the first argument to 499 * dtrace_probe(), so the argument n will actually be found where 500 * one would expect to find argument (n + 1). 501 */ 502 arg++; 503 504 if (arg <= inreg) { 505 /* 506 * This shouldn't happen. If the argument is passed in a 507 * register then it should have been, well, passed in a 508 * register... 509 */ 510 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 511 return (0); 512 } 513 514 arg -= (inreg + 1); 515 stack = fp + 2; 516 517 load: 518 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 519 val = stack[arg]; 520 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); 521 522 return (val); 523 return (0); 524 } 525 526 int 527 dtrace_getstackdepth(int aframes) 528 { 529 int depth = 0; 530 uintptr_t osp, sp; 531 vm_offset_t callpc; 532 533 osp = PAGE_SIZE; 534 aframes++; 535 sp = dtrace_getfp(); 536 depth++; 537 for(;;) { 538 if (sp <= osp) 539 break; 540 541 if (!dtrace_sp_inkernel(sp, aframes)) 542 break; 543 544 if (aframes == 0) 545 depth++; 546 else 547 aframes--; 548 osp = sp; 549 sp = *(uintptr_t *)sp; 550 } 551 if (depth < aframes) 552 return (0); 553 554 return (depth); 555 } 556 557 ulong_t 558 dtrace_getreg(struct trapframe *rp, uint_t reg) 559 { 560 if (reg < 32) 561 return (rp->fixreg[reg]); 562 563 switch (reg) { 564 case 33: 565 return (rp->lr); 566 case 34: 567 return (rp->cr); 568 case 35: 569 return (rp->xer); 570 case 36: 571 return (rp->ctr); 572 case 37: 573 return (rp->srr0); 574 case 38: 575 return (rp->srr1); 576 case 39: 577 return (rp->exc); 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 if (copyin((const void *)uaddr, (void *)kaddr, size)) { 604 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 605 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 606 } 607 } 608 609 void 610 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 611 volatile uint16_t *flags) 612 { 613 if (dtrace_copycheck(uaddr, kaddr, size)) { 614 if (copyout((const void *)kaddr, (void *)uaddr, size)) { 615 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 616 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 617 } 618 } 619 } 620 621 void 622 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 623 volatile uint16_t *flags) 624 { 625 size_t actual; 626 int error; 627 628 if (dtrace_copycheck(uaddr, kaddr, size)) { 629 error = copyinstr((const void *)uaddr, (void *)kaddr, 630 size, &actual); 631 632 /* ENAMETOOLONG is not a fault condition. */ 633 if (error && error != ENAMETOOLONG) { 634 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 635 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 636 } 637 } 638 } 639 640 /* 641 * The bulk of this function could be replaced to match dtrace_copyinstr() 642 * if we ever implement a copyoutstr(). 643 */ 644 void 645 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 646 volatile uint16_t *flags) 647 { 648 size_t len; 649 650 if (dtrace_copycheck(uaddr, kaddr, size)) { 651 len = strlen((const char *)kaddr); 652 if (len > size) 653 len = size; 654 655 if (copyout((const void *)kaddr, (void *)uaddr, len)) { 656 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 657 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 658 } 659 } 660 } 661 662 uint8_t 663 dtrace_fuword8(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 (fubyte(uaddr)); 671 } 672 673 uint16_t 674 dtrace_fuword16(void *uaddr) 675 { 676 uint16_t ret = 0; 677 678 if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { 679 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { 680 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 681 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 682 } 683 } 684 return ret; 685 } 686 687 uint32_t 688 dtrace_fuword32(void *uaddr) 689 { 690 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 691 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 692 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 693 return (0); 694 } 695 return (fuword32(uaddr)); 696 } 697 698 uint64_t 699 dtrace_fuword64(void *uaddr) 700 { 701 uint64_t ret = 0; 702 703 if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { 704 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { 705 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 706 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 707 } 708 } 709 return ret; 710 } 711 712 uintptr_t 713 dtrace_fulword(void *uaddr) 714 { 715 uintptr_t ret = 0; 716 717 if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { 718 if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { 719 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 720 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 721 } 722 } 723 return ret; 724 } 725