// XXX: Do this work correctly? static RList *backtrace_x86_64_anal(RDebug *dbg, ut64 at) { int i; ut8 buf[8]; RDebugFrame *frame; ut64 ptr, ebp2 = UT64_MAX; ut64 _rip, _rbp; RList *list; RReg *reg = dbg->reg; RIOBind *bio = &dbg->iob; RAnalFunction *fcn; _rip = r_reg_get_value (reg, r_reg_get (reg, "rip", R_REG_TYPE_GPR)); if (at == UT64_MAX) { //_rsp = r_reg_get_value (reg, r_reg_get (reg, "rsp", R_REG_TYPE_GPR)); _rbp = r_reg_get_value (reg, r_reg_get (reg, "rbp", R_REG_TYPE_GPR)); } else { _rbp = at; } list = r_list_new (); list->free = free; bio->read_at (bio->io, _rip, (ut8*)&buf, 8); // TODO : frame->size by using esil to emulate first instructions fcn = r_anal_get_fcn_in (dbg->anal, _rip, R_ANAL_FCN_TYPE_NULL); if (fcn) { frame = R_NEW0 (RDebugFrame); frame->addr = _rip; frame->size = 0; frame->sp = _rbp; frame->bp = _rbp + 8; // XXX r_list_append (list, frame); } for (i=1; i<dbg->btdepth; i++) { // TODO: make those two reads in a shot bio->read_at (bio->io, _rbp, (ut8*)&ebp2, 8); if (ebp2 == UT64_MAX) break; bio->read_at (bio->io, _rbp+8, (ut8*)&ptr, 8); if (!ptr || !_rbp) break; //fcn = r_anal_get_fcn_in (dbg->anal, ptr, R_ANAL_FCN_TYPE_NULL); frame = R_NEW0 (RDebugFrame); frame->addr = ptr; frame->size = 0; frame->sp = _rbp; frame->bp = _rbp + 8; //frame->name = (fcn && fcn->name) ? strdup (fcn->name) : NULL; r_list_append (list, frame); _rbp = ebp2; } return list; }
static RList *backtrace_x86_64(RDebug *dbg, ut64 at) { int i; ut8 buf[8]; RDebugFrame *frame; ut64 ptr, ebp2; ut64 _rip, _rsp, _rbp = 0; RList *list; RReg *reg = dbg->reg; RIOBind *bio = &dbg->iob; _rip = r_reg_get_value (reg, r_reg_get (reg, "rip", R_REG_TYPE_GPR)); if (at == UT64_MAX) { _rsp = r_reg_get_value (reg, r_reg_get (reg, "rsp", R_REG_TYPE_GPR)); _rbp = r_reg_get_value (reg, r_reg_get (reg, "rbp", R_REG_TYPE_GPR)); } else { _rsp = _rbp = at; } list = r_list_new (); list->free = free; bio->read_at (bio->io, _rip, (ut8*)&buf, 8); /* %rbp=old rbp, %rbp+4 points to ret */ /* Plugin before function prelude: push %rbp ; mov %rsp, %rbp */ if (!memcmp (buf, "\x55\x89\xe5", 3) || !memcmp (buf, "\x89\xe5\x57", 3)) { if (!bio->read_at (bio->io, _rsp, (ut8*)&ptr, 8)) { eprintf ("read error at 0x%08"PFMT64x"\n", _rsp); r_list_purge (list); free (list); return false; } frame = R_NEW0 (RDebugFrame); frame->addr = ptr; frame->size = 0; // TODO ? r_list_append (list, frame); _rbp = ptr; } for (i=1; i<dbg->btdepth; i++) { // TODO: make those two reads in a shot bio->read_at (bio->io, _rbp, (ut8*)&ebp2, 8); if (ebp2 == UT64_MAX) break; bio->read_at (bio->io, _rbp+8, (ut8*)&ptr, 8); if (!ptr || !_rbp) break; frame = R_NEW0 (RDebugFrame); frame->addr = ptr; frame->size = 0; // TODO ? r_list_append (list, frame); _rbp = ebp2; } return list; }
static ut64 ws_find_label(int l, RIOBind iob) { RIO *io = iob.io; ut64 cur = 0, size = iob.desc_size (io->desc); ut8 buf[128]; RAsmOp aop; iob.read_at (iob.io, cur, buf, 128); while (cur <= size && wsdis (&aop, buf, 128)) { const char *buf_asm = r_strbuf_get (&aop.buf_asm); // r_asm_op_get_asm (&aop); if (buf_asm && (strlen (buf_asm) > 4) && buf_asm[0] == 'm' && buf_asm[1] == 'a' && l == atoi (buf_asm + 5)) { return cur; } cur = cur + aop.size; iob.read_at (iob.io, cur, buf, 128); } return 0; }
static void ios_hwstep_enable32 (RDebug *dbg, task_t port, int enable) { int i; static ARMDebugState32 olds; ARMDebugState32 ds; mach_msg_type_number_t count = ARM_DEBUG_STATE32_COUNT; (void) thread_get_state (port, ARM_DEBUG_STATE32, (thread_state_t)&ds, &count); //static ut64 chainstep = UT64_MAX; if (enable) { RIOBind *bio = &dbg->iob; ut32 pc = r_reg_get_value (dbg->reg, r_reg_get (dbg->reg, "pc", R_REG_TYPE_GPR)); ut32 cpsr = r_reg_get_value (dbg->reg, r_reg_get (dbg->reg, "cpsr", R_REG_TYPE_GPR)); for (i = 0; i < 16 ; i++) { ds.bcr[i] = ds.bvr[i] = 0; } olds = ds; //chainstep = UT64_MAX; // state = old_state; ds.bvr[i] = pc & (UT32_MAX >> 2) << 2; ds.bcr[i] = BCR_M_IMVA_MISMATCH | S_USER | BCR_ENABLE; if (cpsr & 0x20) { ut16 op; if (pc & 2) { ds.bcr[i] |= BAS_IMVA_2_3; } else { ds.bcr[i] |= BAS_IMVA_0_1; } /* check for thumb */ bio->read_at (bio->io, pc, (void *)&op, 2); if (isThumb32 (op)) { eprintf ("Thumb32 chain stepping not supported yet\n"); //chainstep = pc + 2; } else { ds.bcr[i] |= BAS_IMVA_ALL; } } else { ds.bcr[i] |= BAS_IMVA_ALL; } } else {
static ut64 ws_find_label(int l, RIOBind iob) { ut64 cur = 0, size = iob.size(iob.io); ut8 buf[128]; RAsmOp *aop; aop = R_NEW0(RAsmOp); iob.read_at(iob.io, cur, buf, 128); while(cur <= size && wsdis(aop, buf, 128)) { if( aop->buf_asm[0] == 'm' && aop->buf_asm[1] == 'a' && l == atoi(&aop->buf_asm[5])) { r_asm_op_free(aop); return cur; } cur = cur + aop->size; iob.read_at(iob.io, cur, buf, 128); } r_asm_op_free(aop); return 0; }
void gb_bankswitch_detect(RMeta *m, RIOBind iob, ut64 addr, ut16 ldarg) { ut8 rt; if(addr > 0x3fff) return; iob.read_at(iob.io, 0x147, &rt, 1); //xxx: it won't change switch(gb_mbc_resolve(rt)) { case -1: r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "unknown MBC!!!"); case 0: return; default: meta_gb_bankswitch_cmt(m, addr, ldarg, (ut8)gb_mbc_resolve(rt)); } }
static ut64 is_pointer(RAnal *anal, const ut8 *buf, int size) { ut64 n; ut8 buf2[32]; RIOBind *iob = &anal->iob; if (size > sizeof (buf2)) size = sizeof (buf2); n = r_mem_get_num (buf, size); if (!n) return 1; // null pointer #if USE_IS_VALID_OFFSET int r = iob->is_valid_offset (iob->io, n, 0); return r? n: 0LL; #else // optimization to ignore very low and very high pointers // this makes disasm 5x faster, but can result in some false positives // we should compare with current offset, to avoid // short/long references. and discard invalid ones if (n < 0x1000) return 0; // probably wrong if (n > 0xffffffffffffLL) return 0; // probably wrong if (iob->read_at (iob->io, n, buf2, size) != size) return 0; return is_invalid (buf2, size)? 0: n; #endif }
static int modify_trace_bit(RDebug *dbg, xnu_thread *th, int enable) { R_DEBUG_REG_T *state; kern_return_t kr; int ret; ret = xnu_thread_get_drx (dbg, th); if (ret == R_FALSE) { eprintf ("error to get drx registers modificy_trace_bit arm\n"); return R_FALSE; } state = (R_DEBUG_REG_T)th->drx; if (state->flavor == ARM_DEBUG_STATE64) { state->uds.ds64.__mdscr_el1 = (state->uds64.__mdscr_el1 \ & SS_ENABLE) & (enable ? SS_ENABLE : 0); } else if (state->flavor == ARM_DEBUG_STATE32) { R_REG_T *regs; ret = xnu_thread_get_gpr (dbg, th); if (ret == R_FALSE) { eprintf ("error to get gpr register modificy_trace_bit arm\n"); return R_FALSE; } regs = (R_REG_T)th->gpr; if (enable) { int r, i = 0; RIOBind *bio = &dbg->io; (R_DEBUG_REG_T)th->oldstate = state; //set a breakpoint that will stop when the PC doesn't //match the current one //set the current PC as the breakpoint address state->uds.ds32.__bvr[i] = regs->ts_32.__pc; state->uds.ds32.__bcr[i] = BCR_M_IMVA_MISMATCH | //stop on address mismatch S_USER | //stop only in user mode BCR_ENABLE; // enable this breakpoint if (regs->ts_32.__cpsr & 0x20) { ut16 op; // Thumb breakpoint if (regs->ts_32.__pc & 2) { state->uds.ds32.__bcr[i] |= BAS_IMVA_2_3; } else { state->uds.ds32.__bcr[i] |= BAS_IMVA_0_1; } if (bio->read_at (bio->io, regs->ts_32.__pc, (void *)&op, 2) < 1) { eprintf ("Failed to read opcode modify_trace_bit\n"); return false; } if (is_thumb_32 (op)) { eprintf ("Thumb32 chain stepping not supported yet\n"); return false; } else { // Extend the number of bits to ignore for the mismatch state->uds.ds32.__bcr[i] |= BAS_IMVA_ALL; } } else { // ARM breakpoint state->uds.ds32.__bcr[i] |= BAS_IMVA_ALL; // Stop when any address bits change } //disable bits for (i = i + 1; i < 16; i++) { //Disable all others state->uds.ds32.__bcr[i] = 0; state->uds.ds32.__bvr[i] = 0; } } else { state->uds.ds32 = ((R_DEBUG_REG_T)th->oldstate)->uds.ds32; //we set the old state } } else { eprintf ("Bad flavor modificy_trace_bit arm\n"); return false; } //set state th->count = state->dsh.count; memcpy (th->state, state->uds, th->count); if (!xnu_thread_set_drx (dbg, th)) { eprintf ("error to set drx modificy_trace_bit arm\n"); return false; } return true; }
static int modify_trace_bit(RDebug *dbg, xnu_thread_t *th, int enable) { int i = 0; int ret = xnu_thread_get_drx (dbg, th); if (!ret) { eprintf ("error to get drx registers modificy_trace_bit arm\n"); return false; } if (th->flavor == ARM_DEBUG_STATE32) { arm_debug_state32_t *state = &th->debug.drx32; state->__mdscr_el1 = (state->__mdscr_el1 & SS_ENABLE) & (enable ? SS_ENABLE : 0); } else if (th->flavor == ARM_DEBUG_STATE) { arm_debug_state_t *state = &th->debug.drx; R_REG_T *regs; ret = xnu_thread_get_gpr (dbg, th); if (!ret) { eprintf ("error to get gpr register modificy_trace_bit arm\n"); return false; } regs = (R_REG_T*)&th->gpr; if (enable) { static ut64 chained_address = 0; RIOBind *bio = &dbg->iob; //set a breakpoint that will stop when the PC doesn't //match the current one //set the current PC as the breakpoint address if (chained_address) { state->__bvr[i] = chained_address & 0xFFFFFFFCu; chained_address = 0; } else { state->__bvr[i] = regs->ts_32.__pc & 0xFFFFFFFCu; } state->__bcr[i] = BCR_M_IMVA_MISMATCH | // stop on // address // mismatch S_USER | // stop only in user mode BCR_ENABLE; // enable this breakpoint if (regs->ts_32.__cpsr & 0x20) { ut16 op; // Thumb breakpoint if (regs->ts_32.__pc & 2) state->__bcr[i] |= BAS_IMVA_2_3; else state->__bcr[i] |= BAS_IMVA_0_1; if (bio->read_at (bio->io, regs->ts_32.__pc, (void *)&op, 2) < 1) { eprintf ("Failed to read opcode modify_trace_bit\n"); return false; } if (is_thumb_32 (op)) { chained_address = regs->ts_32.__pc + 2; } else { // Extend the number of bits to ignore for the mismatch state->__bcr[i] |= BAS_IMVA_ALL; } } else { // ARM breakpoint state->__bcr[i] |= BAS_IMVA_ALL; // Stop when any address bits change } //disable bits for (i = i + 1; i < 16; i++) { //Disable all others state->__bcr[i] = 0; state->__bvr[i] = 0; } } else { if (state->__bcr[i] & BCR_ENABLE) { state->__bvr[i] = 0; state->__bcr[i] = 0; } } } else { eprintf ("Bad flavor modificy_trace_bit arm\n"); return false; } //set state if (!xnu_thread_set_drx (dbg, th)) { eprintf ("error to set drx modificy_trace_bit arm\n"); return false; } return true; }
static RList *backtrace_fuzzy(RDebug *dbg, ut64 at) { ut8 *stack, *ptr; int wordsize = dbg->bits; // XXX, dbg->bits is wordsize not bits ut64 sp; RIOBind *bio = &dbg->iob; int i, stacksize; ut64 *p64, addr = 0LL; ut32 *p32; ut16 *p16; ut64 cursp, oldsp; RList *list; stacksize = 1024*512; // 512KB .. should get the size from the regions if possible stack = malloc (stacksize); if (at == UT64_MAX) { RRegItem *ri; RReg *reg = dbg->reg; const char *spname = r_reg_get_name (reg, R_REG_NAME_SP); if (!spname) { eprintf ("Cannot find stack pointer register\n"); free (stack); return NULL; } ri = r_reg_get (reg, spname, R_REG_TYPE_GPR); if (!ri) { eprintf ("Cannot find stack pointer register\n"); free (stack); return NULL; } sp = r_reg_get_value (reg, ri); } else { sp = at; } list = r_list_new (); list->free = free; cursp = oldsp = sp; (void)bio->read_at (bio->io, sp, stack, stacksize); ptr = stack; for (i=0; i<dbg->btdepth; i++) { p64 = (ut64*)ptr; p32 = (ut32*)ptr; p16 = (ut16*)ptr; switch (wordsize) { case 8: addr = *p64; break; case 4: addr = *p32; break; case 2: addr = *p16; break; default: eprintf ("Invalid word size with asm.bits\n"); r_list_free (list); return NULL; } if (iscallret (dbg, addr)) { RDebugFrame *frame = R_NEW0 (RDebugFrame); frame->addr = addr; frame->size = cursp - oldsp; frame->sp = cursp; frame->bp = oldsp; //addr + (i * wordsize); // -4 || -8 // eprintf ("--------------> 0x%llx (%d)\n", addr, frame->size); r_list_append (list, frame); oldsp = cursp; } ptr += wordsize; cursp += wordsize; } return list; }