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