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