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