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