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