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