X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/cf7d32b81c573a0536dc4da4157f9c26f8d0bed3..4bd07ac2140668789aa3ee8ec4dde4a3e0a3bba5:/bsd/dev/i386/fasttrap_isa.c diff --git a/bsd/dev/i386/fasttrap_isa.c b/bsd/dev/i386/fasttrap_isa.c index c96666b0b..4eeb6d140 100644 --- a/bsd/dev/i386/fasttrap_isa.c +++ b/bsd/dev/i386/fasttrap_isa.c @@ -20,12 +20,12 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* - * #pragma ident "@(#)fasttrap_isa.c 1.23 06/09/19 SMI" + * #pragma ident "@(#)fasttrap_isa.c 1.27 08/04/09 SMI" */ #ifdef KERNEL @@ -45,7 +45,10 @@ extern dtrace_id_t dtrace_probeid_error; #include #include -#define proc_t struct proc +#include + +/* Solaris proc_t is the struct. Darwin's proc_t is a pointer to it. */ +#define proc_t struct proc /* Steer clear of the Darwin typedef for proc_t */ /* * Lossless User-Land Tracing on x86 @@ -194,21 +197,19 @@ extern dtrace_id_t dtrace_probeid_error; * * REG_RAX -> EAX * REG_RCX -> ECX - * ... + * REG_RDX -> EDX + * REG_RBX -> EBX + * REG_RSP -> UESP + * REG_RBP -> EBP + * REG_RSI -> ESI * REG_RDI -> EDI * * The fasttrap_getreg function knows how to make the correct transformation. */ -#if __sol64 || defined(__APPLE__) static const uint8_t regmap[16] = { REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP, REG_RSI, REG_RDI, REG_R8, REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, }; -#else -static const uint8_t regmap[8] = { - EAX, ECX, EDX, EBX, UESP, EBP, ESI, EDI -}; -#endif static user_addr_t fasttrap_getreg(x86_saved_state_t *, uint_t); @@ -247,7 +248,7 @@ fasttrap_anarg(x86_saved_state_t *regs, int function_entry, int argno) value = dtrace_fuword64(stack); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR); } else { - uint32_t *stack = (uint32_t *)regs32->uesp; + uint32_t *stack = (uint32_t *)(uintptr_t)(regs32->uesp); DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); value = dtrace_fuword32((user_addr_t)(unsigned long)&stack[argno + shift]); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR); @@ -360,13 +361,11 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc, break; } -#if __sol64 || defined(__APPLE__) /* * Identify the REX prefix on 64-bit processes. */ if (p_model == DATAMODEL_LP64 && (instr[start] & 0xf0) == 0x40) rex = instr[start++]; -#endif /* * Now that we're pretty sure that the instruction is okay, copy the @@ -396,6 +395,7 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc, tp->ftt_type = FASTTRAP_T_JCC; tp->ftt_code = (instr[start + 1] & 0x0f) | FASTTRAP_JO; tp->ftt_dest = pc + tp->ftt_size + + /* LINTED - alignment */ *(int32_t *)&instr[start + 2]; break; } @@ -448,11 +448,9 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc, * modes, there is a 32-bit operand. */ if (mod == 0 && rm == 5) { -#if __sol64 || defined(__APPLE__) if (p_model == DATAMODEL_LP64) tp->ftt_base = REG_RIP; else -#endif tp->ftt_base = FASTTRAP_NOREG; sz = 4; } else { @@ -466,12 +464,14 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc, i = 2; } - if (sz == 1) + if (sz == 1) { tp->ftt_dest = *(int8_t *)&instr[start + i]; - else if (sz == 4) + } else if (sz == 4) { + /* LINTED - alignment */ tp->ftt_dest = *(int32_t *)&instr[start + i]; - else + } else { tp->ftt_dest = 0; + } } } else { switch (instr[start]) { @@ -481,6 +481,7 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc, case FASTTRAP_RET16: tp->ftt_type = FASTTRAP_T_RET16; + /* LINTED - alignment */ tp->ftt_dest = *(uint16_t *)&instr[start + 1]; break; @@ -524,6 +525,7 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc, case FASTTRAP_CALL: tp->ftt_type = FASTTRAP_T_CALL; tp->ftt_dest = pc + tp->ftt_size + + /* LINTED - alignment */ *(int32_t *)&instr[start + 1]; tp->ftt_code = 0; break; @@ -531,6 +533,7 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc, case FASTTRAP_JMP32: tp->ftt_type = FASTTRAP_T_JMP; tp->ftt_dest = pc + tp->ftt_size + + /* LINTED - alignment */ *(int32_t *)&instr[start + 1]; break; case FASTTRAP_JMP8: @@ -545,7 +548,6 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc, break; case FASTTRAP_NOP: -#if __sol64 || defined(__APPLE__) ASSERT(p_model == DATAMODEL_LP64 || rex == 0); /* @@ -555,7 +557,6 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc, * (e.g. xchgl %r8d, %eax or xcghq %r8, %rax). */ if (FASTTRAP_REX_B(rex) == 0) -#endif tp->ftt_type = FASTTRAP_T_NOP; break; @@ -582,7 +583,6 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc, } } -#if __sol64 || defined(__APPLE__) if (p_model == DATAMODEL_LP64 && tp->ftt_type == FASTTRAP_T_COMMON) { /* * If the process is 64-bit and the instruction type is still @@ -628,7 +628,6 @@ fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, user_addr_t pc, } } } -#endif return (0); } @@ -671,6 +670,8 @@ fasttrap_return_common(x86_saved_state_t *regs, user_addr_t pc, pid_t pid, x86_saved_state32_t *regs32; unsigned int p_model; + dtrace_icookie_t cookie; + if (is_saved_state64(regs)) { regs64 = saved_state64(regs); regs32 = NULL; @@ -692,7 +693,7 @@ fasttrap_return_common(x86_saved_state_t *regs, user_addr_t pc, pid_t pid, for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { if (pid == tp->ftt_pid && pc == tp->ftt_pc && - !tp->ftt_proc->ftpc_defunct) + tp->ftt_proc->ftpc_acount != 0) break; } @@ -718,6 +719,13 @@ fasttrap_return_common(x86_saved_state_t *regs, user_addr_t pc, pid_t pid, id->fti_probe->ftp_fsize) continue; + /* + * Provide a hint to the stack trace functions to add the + * following pc to the top of the stack since it's missing + * on a return probe yet highly desirable for consistency. + */ + cookie = dtrace_interrupt_disable(); + cpu_core[CPU->cpu_id].cpuc_missing_tos = pc; if (ISSET(current_proc()->p_lflag, P_LNOATTACH)) { dtrace_probe(dtrace_probeid_error, 0 /* state */, id->fti_probe->ftp_id, 1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV); @@ -730,6 +738,9 @@ fasttrap_return_common(x86_saved_state_t *regs, user_addr_t pc, pid_t pid, pc - id->fti_probe->ftp_faddr, regs32->eax, regs32->edx, 0, 0); } + /* remove the hint */ + cpu_core[CPU->cpu_id].cpuc_missing_tos = 0; + dtrace_interrupt_enable(cookie); } lck_mtx_unlock(pid_mtx); @@ -786,7 +797,7 @@ fasttrap_usdt_args32(fasttrap_probe_t *probe, x86_saved_state32_t *regs32, int a uint32_t *argv) { int i, x, cap = MIN(argc, probe->ftp_nargs); - uint32_t *stack = (uint32_t *)regs32->uesp; + uint32_t *stack = (uint32_t *)(uintptr_t)(regs32->uesp); for (i = 0; i < cap; i++) { x = probe->ftp_argmap[i]; @@ -972,12 +983,12 @@ fasttrap_pid_probe32(x86_saved_state_t *regs) * parent. We know that there's only one thread of control in such a * process: this one. */ - /* - * APPLE NOTE: Terry says: "You need to hold the process locks (currently: kernel funnel) for this traversal" - * FIXME: How do we assert this? - */ - while (p->p_lflag & P_LINVFORK) - p = p->p_pptr; + if (p->p_lflag & P_LINVFORK) { + proc_list_lock(); + while (p->p_lflag & P_LINVFORK) + p = p->p_pptr; + proc_list_unlock(); + } pid = p->p_pid; pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock; @@ -989,7 +1000,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs) */ for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { if (pid == tp->ftt_pid && pc == tp->ftt_pc && - !tp->ftt_proc->ftpc_defunct) + tp->ftt_proc->ftpc_acount != 0) break; } @@ -1013,7 +1024,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs) fasttrap_id_t *id; uint32_t s0, s1, s2, s3, s4, s5; - uint32_t *stack = (uint32_t *)regs32->uesp; + uint32_t *stack = (uint32_t *)(uintptr_t)(regs32->uesp); /* * In 32-bit mode, all arguments are passed on the @@ -1341,7 +1352,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs) case FASTTRAP_T_COMMON: { user_addr_t addr; - uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 5 + 2]; + uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 7]; uint_t i = 0; /* @@ -1402,6 +1413,7 @@ fasttrap_pid_probe32(x86_saved_state_t *regs) * the size of the traced instruction cancels out. */ scratch[i++] = FASTTRAP_JMP32; + /* LINTED - alignment */ *(uint32_t *)&scratch[i] = pc - addr - 5; i += sizeof (uint32_t); @@ -1411,6 +1423,8 @@ fasttrap_pid_probe32(x86_saved_state_t *regs) scratch[i++] = FASTTRAP_INT; scratch[i++] = T_DTRACE_RET; + ASSERT(i <= sizeof (scratch)); + if (fasttrap_copyout(scratch, addr, i)) { fasttrap_sigtrap(p, uthread, pc); new_pc = pc; @@ -1528,12 +1542,12 @@ fasttrap_pid_probe64(x86_saved_state_t *regs) * parent. We know that there's only one thread of control in such a * process: this one. */ - /* - * APPLE NOTE: Terry says: "You need to hold the process locks (currently: kernel funnel) for this traversal" - * FIXME: How do we assert this? - */ - while (p->p_lflag & P_LINVFORK) - p = p->p_pptr; + if (p->p_lflag & P_LINVFORK) { + proc_list_lock(); + while (p->p_lflag & P_LINVFORK) + p = p->p_pptr; + proc_list_unlock(); + } pid = p->p_pid; pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock; @@ -1545,7 +1559,7 @@ fasttrap_pid_probe64(x86_saved_state_t *regs) */ for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { if (pid == tp->ftt_pid && pc == tp->ftt_pc && - !tp->ftt_proc->ftpc_defunct) + tp->ftt_proc->ftpc_acount != 0) break; } @@ -1878,7 +1892,7 @@ fasttrap_pid_probe64(x86_saved_state_t *regs) case FASTTRAP_T_COMMON: { user_addr_t addr; - uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 5 + 2]; + uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 22]; uint_t i = 0; /* @@ -2025,6 +2039,7 @@ fasttrap_pid_probe64(x86_saved_state_t *regs) panic("unhandled ripmode in fasttrap_pid_probe64"); } + /* LINTED - alignment */ *(uint64_t *)&scratch[i] = *reg; uthread->t_dtrace_regv = *reg; *reg = pc + tp->ftt_size; @@ -2040,8 +2055,10 @@ fasttrap_pid_probe64(x86_saved_state_t *regs) */ scratch[i++] = FASTTRAP_GROUP5_OP; scratch[i++] = FASTTRAP_MODRM(0, 4, 5); + /* LINTED - alignment */ *(uint32_t *)&scratch[i] = 0; i += sizeof (uint32_t); + /* LINTED - alignment */ *(uint64_t *)&scratch[i] = pc + tp->ftt_size; i += sizeof (uint64_t); @@ -2051,6 +2068,8 @@ fasttrap_pid_probe64(x86_saved_state_t *regs) scratch[i++] = FASTTRAP_INT; scratch[i++] = T_DTRACE_RET; + ASSERT(i <= sizeof (scratch)); + if (fasttrap_copyout(scratch, addr, i)) { fasttrap_sigtrap(p, uthread, pc); new_pc = pc; @@ -2155,13 +2174,10 @@ fasttrap_return_probe(x86_saved_state_t *regs) * parent. We know that there's only one thread of control in such a * process: this one. */ - /* - * APPLE NOTE: Terry says: "You need to hold the process locks (currently: kernel funnel) for this traversal" - * How do we assert this? - */ - while (p->p_lflag & P_LINVFORK) { + proc_list_lock(); + while (p->p_lflag & P_LINVFORK) p = p->p_pptr; - } + proc_list_unlock(); /* * We set rp->r_pc to the address of the traced instruction so @@ -2184,6 +2200,7 @@ uint64_t fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes) { + pal_register_cache_state(current_thread(), VALID); #pragma unused(arg, id, parg, aframes) return (fasttrap_anarg((x86_saved_state_t *)find_user_regs(current_thread()), 1, argno)); } @@ -2192,6 +2209,7 @@ uint64_t fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes) { + pal_register_cache_state(current_thread(), VALID); #pragma unused(arg, id, parg, aframes) return (fasttrap_anarg((x86_saved_state_t *)find_user_regs(current_thread()), 0, argno)); } @@ -2223,6 +2241,20 @@ fasttrap_getreg(x86_saved_state_t *regs, uint_t reg) case REG_R13: return regs64->r13; case REG_R14: return regs64->r14; case REG_R15: return regs64->r15; + case REG_TRAPNO: return regs64->isf.trapno; + case REG_ERR: return regs64->isf.err; + case REG_RIP: return regs64->isf.rip; + case REG_CS: return regs64->isf.cs; + case REG_RFL: return regs64->isf.rflags; + case REG_SS: return regs64->isf.ss; + case REG_FS: return regs64->fs; + case REG_GS: return regs64->gs; + case REG_ES: + case REG_DS: + case REG_FSBASE: + case REG_GSBASE: + // Important to distinguish these requests (which should be legal) from other values. + panic("dtrace: unimplemented x86_64 getreg()"); } panic("dtrace: unhandled x86_64 getreg() constant");