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/psl.h> 42 #include <machine/reg.h> 43 #include <machine/stack.h> 44 45 #include <vm/vm.h> 46 #include <vm/vm_param.h> 47 #include <vm/pmap.h> 48 49 #include "regset.h" 50 51 /* Offset to the LR Save word (ppc32) */ 52 #define RETURN_OFFSET 4 53 /* Offset to LR Save word (ppc64). CR Save area sits between back chain and LR */ 54 #define RETURN_OFFSET64 16 55 56 #ifdef __powerpc64__ 57 #define OFFSET 4 /* Account for the TOC reload slot */ 58 #define FRAME_OFFSET 48 59 #else 60 #define OFFSET 0 61 #define FRAME_OFFSET 8 62 #endif 63 64 #define INKERNEL(x) ((x) <= VM_MAX_KERNEL_ADDRESS && \ 65 (x) >= VM_MIN_KERNEL_ADDRESS) 66 67 static __inline int 68 dtrace_sp_inkernel(uintptr_t sp) 69 { 70 struct trapframe *frame; 71 vm_offset_t callpc; 72 73 #ifdef __powerpc64__ 74 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); 75 #else 76 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); 77 #endif 78 if ((callpc & 3) || (callpc < 0x100)) 79 return (0); 80 81 /* 82 * trapexit() and asttrapexit() are sentinels 83 * for kernel stack tracing. 84 */ 85 if (callpc + OFFSET == (vm_offset_t) &trapexit || 86 callpc + OFFSET == (vm_offset_t) &asttrapexit) { 87 if (sp == 0) 88 return (0); 89 frame = (struct trapframe *)(sp + FRAME_OFFSET); 90 91 return ((frame->srr1 & PSL_PR) == 0); 92 } 93 94 return (1); 95 } 96 97 static __inline uintptr_t 98 dtrace_next_sp(uintptr_t sp) 99 { 100 vm_offset_t callpc; 101 uintptr_t *r1; 102 struct trapframe *frame; 103 104 #ifdef __powerpc64__ 105 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); 106 #else 107 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); 108 #endif 109 110 /* 111 * trapexit() and asttrapexit() are sentinels 112 * for kernel stack tracing. 113 */ 114 if ((callpc + OFFSET == (vm_offset_t) &trapexit || 115 callpc + OFFSET == (vm_offset_t) &asttrapexit)) { 116 /* Access the trap frame */ 117 frame = (struct trapframe *)(sp + FRAME_OFFSET); 118 r1 = (uintptr_t *)frame->fixreg[1]; 119 if (r1 == NULL) 120 return (0); 121 return (*r1); 122 } 123 124 return (*(uintptr_t*)sp); 125 } 126 127 static __inline uintptr_t 128 dtrace_get_pc(uintptr_t sp) 129 { 130 struct trapframe *frame; 131 vm_offset_t callpc; 132 133 #ifdef __powerpc64__ 134 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); 135 #else 136 callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); 137 #endif 138 139 /* 140 * trapexit() and asttrapexit() are sentinels 141 * for kernel stack tracing. 142 */ 143 if ((callpc + OFFSET == (vm_offset_t) &trapexit || 144 callpc + OFFSET == (vm_offset_t) &asttrapexit)) { 145 /* Access the trap frame */ 146 frame = (struct trapframe *)(sp + FRAME_OFFSET); 147 return (frame->srr0); 148 } 149 150 return (callpc); 151 } 152 153 greg_t 154 dtrace_getfp(void) 155 { 156 return (greg_t)__builtin_frame_address(0); 157 } 158 159 void 160 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 161 uint32_t *intrpc) 162 { 163 int depth = 0; 164 uintptr_t osp, sp; 165 vm_offset_t callpc; 166 pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 167 168 osp = PAGE_SIZE; 169 if (intrpc != 0) 170 pcstack[depth++] = (pc_t) intrpc; 171 172 aframes++; 173 174 sp = dtrace_getfp(); 175 176 while (depth < pcstack_limit) { 177 if (sp <= osp) 178 break; 179 180 if (!dtrace_sp_inkernel(sp)) 181 break; 182 callpc = dtrace_get_pc(sp); 183 184 if (aframes > 0) { 185 aframes--; 186 if ((aframes == 0) && (caller != 0)) { 187 pcstack[depth++] = caller; 188 } 189 } 190 else { 191 pcstack[depth++] = callpc; 192 } 193 194 osp = sp; 195 sp = dtrace_next_sp(sp); 196 } 197 198 for (; depth < pcstack_limit; depth++) { 199 pcstack[depth] = 0; 200 } 201 } 202 203 static int 204 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 205 uintptr_t sp) 206 { 207 proc_t *p = curproc; 208 int ret = 0; 209 210 ASSERT(pcstack == NULL || pcstack_limit > 0); 211 212 while (pc != 0) { 213 ret++; 214 if (pcstack != NULL) { 215 *pcstack++ = (uint64_t)pc; 216 pcstack_limit--; 217 if (pcstack_limit <= 0) 218 break; 219 } 220 221 if (sp == 0) 222 break; 223 224 if (SV_PROC_FLAG(p, SV_ILP32)) { 225 pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); 226 sp = dtrace_fuword32((void *)sp); 227 } 228 else { 229 pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); 230 sp = dtrace_fuword64((void *)sp); 231 } 232 } 233 234 return (ret); 235 } 236 237 void 238 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 239 { 240 proc_t *p = curproc; 241 struct trapframe *tf; 242 uintptr_t pc, sp; 243 volatile uint16_t *flags = 244 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 245 int n; 246 247 if (*flags & CPU_DTRACE_FAULT) 248 return; 249 250 if (pcstack_limit <= 0) 251 return; 252 253 /* 254 * If there's no user context we still need to zero the stack. 255 */ 256 if (p == NULL || (tf = curthread->td_frame) == NULL) 257 goto zero; 258 259 *pcstack++ = (uint64_t)p->p_pid; 260 pcstack_limit--; 261 262 if (pcstack_limit <= 0) 263 return; 264 265 pc = tf->srr0; 266 sp = tf->fixreg[1]; 267 268 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 269 /* 270 * In an entry probe. The frame pointer has not yet been 271 * pushed (that happens in the function prologue). The 272 * best approach is to add the current pc as a missing top 273 * of stack and back the pc up to the caller, which is stored 274 * at the current stack pointer address since the call 275 * instruction puts it there right before the branch. 276 */ 277 278 *pcstack++ = (uint64_t)pc; 279 pcstack_limit--; 280 if (pcstack_limit <= 0) 281 return; 282 283 pc = tf->lr; 284 } 285 286 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); 287 ASSERT(n >= 0); 288 ASSERT(n <= pcstack_limit); 289 290 pcstack += n; 291 pcstack_limit -= n; 292 293 zero: 294 while (pcstack_limit-- > 0) 295 *pcstack++ = 0; 296 } 297 298 int 299 dtrace_getustackdepth(void) 300 { 301 proc_t *p = curproc; 302 struct trapframe *tf; 303 uintptr_t pc, sp; 304 int n = 0; 305 306 if (p == NULL || (tf = curthread->td_frame) == NULL) 307 return (0); 308 309 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) 310 return (-1); 311 312 pc = tf->srr0; 313 sp = tf->fixreg[1]; 314 315 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 316 /* 317 * In an entry probe. The frame pointer has not yet been 318 * pushed (that happens in the function prologue). The 319 * best approach is to add the current pc as a missing top 320 * of stack and back the pc up to the caller, which is stored 321 * at the current stack pointer address since the call 322 * instruction puts it there right before the branch. 323 */ 324 325 if (SV_PROC_FLAG(p, SV_ILP32)) { 326 pc = dtrace_fuword32((void *) sp); 327 } 328 else 329 pc = dtrace_fuword64((void *) sp); 330 n++; 331 } 332 333 n += dtrace_getustack_common(NULL, 0, pc, sp); 334 335 return (n); 336 } 337 338 void 339 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 340 { 341 proc_t *p = curproc; 342 struct trapframe *tf; 343 uintptr_t pc, sp; 344 volatile uint16_t *flags = 345 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 346 #ifdef notyet /* XXX signal stack */ 347 uintptr_t oldcontext; 348 size_t s1, s2; 349 #endif 350 351 if (*flags & CPU_DTRACE_FAULT) 352 return; 353 354 if (pcstack_limit <= 0) 355 return; 356 357 /* 358 * If there's no user context we still need to zero the stack. 359 */ 360 if (p == NULL || (tf = curthread->td_frame) == NULL) 361 goto zero; 362 363 *pcstack++ = (uint64_t)p->p_pid; 364 pcstack_limit--; 365 366 if (pcstack_limit <= 0) 367 return; 368 369 pc = tf->srr0; 370 sp = tf->fixreg[1]; 371 372 #ifdef notyet /* XXX signal stack */ 373 oldcontext = lwp->lwp_oldcontext; 374 s1 = sizeof (struct xframe) + 2 * sizeof (long); 375 s2 = s1 + sizeof (siginfo_t); 376 #endif 377 378 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 379 *pcstack++ = (uint64_t)pc; 380 *fpstack++ = 0; 381 pcstack_limit--; 382 if (pcstack_limit <= 0) 383 return; 384 385 if (SV_PROC_FLAG(p, SV_ILP32)) { 386 pc = dtrace_fuword32((void *)sp); 387 } 388 else { 389 pc = dtrace_fuword64((void *)sp); 390 } 391 } 392 393 while (pc != 0) { 394 *pcstack++ = (uint64_t)pc; 395 *fpstack++ = sp; 396 pcstack_limit--; 397 if (pcstack_limit <= 0) 398 break; 399 400 if (sp == 0) 401 break; 402 403 #ifdef notyet /* XXX signal stack */ 404 if (oldcontext == sp + s1 || oldcontext == sp + s2) { 405 ucontext_t *ucp = (ucontext_t *)oldcontext; 406 greg_t *gregs = ucp->uc_mcontext.gregs; 407 408 sp = dtrace_fulword(&gregs[REG_FP]); 409 pc = dtrace_fulword(&gregs[REG_PC]); 410 411 oldcontext = dtrace_fulword(&ucp->uc_link); 412 } else 413 #endif /* XXX */ 414 { 415 if (SV_PROC_FLAG(p, SV_ILP32)) { 416 pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); 417 sp = dtrace_fuword32((void *)sp); 418 } 419 else { 420 pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); 421 sp = dtrace_fuword64((void *)sp); 422 } 423 } 424 425 /* 426 * This is totally bogus: if we faulted, we're going to clear 427 * the fault and break. This is to deal with the apparently 428 * broken Java stacks on x86. 429 */ 430 if (*flags & CPU_DTRACE_FAULT) { 431 *flags &= ~CPU_DTRACE_FAULT; 432 break; 433 } 434 } 435 436 zero: 437 while (pcstack_limit-- > 0) 438 *pcstack++ = 0; 439 } 440 441 /*ARGSUSED*/ 442 uint64_t 443 dtrace_getarg(int arg, int aframes) 444 { 445 uintptr_t val; 446 uintptr_t *fp = (uintptr_t *)dtrace_getfp(); 447 uintptr_t *stack; 448 int i; 449 450 /* 451 * A total of 8 arguments are passed via registers; any argument with 452 * index of 7 or lower is therefore in a register. 453 */ 454 int inreg = 7; 455 456 for (i = 1; i <= aframes; i++) { 457 fp = (uintptr_t *)*fp; 458 459 /* 460 * On ppc32 AIM, and booke, trapexit() is the immediately following 461 * label. On ppc64 AIM trapexit() follows a nop. 462 */ 463 #ifdef __powerpc64__ 464 if ((long)(fp[2]) + 4 == (long)trapexit) { 465 #else 466 if ((long)(fp[1]) == (long)trapexit) { 467 #endif 468 /* 469 * In the case of powerpc, we will use the pointer to the regs 470 * structure that was pushed when we took the trap. To get this 471 * structure, we must increment beyond the frame structure. If the 472 * argument that we're seeking is passed on the stack, we'll pull 473 * the true stack pointer out of the saved registers and decrement 474 * our argument by the number of arguments passed in registers; if 475 * the argument we're seeking is passed in regsiters, we can just 476 * load it directly. 477 */ 478 #ifdef __powerpc64__ 479 struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48); 480 #else 481 struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8); 482 #endif 483 484 if (arg <= inreg) { 485 stack = &rp->fixreg[3]; 486 } else { 487 stack = (uintptr_t *)(rp->fixreg[1]); 488 arg -= inreg; 489 } 490 goto load; 491 } 492 493 } 494 495 /* 496 * We know that we did not come through a trap to get into 497 * dtrace_probe() -- the provider simply called dtrace_probe() 498 * directly. As this is the case, we need to shift the argument 499 * that we're looking for: the probe ID is the first argument to 500 * dtrace_probe(), so the argument n will actually be found where 501 * one would expect to find argument (n + 1). 502 */ 503 arg++; 504 505 if (arg <= inreg) { 506 /* 507 * This shouldn't happen. If the argument is passed in a 508 * register then it should have been, well, passed in a 509 * register... 510 */ 511 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 512 return (0); 513 } 514 515 arg -= (inreg + 1); 516 stack = fp + 2; 517 518 load: 519 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 520 val = stack[arg]; 521 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); 522 523 return (val); 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)) 542 break; 543 544 if (aframes == 0) 545 depth++; 546 else 547 aframes--; 548 osp = sp; 549 sp = dtrace_next_sp(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 32: 565 return (rp->lr); 566 case 33: 567 return (rp->cr); 568 case 34: 569 return (rp->xer); 570 case 35: 571 return (rp->ctr); 572 case 36: 573 return (rp->srr0); 574 case 37: 575 return (rp->srr1); 576 case 38: 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