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 46 uint8_t dtrace_fuword8_nocheck(void *); 47 uint16_t dtrace_fuword16_nocheck(void *); 48 uint32_t dtrace_fuword32_nocheck(void *); 49 uint64_t dtrace_fuword64_nocheck(void *); 50 51 void 52 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 53 uint32_t *intrpc) 54 { 55 int depth = 0; 56 register_t rbp; 57 struct amd64_frame *frame; 58 vm_offset_t callpc; 59 pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 60 61 if (intrpc != 0) 62 pcstack[depth++] = (pc_t) intrpc; 63 64 aframes++; 65 66 __asm __volatile("movq %%rbp,%0" : "=r" (rbp)); 67 68 frame = (struct amd64_frame *)rbp; 69 while (depth < pcstack_limit) { 70 if (!INKERNEL((long) frame)) 71 break; 72 73 callpc = frame->f_retaddr; 74 75 if (!INKERNEL(callpc)) 76 break; 77 78 if (aframes > 0) { 79 aframes--; 80 if ((aframes == 0) && (caller != 0)) { 81 pcstack[depth++] = caller; 82 } 83 } 84 else { 85 pcstack[depth++] = callpc; 86 } 87 88 if (frame->f_frame <= frame || 89 (vm_offset_t)frame->f_frame >= 90 (vm_offset_t)rbp + KSTACK_PAGES * PAGE_SIZE) 91 break; 92 frame = frame->f_frame; 93 } 94 95 for (; depth < pcstack_limit; depth++) { 96 pcstack[depth] = 0; 97 } 98 } 99 100 static int 101 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 102 uintptr_t sp) 103 { 104 volatile uint16_t *flags = 105 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 106 struct amd64_frame *frame; 107 int ret = 0; 108 109 ASSERT(pcstack == NULL || pcstack_limit > 0); 110 111 while (pc != 0 && sp != 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 frame = (struct amd64_frame *) sp; 121 122 pc = dtrace_fulword(&frame->f_retaddr); 123 sp = dtrace_fulword(&frame->f_frame); 124 125 /* 126 * This is totally bogus: if we faulted, we're going to clear 127 * the fault and break. This is to deal with the apparently 128 * broken Java stacks on x86. 129 */ 130 if (*flags & CPU_DTRACE_FAULT) { 131 *flags &= ~CPU_DTRACE_FAULT; 132 break; 133 } 134 } 135 136 return (ret); 137 } 138 139 void 140 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 141 { 142 proc_t *p = curproc; 143 struct trapframe *tf; 144 uintptr_t pc, sp; 145 volatile uint16_t *flags = 146 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 147 int n; 148 149 if (*flags & CPU_DTRACE_FAULT) 150 return; 151 152 if (pcstack_limit <= 0) 153 return; 154 155 /* 156 * If there's no user context we still need to zero the stack. 157 */ 158 if (p == NULL || (tf = curthread->td_frame) == NULL) 159 goto zero; 160 161 *pcstack++ = (uint64_t)p->p_pid; 162 pcstack_limit--; 163 164 if (pcstack_limit <= 0) 165 return; 166 167 pc = tf->tf_rip; 168 sp = tf->tf_rsp; 169 170 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 171 *pcstack++ = (uint64_t)pc; 172 pcstack_limit--; 173 if (pcstack_limit <= 0) 174 return; 175 176 pc = dtrace_fulword((void *) sp); 177 } 178 179 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); 180 ASSERT(n >= 0); 181 ASSERT(n <= pcstack_limit); 182 183 pcstack += n; 184 pcstack_limit -= n; 185 186 zero: 187 while (pcstack_limit-- > 0) 188 *pcstack++ = 0; 189 } 190 191 int 192 dtrace_getustackdepth(void) 193 { 194 proc_t *p = curproc; 195 struct trapframe *tf; 196 uintptr_t pc, sp; 197 int n = 0; 198 199 if (p == NULL || (tf = curthread->td_frame) == NULL) 200 return (0); 201 202 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) 203 return (-1); 204 205 pc = tf->tf_rip; 206 sp = tf->tf_rsp; 207 208 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 209 n++; 210 211 pc = dtrace_fulword((void *) sp); 212 } 213 214 n += dtrace_getustack_common(NULL, 0, pc, sp); 215 216 return (n); 217 } 218 219 #ifdef notyet 220 void 221 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 222 { 223 klwp_t *lwp = ttolwp(curthread); 224 proc_t *p = curproc; 225 struct regs *rp; 226 uintptr_t pc, sp, oldcontext; 227 volatile uint16_t *flags = 228 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 229 size_t s1, s2; 230 231 if (*flags & CPU_DTRACE_FAULT) 232 return; 233 234 if (pcstack_limit <= 0) 235 return; 236 237 /* 238 * If there's no user context we still need to zero the stack. 239 */ 240 if (lwp == NULL || p == NULL || (rp = lwp->lwp_regs) == NULL) 241 goto zero; 242 243 *pcstack++ = (uint64_t)p->p_pid; 244 pcstack_limit--; 245 246 if (pcstack_limit <= 0) 247 return; 248 249 pc = rp->r_pc; 250 sp = rp->r_fp; 251 oldcontext = lwp->lwp_oldcontext; 252 253 s1 = sizeof (struct xframe) + 2 * sizeof (long); 254 s2 = s1 + sizeof (siginfo_t); 255 256 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 257 *pcstack++ = (uint64_t)pc; 258 *fpstack++ = 0; 259 pcstack_limit--; 260 if (pcstack_limit <= 0) 261 return; 262 263 if (p->p_model == DATAMODEL_NATIVE) 264 pc = dtrace_fulword((void *)rp->r_sp); 265 else 266 pc = dtrace_fuword32((void *)rp->r_sp); 267 } 268 269 while (pc != 0 && sp != 0) { 270 *pcstack++ = (uint64_t)pc; 271 *fpstack++ = sp; 272 pcstack_limit--; 273 if (pcstack_limit <= 0) 274 break; 275 276 if (oldcontext == sp + s1 || oldcontext == sp + s2) { 277 ucontext_t *ucp = (ucontext_t *)oldcontext; 278 greg_t *gregs = ucp->uc_mcontext.gregs; 279 280 sp = dtrace_fulword(&gregs[REG_FP]); 281 pc = dtrace_fulword(&gregs[REG_PC]); 282 283 oldcontext = dtrace_fulword(&ucp->uc_link); 284 } else { 285 struct xframe *fr = (struct xframe *)sp; 286 287 pc = dtrace_fulword(&fr->fr_savpc); 288 sp = dtrace_fulword(&fr->fr_savfp); 289 } 290 291 /* 292 * This is totally bogus: if we faulted, we're going to clear 293 * the fault and break. This is to deal with the apparently 294 * broken Java stacks on x86. 295 */ 296 if (*flags & CPU_DTRACE_FAULT) { 297 *flags &= ~CPU_DTRACE_FAULT; 298 break; 299 } 300 } 301 302 zero: 303 while (pcstack_limit-- > 0) 304 *pcstack++ = NULL; 305 } 306 #endif 307 308 /*ARGSUSED*/ 309 uint64_t 310 dtrace_getarg(int arg, int aframes) 311 { 312 uintptr_t val; 313 struct amd64_frame *fp = (struct amd64_frame *)dtrace_getfp(); 314 uintptr_t *stack; 315 int i; 316 317 /* 318 * A total of 6 arguments are passed via registers; any argument with 319 * index of 5 or lower is therefore in a register. 320 */ 321 int inreg = 5; 322 323 for (i = 1; i <= aframes; i++) { 324 fp = fp->f_frame; 325 326 if (fp->f_retaddr == (long)dtrace_invop_callsite) { 327 /* 328 * In the case of amd64, we will use the pointer to the 329 * regs structure that was pushed when we took the 330 * trap. To get this structure, we must increment 331 * beyond the frame structure, and then again beyond 332 * the calling RIP stored in dtrace_invop(). If the 333 * argument that we're seeking is passed on the stack, 334 * we'll pull the true stack pointer out of the saved 335 * registers and decrement our argument by the number 336 * of arguments passed in registers; if the argument 337 * we're seeking is passed in regsiters, we can just 338 * load it directly. 339 */ 340 struct reg *rp = (struct reg *)((uintptr_t)&fp[1] + 341 sizeof (uintptr_t)); 342 343 if (arg <= inreg) { 344 stack = (uintptr_t *)&rp->r_rdi; 345 } else { 346 stack = (uintptr_t *)(rp->r_rsp); 347 arg -= inreg; 348 } 349 goto load; 350 } 351 352 } 353 354 /* 355 * We know that we did not come through a trap to get into 356 * dtrace_probe() -- the provider simply called dtrace_probe() 357 * directly. As this is the case, we need to shift the argument 358 * that we're looking for: the probe ID is the first argument to 359 * dtrace_probe(), so the argument n will actually be found where 360 * one would expect to find argument (n + 1). 361 */ 362 arg++; 363 364 if (arg <= inreg) { 365 /* 366 * This shouldn't happen. If the argument is passed in a 367 * register then it should have been, well, passed in a 368 * register... 369 */ 370 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 371 return (0); 372 } 373 374 arg -= (inreg + 1); 375 stack = (uintptr_t *)&fp[1]; 376 377 load: 378 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 379 val = stack[arg]; 380 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); 381 382 return (val); 383 return (0); 384 } 385 386 int 387 dtrace_getstackdepth(int aframes) 388 { 389 int depth = 0; 390 struct amd64_frame *frame; 391 vm_offset_t rbp; 392 393 aframes++; 394 rbp = dtrace_getfp(); 395 frame = (struct amd64_frame *)rbp; 396 depth++; 397 for(;;) { 398 if (!INKERNEL((long) frame)) 399 break; 400 if (!INKERNEL((long) frame->f_frame)) 401 break; 402 depth++; 403 if (frame->f_frame <= frame || 404 (vm_offset_t)frame->f_frame >= 405 (vm_offset_t)rbp + KSTACK_PAGES * PAGE_SIZE) 406 break; 407 frame = frame->f_frame; 408 } 409 if (depth < aframes) 410 return 0; 411 else 412 return depth - aframes; 413 } 414 415 #ifdef notyet 416 ulong_t 417 dtrace_getreg(struct regs *rp, uint_t reg) 418 { 419 #if defined(__amd64) 420 int regmap[] = { 421 REG_GS, /* GS */ 422 REG_FS, /* FS */ 423 REG_ES, /* ES */ 424 REG_DS, /* DS */ 425 REG_RDI, /* EDI */ 426 REG_RSI, /* ESI */ 427 REG_RBP, /* EBP */ 428 REG_RSP, /* ESP */ 429 REG_RBX, /* EBX */ 430 REG_RDX, /* EDX */ 431 REG_RCX, /* ECX */ 432 REG_RAX, /* EAX */ 433 REG_TRAPNO, /* TRAPNO */ 434 REG_ERR, /* ERR */ 435 REG_RIP, /* EIP */ 436 REG_CS, /* CS */ 437 REG_RFL, /* EFL */ 438 REG_RSP, /* UESP */ 439 REG_SS /* SS */ 440 }; 441 442 if (reg <= SS) { 443 if (reg >= sizeof (regmap) / sizeof (int)) { 444 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 445 return (0); 446 } 447 448 reg = regmap[reg]; 449 } else { 450 reg -= SS + 1; 451 } 452 453 switch (reg) { 454 case REG_RDI: 455 return (rp->r_rdi); 456 case REG_RSI: 457 return (rp->r_rsi); 458 case REG_RDX: 459 return (rp->r_rdx); 460 case REG_RCX: 461 return (rp->r_rcx); 462 case REG_R8: 463 return (rp->r_r8); 464 case REG_R9: 465 return (rp->r_r9); 466 case REG_RAX: 467 return (rp->r_rax); 468 case REG_RBX: 469 return (rp->r_rbx); 470 case REG_RBP: 471 return (rp->r_rbp); 472 case REG_R10: 473 return (rp->r_r10); 474 case REG_R11: 475 return (rp->r_r11); 476 case REG_R12: 477 return (rp->r_r12); 478 case REG_R13: 479 return (rp->r_r13); 480 case REG_R14: 481 return (rp->r_r14); 482 case REG_R15: 483 return (rp->r_r15); 484 case REG_DS: 485 return (rp->r_ds); 486 case REG_ES: 487 return (rp->r_es); 488 case REG_FS: 489 return (rp->r_fs); 490 case REG_GS: 491 return (rp->r_gs); 492 case REG_TRAPNO: 493 return (rp->r_trapno); 494 case REG_ERR: 495 return (rp->r_err); 496 case REG_RIP: 497 return (rp->r_rip); 498 case REG_CS: 499 return (rp->r_cs); 500 case REG_SS: 501 return (rp->r_ss); 502 case REG_RFL: 503 return (rp->r_rfl); 504 case REG_RSP: 505 return (rp->r_rsp); 506 default: 507 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 508 return (0); 509 } 510 511 #else 512 if (reg > SS) { 513 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 514 return (0); 515 } 516 517 return ((&rp->r_gs)[reg]); 518 #endif 519 } 520 #endif 521 522 static int 523 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 524 { 525 ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr); 526 527 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 528 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 529 cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 530 return (0); 531 } 532 533 return (1); 534 } 535 536 void 537 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 538 volatile uint16_t *flags) 539 { 540 if (dtrace_copycheck(uaddr, kaddr, size)) 541 dtrace_copy(uaddr, kaddr, size); 542 } 543 544 void 545 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 546 volatile uint16_t *flags) 547 { 548 if (dtrace_copycheck(uaddr, kaddr, size)) 549 dtrace_copy(kaddr, uaddr, size); 550 } 551 552 void 553 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 554 volatile uint16_t *flags) 555 { 556 if (dtrace_copycheck(uaddr, kaddr, size)) 557 dtrace_copystr(uaddr, kaddr, size, flags); 558 } 559 560 void 561 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 562 volatile uint16_t *flags) 563 { 564 if (dtrace_copycheck(uaddr, kaddr, size)) 565 dtrace_copystr(kaddr, uaddr, size, flags); 566 } 567 568 uint8_t 569 dtrace_fuword8(void *uaddr) 570 { 571 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 572 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 573 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 574 return (0); 575 } 576 return (dtrace_fuword8_nocheck(uaddr)); 577 } 578 579 uint16_t 580 dtrace_fuword16(void *uaddr) 581 { 582 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 583 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 584 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 585 return (0); 586 } 587 return (dtrace_fuword16_nocheck(uaddr)); 588 } 589 590 uint32_t 591 dtrace_fuword32(void *uaddr) 592 { 593 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 594 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 595 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 596 return (0); 597 } 598 return (dtrace_fuword32_nocheck(uaddr)); 599 } 600 601 uint64_t 602 dtrace_fuword64(void *uaddr) 603 { 604 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 605 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 606 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 607 return (0); 608 } 609 return (dtrace_fuword64_nocheck(uaddr)); 610 } 611