17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5f498645aSahl * Common Development and Distribution License (the "License"). 6f498645aSahl * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21f498645aSahl 227c478bd9Sstevel@tonic-gate /* 23f34a7178SJoe Bonasera * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 27*49048e7cSBryan Cantrill /* 28*49048e7cSBryan Cantrill * Copyright (c) 2011, Joyent, Inc. All rights reserved. 29*49048e7cSBryan Cantrill */ 30*49048e7cSBryan Cantrill 317c478bd9Sstevel@tonic-gate #include <sys/dtrace.h> 327c478bd9Sstevel@tonic-gate #include <sys/fasttrap.h> 337c478bd9Sstevel@tonic-gate #include <sys/x_call.h> 347c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 357c478bd9Sstevel@tonic-gate #include <sys/trap.h> 367c478bd9Sstevel@tonic-gate #include <sys/psw.h> 377c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 387c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 397c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h> 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate typedef struct dtrace_invop_hdlr { 427c478bd9Sstevel@tonic-gate int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t); 437c478bd9Sstevel@tonic-gate struct dtrace_invop_hdlr *dtih_next; 447c478bd9Sstevel@tonic-gate } dtrace_invop_hdlr_t; 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate dtrace_invop_hdlr_t *dtrace_invop_hdlr; 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate int 497c478bd9Sstevel@tonic-gate dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax) 507c478bd9Sstevel@tonic-gate { 517c478bd9Sstevel@tonic-gate dtrace_invop_hdlr_t *hdlr; 527c478bd9Sstevel@tonic-gate int rval; 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) { 557c478bd9Sstevel@tonic-gate if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0) 567c478bd9Sstevel@tonic-gate return (rval); 577c478bd9Sstevel@tonic-gate } 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate return (0); 607c478bd9Sstevel@tonic-gate } 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate void 637c478bd9Sstevel@tonic-gate dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t)) 647c478bd9Sstevel@tonic-gate { 657c478bd9Sstevel@tonic-gate dtrace_invop_hdlr_t *hdlr; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP); 687c478bd9Sstevel@tonic-gate hdlr->dtih_func = func; 697c478bd9Sstevel@tonic-gate hdlr->dtih_next = dtrace_invop_hdlr; 707c478bd9Sstevel@tonic-gate dtrace_invop_hdlr = hdlr; 717c478bd9Sstevel@tonic-gate } 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate void 747c478bd9Sstevel@tonic-gate dtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t)) 757c478bd9Sstevel@tonic-gate { 767c478bd9Sstevel@tonic-gate dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate for (;;) { 797c478bd9Sstevel@tonic-gate if (hdlr == NULL) 807c478bd9Sstevel@tonic-gate panic("attempt to remove non-existent invop handler"); 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate if (hdlr->dtih_func == func) 837c478bd9Sstevel@tonic-gate break; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate prev = hdlr; 867c478bd9Sstevel@tonic-gate hdlr = hdlr->dtih_next; 877c478bd9Sstevel@tonic-gate } 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate if (prev == NULL) { 907c478bd9Sstevel@tonic-gate ASSERT(dtrace_invop_hdlr == hdlr); 917c478bd9Sstevel@tonic-gate dtrace_invop_hdlr = hdlr->dtih_next; 927c478bd9Sstevel@tonic-gate } else { 937c478bd9Sstevel@tonic-gate ASSERT(dtrace_invop_hdlr != hdlr); 947c478bd9Sstevel@tonic-gate prev->dtih_next = hdlr->dtih_next; 957c478bd9Sstevel@tonic-gate } 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate kmem_free(hdlr, sizeof (dtrace_invop_hdlr_t)); 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate int 1017c478bd9Sstevel@tonic-gate dtrace_getipl(void) 1027c478bd9Sstevel@tonic-gate { 1037c478bd9Sstevel@tonic-gate return (CPU->cpu_pri); 1047c478bd9Sstevel@tonic-gate } 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1077c478bd9Sstevel@tonic-gate void 1087c478bd9Sstevel@tonic-gate dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit)) 1097c478bd9Sstevel@tonic-gate { 1107c478bd9Sstevel@tonic-gate #ifdef __amd64 1117c478bd9Sstevel@tonic-gate extern uintptr_t toxic_addr; 1127c478bd9Sstevel@tonic-gate extern size_t toxic_size; 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate (*func)(0, _userlimit); 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate if (hole_end > hole_start) 1177c478bd9Sstevel@tonic-gate (*func)(hole_start, hole_end); 1187c478bd9Sstevel@tonic-gate (*func)(toxic_addr, toxic_addr + toxic_size); 1197c478bd9Sstevel@tonic-gate #else 1207c478bd9Sstevel@tonic-gate extern void *device_arena_contains(void *, size_t, size_t *); 1217c478bd9Sstevel@tonic-gate caddr_t vaddr; 1227c478bd9Sstevel@tonic-gate size_t len; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate for (vaddr = (caddr_t)kernelbase; vaddr < (caddr_t)KERNEL_TEXT; 1257c478bd9Sstevel@tonic-gate vaddr += len) { 1267c478bd9Sstevel@tonic-gate len = (caddr_t)KERNEL_TEXT - vaddr; 1277c478bd9Sstevel@tonic-gate vaddr = device_arena_contains(vaddr, len, &len); 1287c478bd9Sstevel@tonic-gate if (vaddr == NULL) 1297c478bd9Sstevel@tonic-gate break; 1307c478bd9Sstevel@tonic-gate (*func)((uintptr_t)vaddr, (uintptr_t)vaddr + len); 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate #endif 1337c478bd9Sstevel@tonic-gate (*func)(0, _userlimit); 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate static int 1377c478bd9Sstevel@tonic-gate dtrace_xcall_func(dtrace_xcall_t func, void *arg) 1387c478bd9Sstevel@tonic-gate { 1397c478bd9Sstevel@tonic-gate (*func)(arg); 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate return (0); 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1457c478bd9Sstevel@tonic-gate void 1467c478bd9Sstevel@tonic-gate dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) 1477c478bd9Sstevel@tonic-gate { 1487c478bd9Sstevel@tonic-gate cpuset_t set; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate CPUSET_ZERO(set); 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate if (cpu == DTRACE_CPUALL) { 1537c478bd9Sstevel@tonic-gate CPUSET_ALL(set); 1547c478bd9Sstevel@tonic-gate } else { 1557c478bd9Sstevel@tonic-gate CPUSET_ADD(set, cpu); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate kpreempt_disable(); 159f34a7178SJoe Bonasera xc_sync((xc_arg_t)func, (xc_arg_t)arg, 0, CPUSET2BV(set), 1607c478bd9Sstevel@tonic-gate (xc_func_t)dtrace_xcall_func); 1617c478bd9Sstevel@tonic-gate kpreempt_enable(); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate void 1657c478bd9Sstevel@tonic-gate dtrace_sync_func(void) 1667c478bd9Sstevel@tonic-gate {} 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate void 1697c478bd9Sstevel@tonic-gate dtrace_sync(void) 1707c478bd9Sstevel@tonic-gate { 1717c478bd9Sstevel@tonic-gate dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL); 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate int (*dtrace_pid_probe_ptr)(struct regs *); 1757c478bd9Sstevel@tonic-gate int (*dtrace_return_probe_ptr)(struct regs *); 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate void 1787c478bd9Sstevel@tonic-gate dtrace_user_probe(struct regs *rp, caddr_t addr, processorid_t cpuid) 1797c478bd9Sstevel@tonic-gate { 1807c478bd9Sstevel@tonic-gate krwlock_t *rwp; 1817c478bd9Sstevel@tonic-gate proc_t *p = curproc; 1827c478bd9Sstevel@tonic-gate extern void trap(struct regs *, caddr_t, processorid_t); 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate if (USERMODE(rp->r_cs) || (rp->r_ps & PS_VM)) { 1857c478bd9Sstevel@tonic-gate if (curthread->t_cred != p->p_cred) { 1867c478bd9Sstevel@tonic-gate cred_t *oldcred = curthread->t_cred; 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate * DTrace accesses t_cred in probe context. t_cred 1897c478bd9Sstevel@tonic-gate * must always be either NULL, or point to a valid, 1907c478bd9Sstevel@tonic-gate * allocated cred structure. 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate curthread->t_cred = crgetcred(); 1937c478bd9Sstevel@tonic-gate crfree(oldcred); 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate if (rp->r_trapno == T_DTRACE_RET) { 1987c478bd9Sstevel@tonic-gate uint8_t step = curthread->t_dtrace_step; 1997c478bd9Sstevel@tonic-gate uint8_t ret = curthread->t_dtrace_ret; 2007c478bd9Sstevel@tonic-gate uintptr_t npc = curthread->t_dtrace_npc; 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate if (curthread->t_dtrace_ast) { 2037c478bd9Sstevel@tonic-gate aston(curthread); 2047c478bd9Sstevel@tonic-gate curthread->t_sig_check = 1; 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* 2087c478bd9Sstevel@tonic-gate * Clear all user tracing flags. 2097c478bd9Sstevel@tonic-gate */ 2107c478bd9Sstevel@tonic-gate curthread->t_dtrace_ft = 0; 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate /* 2137c478bd9Sstevel@tonic-gate * If we weren't expecting to take a return probe trap, kill 2147c478bd9Sstevel@tonic-gate * the process as though it had just executed an unassigned 2157c478bd9Sstevel@tonic-gate * trap instruction. 2167c478bd9Sstevel@tonic-gate */ 2177c478bd9Sstevel@tonic-gate if (step == 0) { 2187c478bd9Sstevel@tonic-gate tsignal(curthread, SIGILL); 2197c478bd9Sstevel@tonic-gate return; 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate /* 2237c478bd9Sstevel@tonic-gate * If we hit this trap unrelated to a return probe, we're 2247c478bd9Sstevel@tonic-gate * just here to reset the AST flag since we deferred a signal 2257c478bd9Sstevel@tonic-gate * until after we logically single-stepped the instruction we 2267c478bd9Sstevel@tonic-gate * copied out. 2277c478bd9Sstevel@tonic-gate */ 2287c478bd9Sstevel@tonic-gate if (ret == 0) { 2297c478bd9Sstevel@tonic-gate rp->r_pc = npc; 2307c478bd9Sstevel@tonic-gate return; 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /* 2347c478bd9Sstevel@tonic-gate * We need to wait until after we've called the 2357c478bd9Sstevel@tonic-gate * dtrace_return_probe_ptr function pointer to set %pc. 2367c478bd9Sstevel@tonic-gate */ 2377c478bd9Sstevel@tonic-gate rwp = &CPU->cpu_ft_lock; 2387c478bd9Sstevel@tonic-gate rw_enter(rwp, RW_READER); 2397c478bd9Sstevel@tonic-gate if (dtrace_return_probe_ptr != NULL) 2407c478bd9Sstevel@tonic-gate (void) (*dtrace_return_probe_ptr)(rp); 2417c478bd9Sstevel@tonic-gate rw_exit(rwp); 2427c478bd9Sstevel@tonic-gate rp->r_pc = npc; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate } else if (rp->r_trapno == T_BPTFLT) { 245ddece0baSsethg uint8_t instr, instr2; 246ddece0baSsethg caddr_t linearpc; 2477c478bd9Sstevel@tonic-gate rwp = &CPU->cpu_ft_lock; 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * The DTrace fasttrap provider uses the breakpoint trap 2517c478bd9Sstevel@tonic-gate * (int 3). We let DTrace take the first crack at handling 2527c478bd9Sstevel@tonic-gate * this trap; if it's not a probe that DTrace knowns about, 2537c478bd9Sstevel@tonic-gate * we call into the trap() routine to handle it like a 2547c478bd9Sstevel@tonic-gate * breakpoint placed by a conventional debugger. 2557c478bd9Sstevel@tonic-gate */ 2567c478bd9Sstevel@tonic-gate rw_enter(rwp, RW_READER); 2577c478bd9Sstevel@tonic-gate if (dtrace_pid_probe_ptr != NULL && 2587c478bd9Sstevel@tonic-gate (*dtrace_pid_probe_ptr)(rp) == 0) { 2597c478bd9Sstevel@tonic-gate rw_exit(rwp); 2607c478bd9Sstevel@tonic-gate return; 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate rw_exit(rwp); 2637c478bd9Sstevel@tonic-gate 264ddece0baSsethg if (dtrace_linear_pc(rp, p, &linearpc) != 0) { 265ddece0baSsethg trap(rp, addr, cpuid); 266ddece0baSsethg return; 267ddece0baSsethg } 268ddece0baSsethg 2697c478bd9Sstevel@tonic-gate /* 2707c478bd9Sstevel@tonic-gate * If the instruction that caused the breakpoint trap doesn't 2717c478bd9Sstevel@tonic-gate * look like an int 3 anymore, it may be that this tracepoint 2727c478bd9Sstevel@tonic-gate * was removed just after the user thread executed it. In 2737c478bd9Sstevel@tonic-gate * that case, return to user land to retry the instuction. 274ddece0baSsethg * Note that we assume the length of the instruction to retry 275ddece0baSsethg * is 1 byte because that's the length of FASTTRAP_INSTR. 276ddece0baSsethg * We check for r_pc > 0 and > 2 so that we don't have to 277ddece0baSsethg * deal with segment wraparound. 2787c478bd9Sstevel@tonic-gate */ 279ddece0baSsethg if (rp->r_pc > 0 && fuword8(linearpc - 1, &instr) == 0 && 280ddece0baSsethg instr != FASTTRAP_INSTR && 281ddece0baSsethg (instr != 3 || (rp->r_pc >= 2 && 282ddece0baSsethg (fuword8(linearpc - 2, &instr2) != 0 || instr2 != 0xCD)))) { 2837c478bd9Sstevel@tonic-gate rp->r_pc--; 2847c478bd9Sstevel@tonic-gate return; 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate trap(rp, addr, cpuid); 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate } else { 2907c478bd9Sstevel@tonic-gate trap(rp, addr, cpuid); 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate void 2957c478bd9Sstevel@tonic-gate dtrace_safe_synchronous_signal(void) 2967c478bd9Sstevel@tonic-gate { 2977c478bd9Sstevel@tonic-gate kthread_t *t = curthread; 2987c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(ttolwp(t)); 2997c478bd9Sstevel@tonic-gate size_t isz = t->t_dtrace_npc - t->t_dtrace_pc; 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate ASSERT(t->t_dtrace_on); 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate /* 3047c478bd9Sstevel@tonic-gate * If we're not in the range of scratch addresses, we're not actually 3057c478bd9Sstevel@tonic-gate * tracing user instructions so turn off the flags. If the instruction 3067c478bd9Sstevel@tonic-gate * we copied out caused a synchonous trap, reset the pc back to its 3077c478bd9Sstevel@tonic-gate * original value and turn off the flags. 3087c478bd9Sstevel@tonic-gate */ 3097c478bd9Sstevel@tonic-gate if (rp->r_pc < t->t_dtrace_scrpc || 3107c478bd9Sstevel@tonic-gate rp->r_pc > t->t_dtrace_astpc + isz) { 3117c478bd9Sstevel@tonic-gate t->t_dtrace_ft = 0; 3127c478bd9Sstevel@tonic-gate } else if (rp->r_pc == t->t_dtrace_scrpc || 3137c478bd9Sstevel@tonic-gate rp->r_pc == t->t_dtrace_astpc) { 3147c478bd9Sstevel@tonic-gate rp->r_pc = t->t_dtrace_pc; 3157c478bd9Sstevel@tonic-gate t->t_dtrace_ft = 0; 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate int 3207c478bd9Sstevel@tonic-gate dtrace_safe_defer_signal(void) 3217c478bd9Sstevel@tonic-gate { 3227c478bd9Sstevel@tonic-gate kthread_t *t = curthread; 3237c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(ttolwp(t)); 3247c478bd9Sstevel@tonic-gate size_t isz = t->t_dtrace_npc - t->t_dtrace_pc; 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate ASSERT(t->t_dtrace_on); 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* 3297c478bd9Sstevel@tonic-gate * If we're not in the range of scratch addresses, we're not actually 3307c478bd9Sstevel@tonic-gate * tracing user instructions so turn off the flags. 3317c478bd9Sstevel@tonic-gate */ 3327c478bd9Sstevel@tonic-gate if (rp->r_pc < t->t_dtrace_scrpc || 3337c478bd9Sstevel@tonic-gate rp->r_pc > t->t_dtrace_astpc + isz) { 3347c478bd9Sstevel@tonic-gate t->t_dtrace_ft = 0; 3357c478bd9Sstevel@tonic-gate return (0); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate /* 339*49048e7cSBryan Cantrill * If we have executed the original instruction, but we have performed 340*49048e7cSBryan Cantrill * neither the jmp back to t->t_dtrace_npc nor the clean up of any 341*49048e7cSBryan Cantrill * registers used to emulate %rip-relative instructions in 64-bit mode, 342*49048e7cSBryan Cantrill * we'll save ourselves some effort by doing that here and taking the 343*49048e7cSBryan Cantrill * signal right away. We detect this condition by seeing if the program 344*49048e7cSBryan Cantrill * counter is the range [scrpc + isz, astpc). 3457c478bd9Sstevel@tonic-gate */ 346*49048e7cSBryan Cantrill if (rp->r_pc >= t->t_dtrace_scrpc + isz && 347*49048e7cSBryan Cantrill rp->r_pc < t->t_dtrace_astpc) { 3487c478bd9Sstevel@tonic-gate #ifdef __amd64 3497c478bd9Sstevel@tonic-gate /* 3507c478bd9Sstevel@tonic-gate * If there is a scratch register and we're on the 3517c478bd9Sstevel@tonic-gate * instruction immediately after the modified instruction, 3527c478bd9Sstevel@tonic-gate * restore the value of that scratch register. 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate if (t->t_dtrace_reg != 0 && 3557c478bd9Sstevel@tonic-gate rp->r_pc == t->t_dtrace_scrpc + isz) { 3567c478bd9Sstevel@tonic-gate switch (t->t_dtrace_reg) { 3577c478bd9Sstevel@tonic-gate case REG_RAX: 3587c478bd9Sstevel@tonic-gate rp->r_rax = t->t_dtrace_regv; 3597c478bd9Sstevel@tonic-gate break; 3607c478bd9Sstevel@tonic-gate case REG_RCX: 3617c478bd9Sstevel@tonic-gate rp->r_rcx = t->t_dtrace_regv; 3627c478bd9Sstevel@tonic-gate break; 3637c478bd9Sstevel@tonic-gate case REG_R8: 3647c478bd9Sstevel@tonic-gate rp->r_r8 = t->t_dtrace_regv; 3657c478bd9Sstevel@tonic-gate break; 3667c478bd9Sstevel@tonic-gate case REG_R9: 3677c478bd9Sstevel@tonic-gate rp->r_r9 = t->t_dtrace_regv; 3687c478bd9Sstevel@tonic-gate break; 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate #endif 3727c478bd9Sstevel@tonic-gate rp->r_pc = t->t_dtrace_npc; 3737c478bd9Sstevel@tonic-gate t->t_dtrace_ft = 0; 3747c478bd9Sstevel@tonic-gate return (0); 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate /* 3787c478bd9Sstevel@tonic-gate * Otherwise, make sure we'll return to the kernel after executing 3797c478bd9Sstevel@tonic-gate * the copied out instruction and defer the signal. 3807c478bd9Sstevel@tonic-gate */ 3817c478bd9Sstevel@tonic-gate if (!t->t_dtrace_step) { 3827c478bd9Sstevel@tonic-gate ASSERT(rp->r_pc < t->t_dtrace_astpc); 3837c478bd9Sstevel@tonic-gate rp->r_pc += t->t_dtrace_astpc - t->t_dtrace_scrpc; 3847c478bd9Sstevel@tonic-gate t->t_dtrace_step = 1; 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate t->t_dtrace_ast = 1; 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate return (1); 3907c478bd9Sstevel@tonic-gate } 391ae115bc7Smrj 392ae115bc7Smrj /* 393ae115bc7Smrj * Additional artificial frames for the machine type. For i86pc, we're already 394843e1988Sjohnlev * accounted for, so return 0. On the hypervisor, we have an additional frame 395843e1988Sjohnlev * (xen_callback_handler). 396ae115bc7Smrj */ 397ae115bc7Smrj int 398ae115bc7Smrj dtrace_mach_aframes(void) 399ae115bc7Smrj { 400843e1988Sjohnlev #ifdef __xpv 401843e1988Sjohnlev return (1); 402843e1988Sjohnlev #else 403ae115bc7Smrj return (0); 404843e1988Sjohnlev #endif 405ae115bc7Smrj } 406