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