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