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 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #include <sys/cdefs.h> 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/dtrace_impl.h> 31 #include <sys/kernel.h> 32 #include <sys/stack.h> 33 #include <sys/pcpu.h> 34 35 #include <machine/frame.h> 36 #include <machine/md_var.h> 37 #include <machine/pcb.h> 38 #include <machine/stack.h> 39 40 #include <vm/vm.h> 41 #include <vm/vm_param.h> 42 #include <vm/pmap.h> 43 44 #include "regset.h" 45 46 extern uintptr_t kernbase; 47 uintptr_t kernelbase = (uintptr_t) &kernbase; 48 49 uint8_t dtrace_fuword8_nocheck(void *); 50 uint16_t dtrace_fuword16_nocheck(void *); 51 uint32_t dtrace_fuword32_nocheck(void *); 52 uint64_t dtrace_fuword64_nocheck(void *); 53 54 int dtrace_ustackdepth_max = 2048; 55 56 void 57 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 58 uint32_t *intrpc) 59 { 60 int depth = 0; 61 register_t ebp; 62 struct i386_frame *frame; 63 vm_offset_t callpc; 64 pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 65 66 if (intrpc != 0) 67 pcstack[depth++] = (pc_t) intrpc; 68 69 aframes++; 70 71 __asm __volatile("movl %%ebp,%0" : "=r" (ebp)); 72 73 frame = (struct i386_frame *)ebp; 74 while (depth < pcstack_limit) { 75 if (!kstack_contains(curthread, (vm_offset_t)frame, 76 sizeof(*frame))) 77 break; 78 79 callpc = frame->f_retaddr; 80 81 if (!INKERNEL(callpc)) 82 break; 83 84 if (aframes > 0) { 85 aframes--; 86 if ((aframes == 0) && (caller != 0)) { 87 pcstack[depth++] = caller; 88 } 89 } 90 else { 91 pcstack[depth++] = callpc; 92 } 93 94 if (frame->f_frame <= frame) 95 break; 96 frame = frame->f_frame; 97 } 98 99 for (; depth < pcstack_limit; depth++) { 100 pcstack[depth] = 0; 101 } 102 } 103 104 static int 105 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 106 uintptr_t sp) 107 { 108 #ifdef notyet 109 proc_t *p = curproc; 110 uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */ 111 size_t s1, s2; 112 #endif 113 uintptr_t oldsp; 114 volatile uint16_t *flags = 115 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 116 int ret = 0; 117 118 ASSERT(pcstack == NULL || pcstack_limit > 0); 119 ASSERT(dtrace_ustackdepth_max > 0); 120 121 #ifdef notyet /* XXX signal stack. */ 122 if (p->p_model == DATAMODEL_NATIVE) { 123 s1 = sizeof (struct frame) + 2 * sizeof (long); 124 s2 = s1 + sizeof (siginfo_t); 125 } else { 126 s1 = sizeof (struct frame32) + 3 * sizeof (int); 127 s2 = s1 + sizeof (siginfo32_t); 128 } 129 #endif 130 131 while (pc != 0) { 132 /* 133 * We limit the number of times we can go around this 134 * loop to account for a circular stack. 135 */ 136 if (ret++ >= dtrace_ustackdepth_max) { 137 *flags |= CPU_DTRACE_BADSTACK; 138 cpu_core[curcpu].cpuc_dtrace_illval = sp; 139 break; 140 } 141 142 if (pcstack != NULL) { 143 *pcstack++ = (uint64_t)pc; 144 pcstack_limit--; 145 if (pcstack_limit <= 0) 146 break; 147 } 148 149 if (sp == 0) 150 break; 151 152 oldsp = sp; 153 154 #ifdef notyet /* XXX signal stack. */ 155 if (oldcontext == sp + s1 || oldcontext == sp + s2) { 156 if (p->p_model == DATAMODEL_NATIVE) { 157 ucontext_t *ucp = (ucontext_t *)oldcontext; 158 greg_t *gregs = ucp->uc_mcontext.gregs; 159 160 sp = dtrace_fulword(&gregs[REG_FP]); 161 pc = dtrace_fulword(&gregs[REG_PC]); 162 163 oldcontext = dtrace_fulword(&ucp->uc_link); 164 } else { 165 ucontext32_t *ucp = (ucontext32_t *)oldcontext; 166 greg32_t *gregs = ucp->uc_mcontext.gregs; 167 168 sp = dtrace_fuword32(&gregs[EBP]); 169 pc = dtrace_fuword32(&gregs[EIP]); 170 171 oldcontext = dtrace_fuword32(&ucp->uc_link); 172 } 173 } else { 174 if (p->p_model == DATAMODEL_NATIVE) { 175 struct frame *fr = (struct frame *)sp; 176 177 pc = dtrace_fulword(&fr->fr_savpc); 178 sp = dtrace_fulword(&fr->fr_savfp); 179 } else { 180 struct frame32 *fr = (struct frame32 *)sp; 181 182 pc = dtrace_fuword32(&fr->fr_savpc); 183 sp = dtrace_fuword32(&fr->fr_savfp); 184 } 185 } 186 #else 187 pc = dtrace_fuword32((void *)(sp + 188 offsetof(struct i386_frame, f_retaddr))); 189 sp = dtrace_fuword32((void *)sp); 190 #endif /* ! notyet */ 191 192 if (sp == oldsp) { 193 *flags |= CPU_DTRACE_BADSTACK; 194 cpu_core[curcpu].cpuc_dtrace_illval = sp; 195 break; 196 } 197 198 /* 199 * This is totally bogus: if we faulted, we're going to clear 200 * the fault and break. This is to deal with the apparently 201 * broken Java stacks on x86. 202 */ 203 if (*flags & CPU_DTRACE_FAULT) { 204 *flags &= ~CPU_DTRACE_FAULT; 205 break; 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, fp; 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->tf_eip; 241 fp = tf->tf_ebp; 242 sp = tf->tf_esp; 243 244 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 245 /* 246 * In an entry probe. The frame pointer has not yet been 247 * pushed (that happens in the function prologue). The 248 * best approach is to add the current pc as a missing top 249 * of stack and back the pc up to the caller, which is stored 250 * at the current stack pointer address since the call 251 * instruction puts it there right before the branch. 252 */ 253 254 *pcstack++ = (uint64_t)pc; 255 pcstack_limit--; 256 if (pcstack_limit <= 0) 257 return; 258 259 pc = dtrace_fuword32((void *) sp); 260 } 261 262 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); 263 ASSERT(n >= 0); 264 ASSERT(n <= pcstack_limit); 265 266 pcstack += n; 267 pcstack_limit -= n; 268 269 zero: 270 while (pcstack_limit-- > 0) 271 *pcstack++ = 0; 272 } 273 274 int 275 dtrace_getustackdepth(void) 276 { 277 proc_t *p = curproc; 278 struct trapframe *tf; 279 uintptr_t pc, fp, sp; 280 int n = 0; 281 282 if (p == NULL || (tf = curthread->td_frame) == NULL) 283 return (0); 284 285 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) 286 return (-1); 287 288 pc = tf->tf_eip; 289 fp = tf->tf_ebp; 290 sp = tf->tf_esp; 291 292 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 293 /* 294 * In an entry probe. The frame pointer has not yet been 295 * pushed (that happens in the function prologue). The 296 * best approach is to add the current pc as a missing top 297 * of stack and back the pc up to the caller, which is stored 298 * at the current stack pointer address since the call 299 * instruction puts it there right before the branch. 300 */ 301 302 pc = dtrace_fuword32((void *) sp); 303 n++; 304 } 305 306 n += dtrace_getustack_common(NULL, 0, pc, fp); 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, fp; 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->tf_eip; 343 fp = tf->tf_ebp; 344 sp = tf->tf_esp; 345 346 #ifdef notyet /* XXX signal stack */ 347 oldcontext = lwp->lwp_oldcontext; 348 349 if (p->p_model == DATAMODEL_NATIVE) { 350 s1 = sizeof (struct frame) + 2 * sizeof (long); 351 s2 = s1 + sizeof (siginfo_t); 352 } else { 353 s1 = sizeof (struct frame32) + 3 * sizeof (int); 354 s2 = s1 + sizeof (siginfo32_t); 355 } 356 #endif 357 358 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 359 *pcstack++ = (uint64_t)pc; 360 *fpstack++ = 0; 361 pcstack_limit--; 362 if (pcstack_limit <= 0) 363 return; 364 365 pc = dtrace_fuword32((void *)sp); 366 } 367 368 while (pc != 0) { 369 *pcstack++ = (uint64_t)pc; 370 *fpstack++ = fp; 371 pcstack_limit--; 372 if (pcstack_limit <= 0) 373 break; 374 375 if (fp == 0) 376 break; 377 378 #ifdef notyet /* XXX signal stack */ 379 if (oldcontext == sp + s1 || oldcontext == sp + s2) { 380 if (p->p_model == DATAMODEL_NATIVE) { 381 ucontext_t *ucp = (ucontext_t *)oldcontext; 382 greg_t *gregs = ucp->uc_mcontext.gregs; 383 384 sp = dtrace_fulword(&gregs[REG_FP]); 385 pc = dtrace_fulword(&gregs[REG_PC]); 386 387 oldcontext = dtrace_fulword(&ucp->uc_link); 388 } else { 389 ucontext_t *ucp = (ucontext_t *)oldcontext; 390 greg_t *gregs = ucp->uc_mcontext.gregs; 391 392 sp = dtrace_fuword32(&gregs[EBP]); 393 pc = dtrace_fuword32(&gregs[EIP]); 394 395 oldcontext = dtrace_fuword32(&ucp->uc_link); 396 } 397 } else 398 #endif /* XXX */ 399 { 400 pc = dtrace_fuword32((void *)(fp + 401 offsetof(struct i386_frame, f_retaddr))); 402 fp = dtrace_fuword32((void *)fp); 403 } 404 405 /* 406 * This is totally bogus: if we faulted, we're going to clear 407 * the fault and break. This is to deal with the apparently 408 * broken Java stacks on x86. 409 */ 410 if (*flags & CPU_DTRACE_FAULT) { 411 *flags &= ~CPU_DTRACE_FAULT; 412 break; 413 } 414 } 415 416 zero: 417 while (pcstack_limit-- > 0) 418 *pcstack++ = 0; 419 } 420 421 uint64_t 422 dtrace_getarg(int arg, int aframes) 423 { 424 struct trapframe *frame; 425 struct i386_frame *fp = (struct i386_frame *)dtrace_getfp(); 426 uintptr_t *stack, val; 427 int i; 428 429 for (i = 1; i <= aframes; i++) { 430 fp = fp->f_frame; 431 432 if (roundup2(fp->f_retaddr, 4) == 433 (long)dtrace_invop_callsite) { 434 /* 435 * If we pass through the invalid op handler, we will 436 * use the trap frame pointer that it pushed on the 437 * stack as the second argument to dtrace_invop() as 438 * the pointer to the stack. When using this stack, we 439 * must skip the third argument to dtrace_invop(), 440 * which is included in the i386_frame. 441 */ 442 frame = (struct trapframe *)(((uintptr_t **)&fp[1])[0]); 443 /* 444 * Skip the three hardware-saved registers and the 445 * return address. 446 */ 447 stack = (uintptr_t *)frame->tf_isp + 4; 448 goto load; 449 } 450 451 } 452 453 /* 454 * We know that we did not come through a trap to get into 455 * dtrace_probe() -- the provider simply called dtrace_probe() 456 * directly. As this is the case, we need to shift the argument 457 * that we're looking for: the probe ID is the first argument to 458 * dtrace_probe(), so the argument n will actually be found where 459 * one would expect to find argument (n + 1). 460 */ 461 arg++; 462 463 stack = (uintptr_t *)fp + 2; 464 465 load: 466 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 467 val = stack[arg]; 468 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); 469 470 return (val); 471 } 472 473 int 474 dtrace_getstackdepth(int aframes) 475 { 476 int depth = 0; 477 struct i386_frame *frame; 478 vm_offset_t ebp; 479 480 aframes++; 481 ebp = dtrace_getfp(); 482 frame = (struct i386_frame *)ebp; 483 depth++; 484 for(;;) { 485 if (!kstack_contains(curthread, (vm_offset_t)frame, 486 sizeof(*frame))) 487 break; 488 depth++; 489 if (frame->f_frame <= frame) 490 break; 491 frame = frame->f_frame; 492 } 493 if (depth < aframes) 494 return 0; 495 else 496 return depth - aframes; 497 } 498 499 ulong_t 500 dtrace_getreg(struct trapframe *frame, uint_t reg) 501 { 502 struct pcb *pcb; 503 int regmap[] = { /* Order is dependent on reg.d */ 504 REG_GS, /* 0 GS */ 505 REG_FS, /* 1 FS */ 506 REG_ES, /* 2 ES */ 507 REG_DS, /* 3 DS */ 508 REG_RDI, /* 4 EDI */ 509 REG_RSI, /* 5 ESI */ 510 REG_RBP, /* 6 EBP, REG_FP */ 511 REG_RSP, /* 7 ESP */ 512 REG_RBX, /* 8 EBX */ 513 REG_RDX, /* 9 EDX, REG_R1 */ 514 REG_RCX, /* 10 ECX */ 515 REG_RAX, /* 11 EAX, REG_R0 */ 516 REG_TRAPNO, /* 12 TRAPNO */ 517 REG_ERR, /* 13 ERR */ 518 REG_RIP, /* 14 EIP, REG_PC */ 519 REG_CS, /* 15 CS */ 520 REG_RFL, /* 16 EFL, REG_PS */ 521 REG_RSP, /* 17 UESP, REG_SP */ 522 REG_SS /* 18 SS */ 523 }; 524 525 if (reg > SS) { 526 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 527 return (0); 528 } 529 530 if (reg >= sizeof (regmap) / sizeof (int)) { 531 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 532 return (0); 533 } 534 535 reg = regmap[reg]; 536 537 switch(reg) { 538 case REG_GS: 539 if ((pcb = curthread->td_pcb) == NULL) { 540 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 541 return (0); 542 } 543 return (pcb->pcb_gs); 544 case REG_FS: 545 return (frame->tf_fs); 546 case REG_ES: 547 return (frame->tf_es); 548 case REG_DS: 549 return (frame->tf_ds); 550 case REG_RDI: 551 return (frame->tf_edi); 552 case REG_RSI: 553 return (frame->tf_esi); 554 case REG_RBP: 555 return (frame->tf_ebp); 556 case REG_RSP: 557 return (frame->tf_isp); 558 case REG_RBX: 559 return (frame->tf_ebx); 560 case REG_RCX: 561 return (frame->tf_ecx); 562 case REG_RAX: 563 return (frame->tf_eax); 564 case REG_TRAPNO: 565 return (frame->tf_trapno); 566 case REG_ERR: 567 return (frame->tf_err); 568 case REG_RIP: 569 return (frame->tf_eip); 570 case REG_CS: 571 return (frame->tf_cs); 572 case REG_RFL: 573 return (frame->tf_eflags); 574 #if 0 575 case REG_RSP: 576 return (frame->tf_esp); 577 #endif 578 case REG_SS: 579 return (frame->tf_ss); 580 default: 581 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 582 return (0); 583 } 584 } 585 586 static int 587 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 588 { 589 ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr); 590 591 if (uaddr + size >= kernelbase || uaddr + size < uaddr) { 592 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 593 cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 594 return (0); 595 } 596 597 return (1); 598 } 599 600 void 601 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 602 volatile uint16_t *flags) 603 { 604 if (dtrace_copycheck(uaddr, kaddr, size)) 605 dtrace_copy(uaddr, kaddr, size); 606 } 607 608 void 609 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 610 volatile uint16_t *flags) 611 { 612 if (dtrace_copycheck(uaddr, kaddr, size)) 613 dtrace_copy(kaddr, uaddr, size); 614 } 615 616 void 617 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 618 volatile uint16_t *flags) 619 { 620 if (dtrace_copycheck(uaddr, kaddr, size)) 621 dtrace_copystr(uaddr, kaddr, size, flags); 622 } 623 624 void 625 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 626 volatile uint16_t *flags) 627 { 628 if (dtrace_copycheck(uaddr, kaddr, size)) 629 dtrace_copystr(kaddr, uaddr, size, flags); 630 } 631 632 uint8_t 633 dtrace_fuword8(void *uaddr) 634 { 635 if ((uintptr_t)uaddr >= kernelbase) { 636 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 637 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 638 return (0); 639 } 640 return (dtrace_fuword8_nocheck(uaddr)); 641 } 642 643 uint16_t 644 dtrace_fuword16(void *uaddr) 645 { 646 if ((uintptr_t)uaddr >= kernelbase) { 647 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 648 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 649 return (0); 650 } 651 return (dtrace_fuword16_nocheck(uaddr)); 652 } 653 654 uint32_t 655 dtrace_fuword32(void *uaddr) 656 { 657 if ((uintptr_t)uaddr >= kernelbase) { 658 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 659 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 660 return (0); 661 } 662 return (dtrace_fuword32_nocheck(uaddr)); 663 } 664 665 uint64_t 666 dtrace_fuword64(void *uaddr) 667 { 668 if ((uintptr_t)uaddr >= kernelbase) { 669 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 670 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 671 return (0); 672 } 673 return (dtrace_fuword64_nocheck(uaddr)); 674 } 675