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