dtrace_isa.c revision 286396
1117397Skan/* 2117397Skan * CDDL HEADER START 3169691Skan * 4169691Skan * The contents of this file are subject to the terms of the 5117397Skan * Common Development and Distribution License, Version 1.0 only 6117397Skan * (the "License"). You may not use this file except in compliance 7117397Skan * with the License. 8117397Skan * 9117397Skan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10117397Skan * or http://www.opensolaris.org/os/licensing. 11117397Skan * See the License for the specific language governing permissions 12117397Skan * and limitations under the License. 13117397Skan * 14117397Skan * When distributing Covered Code, include this CDDL HEADER in each 15117397Skan * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16117397Skan * If applicable, add the following below this CDDL HEADER, with the 17117397Skan * fields enclosed by brackets "[]" replaced with your own identifying 18117397Skan * information: Portions Copyright [yyyy] [name of copyright owner] 19169691Skan * 20117397Skan * CDDL HEADER END 21117397Skan * 22117397Skan * $FreeBSD: stable/10/sys/cddl/dev/dtrace/i386/dtrace_isa.c 286396 2015-08-07 04:31:02Z kib $ 23117397Skan */ 24117397Skan/* 25117397Skan * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 26117397Skan * Use is subject to license terms. 27117397Skan */ 28117397Skan#include <sys/cdefs.h> 29117397Skan 30117397Skan#include <sys/param.h> 31169691Skan#include <sys/systm.h> 32117397Skan#include <sys/kernel.h> 33169691Skan#include <sys/stack.h> 34169691Skan#include <sys/pcpu.h> 35117397Skan 36132720Skan#include <machine/frame.h> 37132720Skan#include <machine/md_var.h> 38132720Skan#include <machine/pcb.h> 39132720Skan#include <machine/stack.h> 40132720Skan 41132720Skan#include <vm/vm.h> 42117397Skan#include <vm/vm_param.h> 43132720Skan#include <vm/pmap.h> 44132720Skan 45132720Skan#include "regset.h" 46132720Skan 47132720Skanextern uintptr_t kernbase; 48132720Skanuintptr_t kernelbase = (uintptr_t) &kernbase; 49132720Skan 50132720Skanuint8_t dtrace_fuword8_nocheck(void *); 51132720Skanuint16_t dtrace_fuword16_nocheck(void *); 52132720Skanuint32_t dtrace_fuword32_nocheck(void *); 53132720Skanuint64_t dtrace_fuword64_nocheck(void *); 54132720Skan 55132720Skanint dtrace_ustackdepth_max = 2048; 56132720Skan 57132720Skanvoid 58132720Skandtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 59132720Skan uint32_t *intrpc) 60132720Skan{ 61132720Skan int depth = 0; 62132720Skan register_t ebp; 63132720Skan struct i386_frame *frame; 64132720Skan vm_offset_t callpc; 65132720Skan pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 66132720Skan 67132720Skan if (intrpc != 0) 68132720Skan pcstack[depth++] = (pc_t) intrpc; 69132720Skan 70132720Skan aframes++; 71117397Skan 72117397Skan __asm __volatile("movl %%ebp,%0" : "=r" (ebp)); 73132720Skan 74132720Skan frame = (struct i386_frame *)ebp; 75132720Skan while (depth < pcstack_limit) { 76132720Skan if (!INKERNEL(frame)) 77132720Skan break; 78117397Skan 79132720Skan callpc = frame->f_retaddr; 80132720Skan 81132720Skan if (!INKERNEL(callpc)) 82132720Skan break; 83132720Skan 84132720Skan if (aframes > 0) { 85132720Skan aframes--; 86132720Skan if ((aframes == 0) && (caller != 0)) { 87132720Skan pcstack[depth++] = caller; 88132720Skan } 89132720Skan } 90132720Skan else { 91132720Skan pcstack[depth++] = callpc; 92132720Skan } 93132720Skan 94132720Skan if (frame->f_frame <= frame || 95132720Skan (vm_offset_t)frame->f_frame >= curthread->td_kstack + 96132720Skan curthread->td_kstack_pages * PAGE_SIZE) 97132720Skan break; 98132720Skan frame = frame->f_frame; 99132720Skan } 100132720Skan 101132720Skan for (; depth < pcstack_limit; depth++) { 102132720Skan pcstack[depth] = 0; 103132720Skan } 104132720Skan} 105132720Skan 106132720Skanstatic int 107132720Skandtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 108132720Skan uintptr_t sp) 109132720Skan{ 110132720Skan#ifdef notyet 111132720Skan proc_t *p = curproc; 112132720Skan uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */ 113132720Skan size_t s1, s2; 114132720Skan#endif 115132720Skan uintptr_t oldsp; 116132720Skan volatile uint16_t *flags = 117132720Skan (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 118132720Skan int ret = 0; 119132720Skan 120132720Skan ASSERT(pcstack == NULL || pcstack_limit > 0); 121132720Skan ASSERT(dtrace_ustackdepth_max > 0); 122132720Skan 123132720Skan#ifdef notyet /* XXX signal stack. */ 124132720Skan if (p->p_model == DATAMODEL_NATIVE) { 125117397Skan s1 = sizeof (struct frame) + 2 * sizeof (long); 126169691Skan s2 = s1 + sizeof (siginfo_t); 127169691Skan } else { 128 s1 = sizeof (struct frame32) + 3 * sizeof (int); 129 s2 = s1 + sizeof (siginfo32_t); 130 } 131#endif 132 133 while (pc != 0) { 134 /* 135 * We limit the number of times we can go around this 136 * loop to account for a circular stack. 137 */ 138 if (ret++ >= dtrace_ustackdepth_max) { 139 *flags |= CPU_DTRACE_BADSTACK; 140 cpu_core[curcpu].cpuc_dtrace_illval = sp; 141 break; 142 } 143 144 if (pcstack != NULL) { 145 *pcstack++ = (uint64_t)pc; 146 pcstack_limit--; 147 if (pcstack_limit <= 0) 148 break; 149 } 150 151 if (sp == 0) 152 break; 153 154 oldsp = sp; 155 156#ifdef notyet /* XXX signal stack. */ 157 if (oldcontext == sp + s1 || oldcontext == sp + s2) { 158 if (p->p_model == DATAMODEL_NATIVE) { 159 ucontext_t *ucp = (ucontext_t *)oldcontext; 160 greg_t *gregs = ucp->uc_mcontext.gregs; 161 162 sp = dtrace_fulword(&gregs[REG_FP]); 163 pc = dtrace_fulword(&gregs[REG_PC]); 164 165 oldcontext = dtrace_fulword(&ucp->uc_link); 166 } else { 167 ucontext32_t *ucp = (ucontext32_t *)oldcontext; 168 greg32_t *gregs = ucp->uc_mcontext.gregs; 169 170 sp = dtrace_fuword32(&gregs[EBP]); 171 pc = dtrace_fuword32(&gregs[EIP]); 172 173 oldcontext = dtrace_fuword32(&ucp->uc_link); 174 } 175 } else { 176 if (p->p_model == DATAMODEL_NATIVE) { 177 struct frame *fr = (struct frame *)sp; 178 179 pc = dtrace_fulword(&fr->fr_savpc); 180 sp = dtrace_fulword(&fr->fr_savfp); 181 } else { 182 struct frame32 *fr = (struct frame32 *)sp; 183 184 pc = dtrace_fuword32(&fr->fr_savpc); 185 sp = dtrace_fuword32(&fr->fr_savfp); 186 } 187 } 188#else 189 pc = dtrace_fuword32((void *)(sp + 190 offsetof(struct i386_frame, f_retaddr))); 191 sp = dtrace_fuword32((void *)sp); 192#endif /* ! notyet */ 193 194 if (sp == oldsp) { 195 *flags |= CPU_DTRACE_BADSTACK; 196 cpu_core[curcpu].cpuc_dtrace_illval = sp; 197 break; 198 } 199 200 /* 201 * This is totally bogus: if we faulted, we're going to clear 202 * the fault and break. This is to deal with the apparently 203 * broken Java stacks on x86. 204 */ 205 if (*flags & CPU_DTRACE_FAULT) { 206 *flags &= ~CPU_DTRACE_FAULT; 207 break; 208 } 209 } 210 211 return (ret); 212} 213 214void 215dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 216{ 217 proc_t *p = curproc; 218 struct trapframe *tf; 219 uintptr_t pc, sp, fp; 220 volatile uint16_t *flags = 221 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 222 int n; 223 224 if (*flags & CPU_DTRACE_FAULT) 225 return; 226 227 if (pcstack_limit <= 0) 228 return; 229 230 /* 231 * If there's no user context we still need to zero the stack. 232 */ 233 if (p == NULL || (tf = curthread->td_frame) == NULL) 234 goto zero; 235 236 *pcstack++ = (uint64_t)p->p_pid; 237 pcstack_limit--; 238 239 if (pcstack_limit <= 0) 240 return; 241 242 pc = tf->tf_eip; 243 fp = tf->tf_ebp; 244 sp = tf->tf_esp; 245 246 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 247 /* 248 * In an entry probe. The frame pointer has not yet been 249 * pushed (that happens in the function prologue). The 250 * best approach is to add the current pc as a missing top 251 * of stack and back the pc up to the caller, which is stored 252 * at the current stack pointer address since the call 253 * instruction puts it there right before the branch. 254 */ 255 256 *pcstack++ = (uint64_t)pc; 257 pcstack_limit--; 258 if (pcstack_limit <= 0) 259 return; 260 261 pc = dtrace_fuword32((void *) sp); 262 } 263 264 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); 265 ASSERT(n >= 0); 266 ASSERT(n <= pcstack_limit); 267 268 pcstack += n; 269 pcstack_limit -= n; 270 271zero: 272 while (pcstack_limit-- > 0) 273 *pcstack++ = 0; 274} 275 276int 277dtrace_getustackdepth(void) 278{ 279 proc_t *p = curproc; 280 struct trapframe *tf; 281 uintptr_t pc, fp, sp; 282 int n = 0; 283 284 if (p == NULL || (tf = curthread->td_frame) == NULL) 285 return (0); 286 287 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) 288 return (-1); 289 290 pc = tf->tf_eip; 291 fp = tf->tf_ebp; 292 sp = tf->tf_esp; 293 294 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 295 /* 296 * In an entry probe. The frame pointer has not yet been 297 * pushed (that happens in the function prologue). The 298 * best approach is to add the current pc as a missing top 299 * of stack and back the pc up to the caller, which is stored 300 * at the current stack pointer address since the call 301 * instruction puts it there right before the branch. 302 */ 303 304 pc = dtrace_fuword32((void *) sp); 305 n++; 306 } 307 308 n += dtrace_getustack_common(NULL, 0, pc, fp); 309 310 return (n); 311} 312 313void 314dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 315{ 316 proc_t *p = curproc; 317 struct trapframe *tf; 318 uintptr_t pc, sp, fp; 319 volatile uint16_t *flags = 320 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 321#ifdef notyet /* XXX signal stack */ 322 uintptr_t oldcontext; 323 size_t s1, s2; 324#endif 325 326 if (*flags & CPU_DTRACE_FAULT) 327 return; 328 329 if (pcstack_limit <= 0) 330 return; 331 332 /* 333 * If there's no user context we still need to zero the stack. 334 */ 335 if (p == NULL || (tf = curthread->td_frame) == NULL) 336 goto zero; 337 338 *pcstack++ = (uint64_t)p->p_pid; 339 pcstack_limit--; 340 341 if (pcstack_limit <= 0) 342 return; 343 344 pc = tf->tf_eip; 345 fp = tf->tf_ebp; 346 sp = tf->tf_esp; 347 348#ifdef notyet /* XXX signal stack */ 349 oldcontext = lwp->lwp_oldcontext; 350 351 if (p->p_model == DATAMODEL_NATIVE) { 352 s1 = sizeof (struct frame) + 2 * sizeof (long); 353 s2 = s1 + sizeof (siginfo_t); 354 } else { 355 s1 = sizeof (struct frame32) + 3 * sizeof (int); 356 s2 = s1 + sizeof (siginfo32_t); 357 } 358#endif 359 360 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 361 *pcstack++ = (uint64_t)pc; 362 *fpstack++ = 0; 363 pcstack_limit--; 364 if (pcstack_limit <= 0) 365 return; 366 367 pc = dtrace_fuword32((void *)sp); 368 } 369 370 while (pc != 0) { 371 *pcstack++ = (uint64_t)pc; 372 *fpstack++ = fp; 373 pcstack_limit--; 374 if (pcstack_limit <= 0) 375 break; 376 377 if (fp == 0) 378 break; 379 380#ifdef notyet /* XXX signal stack */ 381 if (oldcontext == sp + s1 || oldcontext == sp + s2) { 382 if (p->p_model == DATAMODEL_NATIVE) { 383 ucontext_t *ucp = (ucontext_t *)oldcontext; 384 greg_t *gregs = ucp->uc_mcontext.gregs; 385 386 sp = dtrace_fulword(&gregs[REG_FP]); 387 pc = dtrace_fulword(&gregs[REG_PC]); 388 389 oldcontext = dtrace_fulword(&ucp->uc_link); 390 } else { 391 ucontext_t *ucp = (ucontext_t *)oldcontext; 392 greg_t *gregs = ucp->uc_mcontext.gregs; 393 394 sp = dtrace_fuword32(&gregs[EBP]); 395 pc = dtrace_fuword32(&gregs[EIP]); 396 397 oldcontext = dtrace_fuword32(&ucp->uc_link); 398 } 399 } else 400#endif /* XXX */ 401 { 402 pc = dtrace_fuword32((void *)(fp + 403 offsetof(struct i386_frame, f_retaddr))); 404 fp = dtrace_fuword32((void *)fp); 405 } 406 407 /* 408 * This is totally bogus: if we faulted, we're going to clear 409 * the fault and break. This is to deal with the apparently 410 * broken Java stacks on x86. 411 */ 412 if (*flags & CPU_DTRACE_FAULT) { 413 *flags &= ~CPU_DTRACE_FAULT; 414 break; 415 } 416 } 417 418zero: 419 while (pcstack_limit-- > 0) 420 *pcstack++ = 0; 421} 422 423uint64_t 424dtrace_getarg(int arg, int aframes) 425{ 426 uintptr_t val; 427 struct i386_frame *fp = (struct i386_frame *)dtrace_getfp(); 428 uintptr_t *stack; 429 int i; 430 431 for (i = 1; i <= aframes; i++) { 432 fp = fp->f_frame; 433 434 if (P2ROUNDUP(fp->f_retaddr, 4) == 435 (long)dtrace_invop_callsite) { 436 /* 437 * If we pass through the invalid op handler, we will 438 * use the pointer that it passed to the stack as the 439 * second argument to dtrace_invop() as the pointer to 440 * the stack. When using this stack, we must step 441 * beyond the EIP/RIP that was pushed when the trap was 442 * taken -- hence the "+ 1" below. 443 */ 444 stack = ((uintptr_t **)&fp[1])[0] + 1; 445 goto load; 446 } 447 448 } 449 450 /* 451 * We know that we did not come through a trap to get into 452 * dtrace_probe() -- the provider simply called dtrace_probe() 453 * directly. As this is the case, we need to shift the argument 454 * that we're looking for: the probe ID is the first argument to 455 * dtrace_probe(), so the argument n will actually be found where 456 * one would expect to find argument (n + 1). 457 */ 458 arg++; 459 460 stack = (uintptr_t *)fp + 2; 461 462load: 463 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 464 val = stack[arg]; 465 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); 466 467 return (val); 468} 469 470int 471dtrace_getstackdepth(int aframes) 472{ 473 int depth = 0; 474 struct i386_frame *frame; 475 vm_offset_t ebp; 476 477 aframes++; 478 ebp = dtrace_getfp(); 479 frame = (struct i386_frame *)ebp; 480 depth++; 481 for(;;) { 482 if (!INKERNEL((long) frame)) 483 break; 484 if (!INKERNEL((long) frame->f_frame)) 485 break; 486 depth++; 487 if (frame->f_frame <= frame || 488 (vm_offset_t)frame->f_frame >= curthread->td_kstack + 489 curthread->td_kstack_pages * PAGE_SIZE) 490 break; 491 frame = frame->f_frame; 492 } 493 if (depth < aframes) 494 return 0; 495 else 496 return depth - aframes; 497} 498 499ulong_t 500dtrace_getreg(struct trapframe *rp, uint_t reg) 501{ 502 struct pcb *pcb; 503 int regmap[] = { /* Order is dependent on reg.d */ 504 REG_GS, /* 0 GS */ 505 REG_FS, /* 1 FS */ 506 REG_ES, /* 2 ES */ 507 REG_DS, /* 3 DS */ 508 REG_RDI, /* 4 EDI */ 509 REG_RSI, /* 5 ESI */ 510 REG_RBP, /* 6 EBP, REG_FP */ 511 REG_RSP, /* 7 ESP */ 512 REG_RBX, /* 8 EBX */ 513 REG_RDX, /* 9 EDX, REG_R1 */ 514 REG_RCX, /* 10 ECX */ 515 REG_RAX, /* 11 EAX, REG_R0 */ 516 REG_TRAPNO, /* 12 TRAPNO */ 517 REG_ERR, /* 13 ERR */ 518 REG_RIP, /* 14 EIP, REG_PC */ 519 REG_CS, /* 15 CS */ 520 REG_RFL, /* 16 EFL, REG_PS */ 521 REG_RSP, /* 17 UESP, REG_SP */ 522 REG_SS /* 18 SS */ 523 }; 524 525 if (reg > SS) { 526 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 527 return (0); 528 } 529 530 if (reg >= sizeof (regmap) / sizeof (int)) { 531 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 532 return (0); 533 } 534 535 reg = regmap[reg]; 536 537 switch(reg) { 538 case REG_GS: 539 if ((pcb = curthread->td_pcb) == NULL) { 540 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 541 return (0); 542 } 543 return (pcb->pcb_gs); 544 case REG_FS: 545 return (rp->tf_fs); 546 case REG_ES: 547 return (rp->tf_es); 548 case REG_DS: 549 return (rp->tf_ds); 550 case REG_RDI: 551 return (rp->tf_edi); 552 case REG_RSI: 553 return (rp->tf_esi); 554 case REG_RBP: 555 return (rp->tf_ebp); 556 case REG_RSP: 557 return (rp->tf_isp); 558 case REG_RBX: 559 return (rp->tf_ebx); 560 case REG_RCX: 561 return (rp->tf_ecx); 562 case REG_RAX: 563 return (rp->tf_eax); 564 case REG_TRAPNO: 565 return (rp->tf_trapno); 566 case REG_ERR: 567 return (rp->tf_err); 568 case REG_RIP: 569 return (rp->tf_eip); 570 case REG_CS: 571 return (rp->tf_cs); 572 case REG_RFL: 573 return (rp->tf_eflags); 574#if 0 575 case REG_RSP: 576 return (rp->tf_esp); 577#endif 578 case REG_SS: 579 return (rp->tf_ss); 580 default: 581 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 582 return (0); 583 } 584} 585 586static int 587dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 588{ 589 ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr); 590 591 if (uaddr + size >= kernelbase || uaddr + size < uaddr) { 592 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 593 cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 594 return (0); 595 } 596 597 return (1); 598} 599 600void 601dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 602 volatile uint16_t *flags) 603{ 604 if (dtrace_copycheck(uaddr, kaddr, size)) 605 dtrace_copy(uaddr, kaddr, size); 606} 607 608void 609dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 610 volatile uint16_t *flags) 611{ 612 if (dtrace_copycheck(uaddr, kaddr, size)) 613 dtrace_copy(kaddr, uaddr, size); 614} 615 616void 617dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 618 volatile uint16_t *flags) 619{ 620 if (dtrace_copycheck(uaddr, kaddr, size)) 621 dtrace_copystr(uaddr, kaddr, size, flags); 622} 623 624void 625dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 626 volatile uint16_t *flags) 627{ 628 if (dtrace_copycheck(uaddr, kaddr, size)) 629 dtrace_copystr(kaddr, uaddr, size, flags); 630} 631 632uint8_t 633dtrace_fuword8(void *uaddr) 634{ 635 if ((uintptr_t)uaddr >= kernelbase) { 636 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 637 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 638 return (0); 639 } 640 return (dtrace_fuword8_nocheck(uaddr)); 641} 642 643uint16_t 644dtrace_fuword16(void *uaddr) 645{ 646 if ((uintptr_t)uaddr >= kernelbase) { 647 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 648 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 649 return (0); 650 } 651 return (dtrace_fuword16_nocheck(uaddr)); 652} 653 654uint32_t 655dtrace_fuword32(void *uaddr) 656{ 657 if ((uintptr_t)uaddr >= kernelbase) { 658 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 659 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 660 return (0); 661 } 662 return (dtrace_fuword32_nocheck(uaddr)); 663} 664 665uint64_t 666dtrace_fuword64(void *uaddr) 667{ 668 if ((uintptr_t)uaddr >= kernelbase) { 669 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 670 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 671 return (0); 672 } 673 return (dtrace_fuword64_nocheck(uaddr)); 674} 675