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/reg.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 uint8_t dtrace_fuword8_nocheck(void *); 48 uint16_t dtrace_fuword16_nocheck(void *); 49 uint32_t dtrace_fuword32_nocheck(void *); 50 uint64_t dtrace_fuword64_nocheck(void *); 51 52 void 53 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 54 uint32_t *intrpc) 55 { 56 int depth = 0; 57 register_t rbp; 58 struct amd64_frame *frame; 59 vm_offset_t callpc; 60 pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 61 62 if (intrpc != 0) 63 pcstack[depth++] = (pc_t) intrpc; 64 65 aframes++; 66 67 __asm __volatile("movq %%rbp,%0" : "=r" (rbp)); 68 69 frame = (struct amd64_frame *)rbp; 70 while (depth < pcstack_limit) { 71 if (!INKERNEL((long) frame)) 72 break; 73 74 callpc = frame->f_retaddr; 75 76 if (!INKERNEL(callpc)) 77 break; 78 79 if (aframes > 0) { 80 aframes--; 81 if ((aframes == 0) && (caller != 0)) { 82 pcstack[depth++] = caller; 83 } 84 } 85 else { 86 pcstack[depth++] = callpc; 87 } 88 89 if (frame->f_frame <= frame || 90 (vm_offset_t)frame->f_frame >= 91 (vm_offset_t)rbp + KSTACK_PAGES * PAGE_SIZE) 92 break; 93 frame = frame->f_frame; 94 } 95 96 for (; depth < pcstack_limit; depth++) { 97 pcstack[depth] = 0; 98 } 99 } 100 101 static int 102 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 103 uintptr_t sp) 104 { 105 volatile uint16_t *flags = 106 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 107 int ret = 0; 108 109 ASSERT(pcstack == NULL || pcstack_limit > 0); 110 111 while (pc != 0) { 112 ret++; 113 if (pcstack != NULL) { 114 *pcstack++ = (uint64_t)pc; 115 pcstack_limit--; 116 if (pcstack_limit <= 0) 117 break; 118 } 119 120 if (sp == 0) 121 break; 122 123 pc = dtrace_fuword64((void *)(sp + 124 offsetof(struct amd64_frame, f_retaddr))); 125 sp = dtrace_fuword64((void *)sp); 126 127 /* 128 * This is totally bogus: if we faulted, we're going to clear 129 * the fault and break. This is to deal with the apparently 130 * broken Java stacks on x86. 131 */ 132 if (*flags & CPU_DTRACE_FAULT) { 133 *flags &= ~CPU_DTRACE_FAULT; 134 break; 135 } 136 } 137 138 return (ret); 139 } 140 141 void 142 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 143 { 144 proc_t *p = curproc; 145 struct trapframe *tf; 146 uintptr_t pc, sp, fp; 147 volatile uint16_t *flags = 148 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 149 int n; 150 151 if (*flags & CPU_DTRACE_FAULT) 152 return; 153 154 if (pcstack_limit <= 0) 155 return; 156 157 /* 158 * If there's no user context we still need to zero the stack. 159 */ 160 if (p == NULL || (tf = curthread->td_frame) == NULL) 161 goto zero; 162 163 *pcstack++ = (uint64_t)p->p_pid; 164 pcstack_limit--; 165 166 if (pcstack_limit <= 0) 167 return; 168 169 pc = tf->tf_rip; 170 fp = tf->tf_rbp; 171 sp = tf->tf_rsp; 172 173 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 174 /* 175 * In an entry probe. The frame pointer has not yet been 176 * pushed (that happens in the function prologue). The 177 * best approach is to add the current pc as a missing top 178 * of stack and back the pc up to the caller, which is stored 179 * at the current stack pointer address since the call 180 * instruction puts it there right before the branch. 181 */ 182 183 *pcstack++ = (uint64_t)pc; 184 pcstack_limit--; 185 if (pcstack_limit <= 0) 186 return; 187 188 pc = dtrace_fuword64((void *) sp); 189 } 190 191 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp); 192 ASSERT(n >= 0); 193 ASSERT(n <= pcstack_limit); 194 195 pcstack += n; 196 pcstack_limit -= n; 197 198 zero: 199 while (pcstack_limit-- > 0) 200 *pcstack++ = 0; 201 } 202 203 int 204 dtrace_getustackdepth(void) 205 { 206 proc_t *p = curproc; 207 struct trapframe *tf; 208 uintptr_t pc, fp, sp; 209 int n = 0; 210 211 if (p == NULL || (tf = curthread->td_frame) == NULL) 212 return (0); 213 214 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) 215 return (-1); 216 217 pc = tf->tf_rip; 218 fp = tf->tf_rbp; 219 sp = tf->tf_rsp; 220 221 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 222 /* 223 * In an entry probe. The frame pointer has not yet been 224 * pushed (that happens in the function prologue). The 225 * best approach is to add the current pc as a missing top 226 * of stack and back the pc up to the caller, which is stored 227 * at the current stack pointer address since the call 228 * instruction puts it there right before the branch. 229 */ 230 231 pc = dtrace_fuword64((void *) sp); 232 n++; 233 } 234 235 n += dtrace_getustack_common(NULL, 0, pc, fp); 236 237 return (n); 238 } 239 240 void 241 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 242 { 243 proc_t *p = curproc; 244 struct trapframe *tf; 245 uintptr_t pc, sp, fp; 246 volatile uint16_t *flags = 247 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 248 #ifdef notyet /* XXX signal stack */ 249 uintptr_t oldcontext; 250 size_t s1, s2; 251 #endif 252 253 if (*flags & CPU_DTRACE_FAULT) 254 return; 255 256 if (pcstack_limit <= 0) 257 return; 258 259 /* 260 * If there's no user context we still need to zero the stack. 261 */ 262 if (p == NULL || (tf = curthread->td_frame) == NULL) 263 goto zero; 264 265 *pcstack++ = (uint64_t)p->p_pid; 266 pcstack_limit--; 267 268 if (pcstack_limit <= 0) 269 return; 270 271 pc = tf->tf_rip; 272 sp = tf->tf_rsp; 273 fp = tf->tf_rbp; 274 275 #ifdef notyet /* XXX signal stack */ 276 oldcontext = lwp->lwp_oldcontext; 277 s1 = sizeof (struct xframe) + 2 * sizeof (long); 278 s2 = s1 + sizeof (siginfo_t); 279 #endif 280 281 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 282 *pcstack++ = (uint64_t)pc; 283 *fpstack++ = 0; 284 pcstack_limit--; 285 if (pcstack_limit <= 0) 286 return; 287 288 pc = dtrace_fuword64((void *)sp); 289 } 290 291 while (pc != 0) { 292 *pcstack++ = (uint64_t)pc; 293 *fpstack++ = fp; 294 pcstack_limit--; 295 if (pcstack_limit <= 0) 296 break; 297 298 if (fp == 0) 299 break; 300 301 #ifdef notyet /* XXX signal stack */ 302 if (oldcontext == sp + s1 || oldcontext == sp + s2) { 303 ucontext_t *ucp = (ucontext_t *)oldcontext; 304 greg_t *gregs = ucp->uc_mcontext.gregs; 305 306 sp = dtrace_fulword(&gregs[REG_FP]); 307 pc = dtrace_fulword(&gregs[REG_PC]); 308 309 oldcontext = dtrace_fulword(&ucp->uc_link); 310 } else 311 #endif /* XXX */ 312 { 313 pc = dtrace_fuword64((void *)(fp + 314 offsetof(struct amd64_frame, f_retaddr))); 315 fp = dtrace_fuword64((void *)fp); 316 } 317 318 /* 319 * This is totally bogus: if we faulted, we're going to clear 320 * the fault and break. This is to deal with the apparently 321 * broken Java stacks on x86. 322 */ 323 if (*flags & CPU_DTRACE_FAULT) { 324 *flags &= ~CPU_DTRACE_FAULT; 325 break; 326 } 327 } 328 329 zero: 330 while (pcstack_limit-- > 0) 331 *pcstack++ = 0; 332 } 333 334 /*ARGSUSED*/ 335 uint64_t 336 dtrace_getarg(int arg, int aframes) 337 { 338 uintptr_t val; 339 struct amd64_frame *fp = (struct amd64_frame *)dtrace_getfp(); 340 uintptr_t *stack; 341 int i; 342 343 /* 344 * A total of 6 arguments are passed via registers; any argument with 345 * index of 5 or lower is therefore in a register. 346 */ 347 int inreg = 5; 348 349 for (i = 1; i <= aframes; i++) { 350 fp = fp->f_frame; 351 352 if (fp->f_retaddr == (long)dtrace_invop_callsite) { 353 /* 354 * In the case of amd64, we will use the pointer to the 355 * regs structure that was pushed when we took the 356 * trap. To get this structure, we must increment 357 * beyond the frame structure, and then again beyond 358 * the calling RIP stored in dtrace_invop(). If the 359 * argument that we're seeking is passed on the stack, 360 * we'll pull the true stack pointer out of the saved 361 * registers and decrement our argument by the number 362 * of arguments passed in registers; if the argument 363 * we're seeking is passed in regsiters, we can just 364 * load it directly. 365 */ 366 struct reg *rp = (struct reg *)((uintptr_t)&fp[1] + 367 sizeof (uintptr_t)); 368 369 if (arg <= inreg) { 370 switch (arg) { 371 case 0: 372 stack = (uintptr_t *)&rp->r_rdi; 373 break; 374 case 1: 375 stack = (uintptr_t *)&rp->r_rsi; 376 break; 377 case 2: 378 stack = (uintptr_t *)&rp->r_rdx; 379 break; 380 case 3: 381 stack = (uintptr_t *)&rp->r_rcx; 382 break; 383 case 4: 384 stack = (uintptr_t *)&rp->r_r8; 385 break; 386 case 5: 387 stack = (uintptr_t *)&rp->r_r9; 388 break; 389 } 390 arg = 0; 391 } else { 392 stack = (uintptr_t *)(rp->r_rsp); 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 = (uintptr_t *)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 struct amd64_frame *frame; 437 vm_offset_t rbp; 438 439 aframes++; 440 rbp = dtrace_getfp(); 441 frame = (struct amd64_frame *)rbp; 442 depth++; 443 for(;;) { 444 if (!INKERNEL((long) frame)) 445 break; 446 if (!INKERNEL((long) frame->f_frame)) 447 break; 448 depth++; 449 if (frame->f_frame <= frame || 450 (vm_offset_t)frame->f_frame >= 451 (vm_offset_t)rbp + KSTACK_PAGES * PAGE_SIZE) 452 break; 453 frame = frame->f_frame; 454 } 455 if (depth < aframes) 456 return 0; 457 else 458 return depth - aframes; 459 } 460 461 ulong_t 462 dtrace_getreg(struct trapframe *rp, uint_t reg) 463 { 464 /* This table is dependent on reg.d. */ 465 int regmap[] = { 466 REG_GS, /* 0 GS */ 467 REG_FS, /* 1 FS */ 468 REG_ES, /* 2 ES */ 469 REG_DS, /* 3 DS */ 470 REG_RDI, /* 4 EDI */ 471 REG_RSI, /* 5 ESI */ 472 REG_RBP, /* 6 EBP, REG_FP */ 473 REG_RSP, /* 7 ESP */ 474 REG_RBX, /* 8 EBX, REG_R1 */ 475 REG_RDX, /* 9 EDX */ 476 REG_RCX, /* 10 ECX */ 477 REG_RAX, /* 11 EAX, REG_R0 */ 478 REG_TRAPNO, /* 12 TRAPNO */ 479 REG_ERR, /* 13 ERR */ 480 REG_RIP, /* 14 EIP, REG_PC */ 481 REG_CS, /* 15 CS */ 482 REG_RFL, /* 16 EFL, REG_PS */ 483 REG_RSP, /* 17 UESP, REG_SP */ 484 REG_SS /* 18 SS */ 485 }; 486 487 if (reg <= SS) { 488 if (reg >= sizeof (regmap) / sizeof (int)) { 489 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 490 return (0); 491 } 492 493 reg = regmap[reg]; 494 } else { 495 /* This is dependent on reg.d. */ 496 reg -= SS + 1; 497 } 498 499 switch (reg) { 500 case REG_RDI: 501 return (rp->tf_rdi); 502 case REG_RSI: 503 return (rp->tf_rsi); 504 case REG_RDX: 505 return (rp->tf_rdx); 506 case REG_RCX: 507 return (rp->tf_rcx); 508 case REG_R8: 509 return (rp->tf_r8); 510 case REG_R9: 511 return (rp->tf_r9); 512 case REG_RAX: 513 return (rp->tf_rax); 514 case REG_RBX: 515 return (rp->tf_rbx); 516 case REG_RBP: 517 return (rp->tf_rbp); 518 case REG_R10: 519 return (rp->tf_r10); 520 case REG_R11: 521 return (rp->tf_r11); 522 case REG_R12: 523 return (rp->tf_r12); 524 case REG_R13: 525 return (rp->tf_r13); 526 case REG_R14: 527 return (rp->tf_r14); 528 case REG_R15: 529 return (rp->tf_r15); 530 case REG_DS: 531 return (rp->tf_ds); 532 case REG_ES: 533 return (rp->tf_es); 534 case REG_FS: 535 return (rp->tf_fs); 536 case REG_GS: 537 return (rp->tf_gs); 538 case REG_TRAPNO: 539 return (rp->tf_trapno); 540 case REG_ERR: 541 return (rp->tf_err); 542 case REG_RIP: 543 return (rp->tf_rip); 544 case REG_CS: 545 return (rp->tf_cs); 546 case REG_SS: 547 return (rp->tf_ss); 548 case REG_RFL: 549 return (rp->tf_rflags); 550 case REG_RSP: 551 return (rp->tf_rsp); 552 default: 553 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 554 return (0); 555 } 556 } 557 558 static int 559 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 560 { 561 ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr); 562 563 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 564 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 565 cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 566 return (0); 567 } 568 569 return (1); 570 } 571 572 void 573 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 574 volatile uint16_t *flags) 575 { 576 if (dtrace_copycheck(uaddr, kaddr, size)) 577 dtrace_copy(uaddr, kaddr, size); 578 } 579 580 void 581 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 582 volatile uint16_t *flags) 583 { 584 if (dtrace_copycheck(uaddr, kaddr, size)) 585 dtrace_copy(kaddr, uaddr, size); 586 } 587 588 void 589 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 590 volatile uint16_t *flags) 591 { 592 if (dtrace_copycheck(uaddr, kaddr, size)) 593 dtrace_copystr(uaddr, kaddr, size, flags); 594 } 595 596 void 597 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 598 volatile uint16_t *flags) 599 { 600 if (dtrace_copycheck(uaddr, kaddr, size)) 601 dtrace_copystr(kaddr, uaddr, size, flags); 602 } 603 604 uint8_t 605 dtrace_fuword8(void *uaddr) 606 { 607 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 608 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 609 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 610 return (0); 611 } 612 return (dtrace_fuword8_nocheck(uaddr)); 613 } 614 615 uint16_t 616 dtrace_fuword16(void *uaddr) 617 { 618 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 619 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 620 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 621 return (0); 622 } 623 return (dtrace_fuword16_nocheck(uaddr)); 624 } 625 626 uint32_t 627 dtrace_fuword32(void *uaddr) 628 { 629 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 630 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 631 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 632 return (0); 633 } 634 return (dtrace_fuword32_nocheck(uaddr)); 635 } 636 637 uint64_t 638 dtrace_fuword64(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 (dtrace_fuword64_nocheck(uaddr)); 646 } 647