📄 fasttrap_isa.c
字号:
return (0); if (instr != FASTTRAP_INSTR && instr != BREAKPOINT_INSTR) return (0); if (fasttrap_uwrite(p, &tp->ftt_instr, 4, tp->ftt_pc) != 0) return (-1); return (0);}intfasttrap_tracepoint_init(proc_t *p, fasttrap_probe_t *probe, fasttrap_tracepoint_t *tp, uintptr_t pc){ uint32_t instr; int32_t disp; /* * Read the instruction at the given address out of the process's * address space. We don't have to worry about a debugger * changing this instruction before we overwrite it with our trap * instruction since P_PR_LOCK is set. */ if (fasttrap_uread(p, &instr, 4, pc) != 0) return (-1); /* * Decode the instruction to fill in the probe flags. We can have * the process execute most instructions on its own using a pc/npc * trick, but pc-relative control transfer present a problem since * we're relocating the instruction. We emulate these instructions * in the kernel. We assume a default type and over-write that as * needed. * * pc-relative instructions must be emulated for correctness; * other instructions (which represent a large set of commonly traced * instructions) are emulated or otherwise optimized for performance. */ tp->ftt_type = FASTTRAP_T_COMMON; if (OP(instr) == 1) { /* * Call instructions. */ tp->ftt_type = FASTTRAP_T_CALL; disp = DISP30(instr) << 2; tp->ftt_dest = pc + (intptr_t)disp; } else if (OP(instr) == 0) { /* * Branch instructions. * * Unconditional branches need careful attention when they're * annulled: annulled unconditional branches never execute * the instruction in the delay slot. */ switch (OP2(instr)) { case OP2_ILLTRAP: case 0x7: /* * The compiler may place an illtrap after a call to * a function that returns a structure. In the case of * a returned structure, the compiler places an illtrap * whose const22 field is the size of the returned * structure immediately following the delay slot of * the call. To stay out of the way, we refuse to * place tracepoints on top of illtrap instructions. * * This is one of the dumbest architectural decisions * I've ever had to work around. * * We also identify the only illegal op2 value (See * SPARC Architecture Manual Version 9, E.2 table 31). */ return (-1); case OP2_BPcc: if (COND(instr) == 8) { tp->ftt_type = FASTTRAP_T_ALWAYS; } else { /* * Check for an illegal instruction. */ if (CC(instr) & 1) return (-1); tp->ftt_type = FASTTRAP_T_CCR; tp->ftt_cc = CC(instr); tp->ftt_code = COND(instr); } if (A(instr) != 0) tp->ftt_flags |= FASTTRAP_F_ANNUL; disp = DISP19(instr); disp <<= 13; disp >>= 11; tp->ftt_dest = pc + (intptr_t)disp; break; case OP2_Bicc: if (COND(instr) == 8) { tp->ftt_type = FASTTRAP_T_ALWAYS; } else { tp->ftt_type = FASTTRAP_T_CCR; tp->ftt_cc = 0; tp->ftt_code = COND(instr); } if (A(instr) != 0) tp->ftt_flags |= FASTTRAP_F_ANNUL; disp = DISP22(instr); disp <<= 10; disp >>= 8; tp->ftt_dest = pc + (intptr_t)disp; break; case OP2_BPr: /* * Check for an illegal instruction. */ if ((RCOND(instr) & 3) == 0) return (-1); /* * It's a violation of the v8plus ABI to use a * register-predicated branch in a 32-bit app if * the register used is an %l or an %i (%gs and %os * are legit because they're not saved to the stack * in 32-bit words when we take a trap). */ if (p->p_model == DATAMODEL_ILP32 && RS1(instr) >= 16) return (-1); tp->ftt_type = FASTTRAP_T_REG; if (A(instr) != 0) tp->ftt_flags |= FASTTRAP_F_ANNUL; disp = DISP16(instr); disp <<= 16; disp >>= 14; tp->ftt_dest = pc + (intptr_t)disp; tp->ftt_code = RCOND(instr); break; case OP2_SETHI: tp->ftt_type = FASTTRAP_T_SETHI; break; case OP2_FBPfcc: if (COND(instr) == 8) { tp->ftt_type = FASTTRAP_T_ALWAYS; } else { tp->ftt_type = FASTTRAP_T_FCC; tp->ftt_cc = CC(instr); tp->ftt_code = COND(instr); } if (A(instr) != 0) tp->ftt_flags |= FASTTRAP_F_ANNUL; disp = DISP19(instr); disp <<= 13; disp >>= 11; tp->ftt_dest = pc + (intptr_t)disp; break; case OP2_FBfcc: if (COND(instr) == 8) { tp->ftt_type = FASTTRAP_T_ALWAYS; } else { tp->ftt_type = FASTTRAP_T_FCC; tp->ftt_cc = 0; tp->ftt_code = COND(instr); } if (A(instr) != 0) tp->ftt_flags |= FASTTRAP_F_ANNUL; disp = DISP22(instr); disp <<= 10; disp >>= 8; tp->ftt_dest = pc + (intptr_t)disp; break; } } else if (OP(instr) == 2) { switch (OP3(instr)) { case OP3_RETURN: tp->ftt_type = FASTTRAP_T_RETURN; break; case OP3_JMPL: tp->ftt_type = FASTTRAP_T_JMPL; break; case OP3_RD: if (RS1(instr) == 5) tp->ftt_type = FASTTRAP_T_RDPC; break; case OP3_SAVE: /* * We optimize for save instructions at function * entry; see the comment in fasttrap_pid_probe() * (near FASTTRAP_T_SAVE) for details. */ if (fasttrap_optimize_save != 0 && probe->ftp_type == DTFTP_ENTRY && I(instr) == 1 && RD(instr) == R_SP) tp->ftt_type = FASTTRAP_T_SAVE; break; case OP3_RESTORE: /* * We optimize restore instructions at function * return; see the comment in fasttrap_pid_probe() * (near FASTTRAP_T_RESTORE) for details. * * rd must be an %o or %g register. */ if ((RD(instr) & 0x10) == 0) tp->ftt_type = FASTTRAP_T_RESTORE; break; case OP3_OR: /* * A large proportion of instructions in the delay * slot of retl instructions are or's so we emulate * these downstairs as an optimization. */ tp->ftt_type = FASTTRAP_T_OR; break; case OP3_TCC: /* * Breakpoint instructions are effectively position- * dependent since the debugger uses the %pc value * to lookup which breakpoint was executed. As a * result, we can't actually instrument breakpoints. */ if (SW_TRAP(instr) == ST_BREAKPOINT) return (-1); break; case 0x19: case 0x1d: case 0x29: case 0x33: case 0x3f: /* * Identify illegal instructions (See SPARC * Architecture Manual Version 9, E.2 table 32). */ return (-1); } } else if (OP(instr) == 3) { uint32_t op3 = OP3(instr); /* * Identify illegal instructions (See SPARC Architecture * Manual Version 9, E.2 table 33). */ if ((op3 & 0x28) == 0x28) { if (op3 != OP3_PREFETCH && op3 != OP3_CASA && op3 != OP3_PREFETCHA && op3 != OP3_CASXA) return (-1); } else { if ((op3 & 0x0f) == 0x0c || (op3 & 0x3b) == 0x31) return (-1); } } tp->ftt_instr = instr; return (0);}/*ARGSUSED*/uint64_tfasttrap_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes){ return (fasttrap_anarg(ttolwp(curthread)->lwp_regs, argno));}/*ARGSUSED*/uint64_tfasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes){ return (fasttrap_anarg(ttolwp(curthread)->lwp_regs, argno));}static uint64_t fasttrap_getreg_fast_cnt;static uint64_t fasttrap_getreg_mpcb_cnt;static uint64_t fasttrap_getreg_slow_cnt;static ulong_tfasttrap_getreg(struct regs *rp, uint_t reg){ ulong_t value; dtrace_icookie_t cookie; struct machpcb *mpcb; extern ulong_t dtrace_getreg_win(uint_t, uint_t); /* * We have the %os and %gs in our struct regs, but if we need to * snag a %l or %i we need to go scrounging around in the process's * address space. */ if (reg == 0) return (0); if (reg < 16) return ((&rp->r_g1)[reg - 1]); /* * Before we look at the user's stack, we'll check the register * windows to see if the information we want is in there. */ cookie = dtrace_interrupt_disable(); if (dtrace_getotherwin() > 0) { value = dtrace_getreg_win(reg, 1); dtrace_interrupt_enable(cookie); atomic_add_64(&fasttrap_getreg_fast_cnt, 1); return (value); } dtrace_interrupt_enable(cookie); /* * First check the machpcb structure to see if we've already read * in the register window we're looking for; if we haven't, (and * we probably haven't) try to copy in the value of the register. */ mpcb = (struct machpcb *)((caddr_t)rp - REGOFF); if (get_udatamodel() == DATAMODEL_NATIVE) { struct frame *fr = (struct frame *)(rp->r_sp + STACK_BIAS); if (mpcb->mpcb_wbcnt > 0) { struct rwindow *rwin = (void *)mpcb->mpcb_wbuf; int i = mpcb->mpcb_wbcnt; do { i--; if ((long)mpcb->mpcb_spbuf[i] != rp->r_sp) continue; atomic_add_64(&fasttrap_getreg_mpcb_cnt, 1); return (rwin[i].rw_local[reg - 16]); } while (i > 0); } if (fasttrap_fulword(&fr->fr_local[reg - 16], &value) != 0) goto err; } else { struct frame32 *fr = (struct frame32 *)(caddr32_t)rp->r_sp; uint32_t *v32 = (uint32_t *)&value; if (mpcb->mpcb_wbcnt > 0) { struct rwindow32 *rwin = (void *)mpcb->mpcb_wbuf; int i = mpcb->mpcb_wbcnt; do { i--; if ((long)mpcb->mpcb_spbuf[i] != rp->r_sp) continue; atomic_add_64(&fasttrap_getreg_mpcb_cnt, 1); return (rwin[i].rw_local[reg - 16]); } while (i > 0); } if (fasttrap_fuword32(&fr->fr_local[reg - 16], &v32[1]) != 0) goto err; v32[0] = 0; } atomic_add_64(&fasttrap_getreg_slow_cnt, 1); return (value);err: /* * If the copy in failed, the process will be in a irrecoverable * state, and we have no choice but to kill it. */ psignal(ttoproc(curthread), SIGILL); return (0);}static uint64_t fasttrap_putreg_fast_cnt;static uint64_t fasttrap_putreg_mpcb_cnt;static uint64_t fasttrap_putreg_slow_cnt;static voidfasttrap_putreg(struct regs *rp, uint_t reg, ulong_t value){ dtrace_icookie_t cookie; struct machpcb *mpcb; extern void dtrace_putreg_win(uint_t, ulong_t); if (reg == 0) return; if (reg < 16) { (&rp->r_g1)[reg - 1] = value; return; } /* * If the user process is still using some register windows, we * can just place the value in the correct window. */ cookie = dtrace_interrupt_disable(); if (dtrace_getotherwin() > 0) { dtrace_putreg_win(reg, value); dtrace_interrupt_enable(cookie); atomic_add_64(&fasttrap_putreg_fast_cnt, 1); return; } dtrace_interrupt_enable(cookie); /* * First see if there's a copy of the register window in the * machpcb structure that we can modify; if there isn't try to * copy out the value. If that fails, we try to create a new * register window in the machpcb structure. While this isn't * _precisely_ the intended use of the machpcb structure, it * can't cause any problems since we know at this point in the * code that all of the user's data have been flushed out of the * register file (since %otherwin is 0). */ mpcb = (struct machpcb *)((caddr_t)rp - REGOFF); if (get_udatamodel() == DATAMODEL_NATIVE) { struct frame *fr = (struct frame *)(rp->r_sp + STACK_BIAS); struct rwindow *rwin = (struct rwindow *)mpcb->mpcb_wbuf; if (mpcb->mpcb_wbcnt > 0) { int i = mpcb->mpcb_wbcnt; do { i--; if ((long)mpcb->mpcb_spbuf[i] != rp->r_sp) continue; rwin[i].rw_local[reg - 16] = value; atomic_add_64(&fasttrap_putreg_mpcb_cnt, 1); return; } while (i > 0); } if (fasttrap_sulword(&fr->fr_local[reg - 16], value) != 0) { if (mpcb->mpcb_wbcnt >= MAXWIN || copyin(fr, &rwin[mpcb->mpcb_wbcnt], sizeof (*rwin)) != 0) goto err; rwin[mpcb->mpcb_wbcnt].rw_local[reg - 16] = value; mpcb->mpcb_spbuf[mpcb->mpcb_wbcnt] = (caddr_t)rp->r_sp; mpcb->mpcb_wbcnt++; atomic_add_64(&fasttrap_putreg_mpcb_cnt, 1); return; } } else { struct frame32 *fr = (struct frame32 *)(caddr32_t)rp->r_sp; struct rwindow32 *rwin = (struct rwindow32 *)mpcb->mpcb_wbuf; uint32_t v32 = (uint32_t)value; if (mpcb->mpcb_wbcnt > 0) { int i = mpcb->mpcb_wbcnt; do { i--; if ((long)mpcb->mpcb_spbuf[i] != rp->r_sp) continue; rwin[i].rw_local[reg - 16] = v32; atomic_add_64(&fasttrap_putreg_mpcb_cnt, 1); return; } while (i > 0); } if (fasttrap_suword32(&fr->fr_local[reg - 16], v32) != 0) { if (mpcb->mpcb_wbcnt >= MAXWIN || copyin(fr, &rwin[mpcb->mpcb_wbcnt], sizeof (*rwin)) != 0) goto err; rwin[mpcb->mpcb_wbcnt].rw_local[reg - 16] = v32; mpcb->mpcb_spbuf[mpcb->mpcb_wbcnt] = (caddr_t)rp->r_sp; mpcb->mpcb_wbcnt++; atomic_add_64(&fasttrap_putreg_mpcb_cnt, 1); return; } } atomic_add_64(&fasttrap_putreg_slow_cnt, 1); return;err: /* * If we couldn't record this register's value, the process is in an * irrecoverable state and we have no choice but to euthanize it. */ psignal(ttoproc(curthread), SIGILL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -