// XXX: very experimental R_API int r_debug_step_soft(RDebug *dbg) { int ret; ut8 buf[32]; RAnalOp op; ut64 pc0, pc1, pc2; if (r_debug_is_dead (dbg)) return R_FALSE; pc0 = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); dbg->iob.read_at (dbg->iob.io, pc0, buf, sizeof (buf)); ret = r_anal_op (dbg->anal, &op, pc0, buf, sizeof (buf)); //eprintf ("read from pc0 = 0x%llx\n", pc0); pc1 = pc0 + op.length; //eprintf ("oplen = %d\n", op.length); //eprintf ("breakpoint at pc1 = 0x%llx\n", pc1); // XXX: Does not works for 'ret' pc2 = op.jump? op.jump: 0; //eprintf ("ADD SECOND BREAKPOINT FRO CALLS %llx\n", op.jump); //eprintf ("breakpoint 2 at pc2 = 0x%llx\n", pc2); r_bp_add_sw (dbg->bp, pc1, 4, R_BP_PROT_EXEC); if (pc2) r_bp_add_sw (dbg->bp, pc2, 4, R_BP_PROT_EXEC); r_debug_continue (dbg); //eprintf ("wait\n"); //r_debug_wait (dbg); //eprintf ("del\n"); r_bp_del (dbg->bp, pc1); if (pc2) r_bp_del (dbg->bp, pc2); return ret; }
R_API int r_debug_continue_until(RDebug *dbg, ut64 addr) { int has_bp; ut64 pc; if (r_debug_is_dead (dbg)) return R_FALSE; // Check if there was another breakpoint set at addr has_bp = r_bp_get_in (dbg->bp, addr, R_BP_PROT_EXEC) != NULL; if (!has_bp) r_bp_add_sw (dbg->bp, addr, dbg->bpsize, R_BP_PROT_EXEC); // Continue until the bp is reached for (;;) { if (r_debug_is_dead (dbg)) break; pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); if (pc == addr) break; if (r_bp_get_at (dbg->bp, pc)) break; r_debug_continue (dbg); } // Clean up if needed if (!has_bp) r_bp_del (dbg->bp, addr); return R_TRUE; }
R_API int r_debug_step_over(RDebug *dbg, int steps) { RAnalOp op; ut8 buf[64]; int ret = -1; if (r_debug_is_dead (dbg)) return R_FALSE; if (dbg->h && dbg->h->step_over) { if (steps<1) steps = 1; while (steps--) if (!dbg->h->step_over (dbg)) return R_FALSE; return R_TRUE; } if (dbg->anal && dbg->reg) { ut64 pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); dbg->iob.read_at (dbg->iob.io, pc, buf, sizeof (buf)); r_anal_op (dbg->anal, &op, pc, buf, sizeof (buf)); if (op.type & R_ANAL_OP_TYPE_CALL || op.type & R_ANAL_OP_TYPE_UCALL) { ut64 bpaddr = pc + op.length; r_bp_add_sw (dbg->bp, bpaddr, 1, R_BP_PROT_EXEC); ret = r_debug_continue (dbg); r_bp_del (dbg->bp, bpaddr); } else { ret = r_debug_step (dbg, 1); } } else eprintf ("Undefined debugger backend\n"); return ret; }
/* * Save 4096 bytes from %esp * TODO: Add support for reverse stack architectures * Also known as r_debug_inject() */ R_API ut64 r_debug_execute(RDebug *dbg, const ut8 *buf, int len, int restore) { int orig_sz; ut8 stackbackup[4096]; ut8 *backup, *orig = NULL; RRegItem *ri, *risp, *ripc; ut64 rsp, rpc, ra0 = 0LL; if (r_debug_is_dead (dbg)) return R_FALSE; ripc = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_PC], R_REG_TYPE_GPR); risp = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_SP], R_REG_TYPE_GPR); if (ripc) { r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE); orig = r_reg_get_bytes (dbg->reg, -1, &orig_sz); if (orig == NULL) { eprintf ("Cannot get register arena bytes\n"); return 0LL; } rpc = r_reg_get_value (dbg->reg, ripc); rsp = r_reg_get_value (dbg->reg, risp); backup = malloc (len); if (backup == NULL) { free (orig); return 0LL; } dbg->iob.read_at (dbg->iob.io, rpc, backup, len); dbg->iob.read_at (dbg->iob.io, rsp, stackbackup, len); r_bp_add_sw (dbg->bp, rpc+len, dbg->bpsize, R_BP_PROT_EXEC); /* execute code here */ dbg->iob.write_at (dbg->iob.io, rpc, buf, len); //r_bp_add_sw (dbg->bp, rpc+len, 4, R_BP_PROT_EXEC); r_debug_continue (dbg); //r_bp_del (dbg->bp, rpc+len); /* TODO: check if stopped in breakpoint or not */ r_bp_del (dbg->bp, rpc+len); dbg->iob.write_at (dbg->iob.io, rpc, backup, len); if (restore) { dbg->iob.write_at (dbg->iob.io, rsp, stackbackup, len); } r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE); ri = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_A0], R_REG_TYPE_GPR); ra0 = r_reg_get_value (dbg->reg, ri); if (restore) { r_reg_set_bytes (dbg->reg, -1, orig, orig_sz); } else { r_reg_set_value (dbg->reg, ripc, rpc); } r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_TRUE); free (backup); free (orig); eprintf ("ra0=0x%08"PFMT64x"\n", ra0); } else eprintf ("r_debug_execute: Cannot get program counter\n"); return (ra0); }
R_API int r_debug_step_soft(RDebug *dbg) { ut8 buf[32]; ut64 pc, sp; ut64 next[2]; RAnalOp op; int br, i, ret; union { ut64 r64; ut32 r32[2]; } sp_top; if (r_debug_is_dead (dbg)) return R_FALSE; pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); sp = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_SP]); if (dbg->iob.read_at) { if (dbg->iob.read_at (dbg->iob.io, pc, buf, sizeof (buf)) < 0) return R_FALSE; } else return R_FALSE; if (!r_anal_op (dbg->anal, &op, pc, buf, sizeof (buf))) return R_FALSE; if (op.type == R_ANAL_OP_TYPE_ILL) return R_FALSE; switch (op.type) { case R_ANAL_OP_TYPE_RET: dbg->iob.read_at (dbg->iob.io, sp, (ut8 *)&sp_top, 8); next[0] = (dbg->bits == R_SYS_BITS_32) ? sp_top.r32[0] : sp_top.r64; br = 1; break; case R_ANAL_OP_TYPE_CJMP: case R_ANAL_OP_TYPE_CCALL: next[0] = op.jump; next[1] = op.fail; br = 2; break; case R_ANAL_OP_TYPE_CALL: case R_ANAL_OP_TYPE_JMP: next[0] = op.jump; br = 1; break; default: next[0] = op.addr + op.size; br = 1; break; } for (i = 0; i < br; i++) r_bp_add_sw (dbg->bp, next[i], dbg->bpsize, R_BP_PROT_EXEC); ret = r_debug_continue (dbg); for (i = 0; i < br; i++) r_bp_del (dbg->bp, next[i]); return ret; }