📄 fasttrap_isa.c
字号:
FASTTRAP_REX_B(rex)); rm = 0; } else { tp->ftt_ripmode = FASTTRAP_RIP_2 | (FASTTRAP_RIP_X * FASTTRAP_REX_B(rex)); rm = 1; } tp->ftt_modrm = tp->ftt_instr[rmindex]; tp->ftt_instr[rmindex] = FASTTRAP_MODRM(2, reg, rm); } } }#endif return (0);}intfasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp){ fasttrap_instr_t instr = FASTTRAP_INSTR; if (fasttrap_uwrite(p, &instr, 1, tp->ftt_pc) != 0) return (-1); return (0);}intfasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp){ uint8_t instr; /* * Distinguish between read or write failures and a changed * instruction. */ if (fasttrap_uread(p, &instr, 1, tp->ftt_pc) != 0) return (0); if (instr != FASTTRAP_INSTR) return (0); if (fasttrap_uwrite(p, &tp->ftt_instr[0], 1, tp->ftt_pc) != 0) return (-1); return (0);}static uintptr_tfasttrap_fulword_noerr(const void *uaddr){ uintptr_t ret; if (fasttrap_fulword(uaddr, &ret) == 0) return (ret); return (0);}static uint32_tfasttrap_fuword32_noerr(const void *uaddr){ uint32_t ret; if (fasttrap_fuword32(uaddr, &ret) == 0) return (ret); return (0);}/*ARGSUSED*/intfasttrap_probe(struct regs *rp){#ifdef __amd64 proc_t *p = curproc;#endif uintptr_t s0, s1, s2, s3, s4;#ifdef __amd64 if (p->p_model == DATAMODEL_LP64) { uintptr_t *stack = (uintptr_t *)rp->r_sp; s0 = fasttrap_fulword_noerr(&stack[1]); s1 = fasttrap_fulword_noerr(&stack[2]); s2 = fasttrap_fulword_noerr(&stack[3]); s3 = fasttrap_fulword_noerr(&stack[4]); s4 = fasttrap_fulword_noerr(&stack[5]); } else {#endif uint32_t *stack = (uint32_t *)rp->r_sp; s0 = fasttrap_fuword32_noerr(&stack[1]); s1 = fasttrap_fuword32_noerr(&stack[2]); s2 = fasttrap_fuword32_noerr(&stack[3]); s3 = fasttrap_fuword32_noerr(&stack[4]); s4 = fasttrap_fuword32_noerr(&stack[5]);#ifdef __amd64 }#endif dtrace_probe(fasttrap_probe_id, s0, s1, s2, s3, s4); return (0);}static voidfasttrap_return_common(struct regs *rp, uintptr_t pc, pid_t pid, uintptr_t new_pc){ fasttrap_tracepoint_t *tp; fasttrap_bucket_t *bucket; fasttrap_id_t *id; kmutex_t *pid_mtx; pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock; mutex_enter(pid_mtx); bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]; for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { if (pid == tp->ftt_pid && pc == tp->ftt_pc && !tp->ftt_prov->ftp_defunct) break; } /* * Don't sweat it if we can't find the tracepoint again; unlike * when we're in fasttrap_pid_probe(), finding the tracepoint here * is not essential to the correct execution of the process. */ if (tp == NULL) { mutex_exit(pid_mtx); return; } for (id = tp->ftt_retids; id != NULL; id = id->fti_next) { /* * If there's a branch that could act as a return site, we * need to trace it, and check here if the program counter is * external to the function. */ if (new_pc - id->fti_probe->ftp_faddr < id->fti_probe->ftp_fsize) continue; dtrace_probe(id->fti_probe->ftp_id, pc - id->fti_probe->ftp_faddr, rp->r_r0, rp->r_r1, 0, 0); } mutex_exit(pid_mtx);}static voidfasttrap_sigsegv(proc_t *p, kthread_t *t, uintptr_t addr){ sigqueue_t *sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP); sqp->sq_info.si_signo = SIGSEGV; sqp->sq_info.si_code = SEGV_MAPERR; sqp->sq_info.si_addr = (caddr_t)addr; mutex_enter(&p->p_lock); sigaddqa(p, t, sqp); mutex_exit(&p->p_lock); if (t != NULL) aston(t);}#ifdef __amd64static voidfasttrap_usdt_args64(fasttrap_probe_t *probe, struct regs *rp, int argc, uintptr_t *argv){ int i, x, cap = MIN(argc, probe->ftp_nargs); uintptr_t *stack = (uintptr_t *)rp->r_sp; for (i = 0; i < cap; i++) { x = probe->ftp_argmap[i]; if (x < 6) argv[i] = (&rp->r_rdi)[x]; else argv[i] = fasttrap_fulword_noerr(&stack[x]); } for (; i < argc; i++) { argv[i] = 0; }}#endifstatic voidfasttrap_usdt_args32(fasttrap_probe_t *probe, struct regs *rp, int argc, uint32_t *argv){ int i, x, cap = MIN(argc, probe->ftp_nargs); uint32_t *stack = (uint32_t *)rp->r_sp; for (i = 0; i < cap; i++) { x = probe->ftp_argmap[i]; argv[i] = fasttrap_fuword32_noerr(&stack[x]); } for (; i < argc; i++) { argv[i] = 0; }}intfasttrap_pid_probe(struct regs *rp){ proc_t *p = curproc; uintptr_t pc = rp->r_pc - 1, new_pc = 0; fasttrap_bucket_t *bucket; kmutex_t *pid_mtx; fasttrap_tracepoint_t *tp, tp_local; pid_t pid; dtrace_icookie_t cookie; /* * It's possible that a user (in a veritable orgy of bad planning) * could redirect this thread's flow of control before it reached the * return probe fasttrap. In this case we need to kill the process * since it's in a unrecoverable state. */ if (curthread->t_dtrace_step) { ASSERT(curthread->t_dtrace_on); fasttrap_sigtrap(p, curthread, pc); return (0); } /* * Clear all user tracing flags. */ curthread->t_dtrace_ft = 0; curthread->t_dtrace_pc = 0; curthread->t_dtrace_npc = 0; curthread->t_dtrace_scrpc = 0; curthread->t_dtrace_astpc = 0;#ifdef __amd64 curthread->t_dtrace_regv = 0;#endif /* * Treat a child created by a call to vfork(2) as if it were its * parent. We know that there's only one thread of control in such a * process: this one. */ while (p->p_flag & SVFORK) { p = p->p_parent; } pid = p->p_pid; pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock; mutex_enter(pid_mtx); bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]; /* * Lookup the tracepoint that the process just hit. */ for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { if (pid == tp->ftt_pid && pc == tp->ftt_pc && !tp->ftt_prov->ftp_defunct) break; } /* * If we couldn't find a matching tracepoint, either a tracepoint has * been inserted without using the pid<pid> ioctl interface (see * fasttrap_ioctl), or somehow we have mislaid this tracepoint. */ if (tp == NULL) { mutex_exit(pid_mtx); return (-1); } /* * Set the program counter to the address of the traced instruction * so that it looks right in ustack() output. */ rp->r_pc = pc; if (tp->ftt_ids != NULL) { fasttrap_id_t *id;#ifdef __amd64 if (p->p_model == DATAMODEL_LP64) { for (id = tp->ftt_ids; id != NULL; id = id->fti_next) { fasttrap_probe_t *probe = id->fti_probe; if (probe->ftp_type == DTFTP_ENTRY) { /* * We note that this was an entry * probe to help ustack() find the * first caller. */ cookie = dtrace_interrupt_disable(); DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY); dtrace_probe(probe->ftp_id, rp->r_rdi, rp->r_rsi, rp->r_rdx, rp->r_rcx, rp->r_r8); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY); dtrace_interrupt_enable(cookie); } else if (probe->ftp_argmap == NULL) { dtrace_probe(probe->ftp_id, rp->r_rdi, rp->r_rsi, rp->r_rdx, rp->r_rcx, rp->r_r8); } else { uintptr_t t[5]; fasttrap_usdt_args64(probe, rp, sizeof (t) / sizeof (t[0]), t); dtrace_probe(probe->ftp_id, t[0], t[1], t[2], t[3], t[4]); } } } else {#endif uintptr_t s0, s1, s2, s3, s4, s5; uint32_t *stack = (uint32_t *)rp->r_sp; /* * In 32-bit mode, all arguments are passed on the * stack. If this is a function entry probe, we need * to skip the first entry on the stack as it * represents the return address rather than a * parameter to the function. */ s0 = fasttrap_fuword32_noerr(&stack[0]); s1 = fasttrap_fuword32_noerr(&stack[1]); s2 = fasttrap_fuword32_noerr(&stack[2]); s3 = fasttrap_fuword32_noerr(&stack[3]); s4 = fasttrap_fuword32_noerr(&stack[4]); s5 = fasttrap_fuword32_noerr(&stack[5]); for (id = tp->ftt_ids; id != NULL; id = id->fti_next) { fasttrap_probe_t *probe = id->fti_probe; if (probe->ftp_type == DTFTP_ENTRY) { /* * We note that this was an entry * probe to help ustack() find the * first caller. */ cookie = dtrace_interrupt_disable(); DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY); dtrace_probe(probe->ftp_id, s1, s2, s3, s4, s5); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY); dtrace_interrupt_enable(cookie); } else if (probe->ftp_argmap == NULL) { dtrace_probe(probe->ftp_id, s0, s1, s2, s3, s4); } else { uint32_t t[5]; fasttrap_usdt_args32(probe, rp, sizeof (t) / sizeof (t[0]), t); dtrace_probe(probe->ftp_id, t[0], t[1], t[2], t[3], t[4]); } }#ifdef __amd64 }#endif } /* * We're about to do a bunch of work so we cache a local copy of * the tracepoint to emulate the instruction, and then find the * tracepoint again later if we need to light up any return probes. */ tp_local = *tp; mutex_exit(pid_mtx); tp = &tp_local; /* * Set the program counter to appear as though the traced instruction * had completely executed. This ensures that fasttrap_getreg() will * report the expected value for REG_RIP. */ rp->r_pc = pc + tp->ftt_size; switch (tp->ftt_type) { case FASTTRAP_T_RET: case FASTTRAP_T_RET16: { uintptr_t dst; uintptr_t addr; int ret; /* * We have to emulate _every_ facet of the behavior of a ret * instruction including what happens if the load from %esp * fails; in that case, we send a SIGSEGV. */#ifdef __amd64 if (p->p_model == DATAMODEL_NATIVE) {#endif ret = fasttrap_fulword((void *)rp->r_sp, &dst); addr = rp->r_sp + sizeof (uintptr_t);#ifdef __amd64 } else { uint32_t dst32; ret = fasttrap_fuword32((void *)rp->r_sp, &dst32); dst = dst32; addr = rp->r_sp + sizeof (uint32_t); }#endif if (ret == -1) { fasttrap_sigsegv(p, curthread, rp->r_sp); new_pc = pc; break; } if (tp->ftt_type == FASTTRAP_T_RET16) addr += tp->ftt_dest; rp->r_sp = addr; new_pc = dst; break; } case FASTTRAP_T_JCC: { uint_t taken; switch (tp->ftt_code) { case FASTTRAP_JO: taken = (rp->r_ps & FASTTRAP_EFLAGS_OF) != 0; break; case FASTTRAP_JNO: taken = (rp->r_ps & FASTTRAP_EFLAGS_OF) == 0; break; case FASTTRAP_JB: taken = (rp->r_ps & FASTTRAP_EFLAGS_CF) != 0; break; case FASTTRAP_JAE: taken = (rp->r_ps & FASTTRAP_EFLAGS_CF) == 0; break; case FASTTRAP_JE: taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) != 0; break; case FASTTRAP_JNE: taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) == 0; break; case FASTTRAP_JBE: taken = (rp->r_ps & FASTTRAP_EFLAGS_CF) != 0 || (rp->r_ps & FASTTRAP_EFLAGS_ZF) != 0; break; case FASTTRAP_JA: taken = (rp->r_ps & FASTTRAP_EFLAGS_CF) == 0 && (rp->r_ps & FASTTRAP_EFLAGS_ZF) == 0; break; case FASTTRAP_JS: taken = (rp->r_ps & FASTTRAP_EFLAGS_SF) != 0; break; case FASTTRAP_JNS: taken = (rp->r_ps & FASTTRAP_EFLAGS_SF) == 0; break; case FASTTRAP_JP: taken = (rp->r_ps & FASTTRAP_EFLAGS_PF) != 0; break; case FASTTRAP_JNP: taken = (rp->r_ps & FASTTRAP_EFLAGS_PF) == 0; break; case FASTTRAP_JL: taken = ((rp->r_ps & FASTTRAP_EFLAGS_SF) == 0) != ((rp->r_ps & FASTTRAP_EFLAGS_OF) == 0); break; case FASTTRAP_JGE: taken = ((rp->r_ps & FASTTRAP_EFLAGS_SF) == 0) == ((rp->r_ps & FASTTRAP_EFLAGS_OF) == 0); break; case FASTTRAP_JLE: taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) != 0 || ((rp->r_ps & FASTTRAP_EFLAGS_SF) == 0) != ((rp->r_ps & FASTTRAP_EFLAGS_OF) == 0); break; case FASTTRAP_JG: taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) == 0 && ((rp->r_ps & FASTTRAP_EFLAGS_SF) == 0) == ((rp->r_ps & FASTTRAP_EFLAGS_OF) == 0); break; } if (taken) new_pc = tp->ftt_dest; else new_pc = pc + tp->ftt_size; break; } case FASTTRAP_T_LOOP: {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -