Exemple #1
0
R_API int r_debug_esil_stepi (RDebug *d) {
	RAnalOp op;
	ut8 obuf[64];
	int ret = 1;
	dbg = d;
	if (!ESIL) {
		ESIL = r_anal_esil_new (R_TRUE);
		// TODO setup something?
	}

	r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE);
	opc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
	dbg->iob.read_at (dbg->iob.io, opc, obuf, sizeof (obuf));

	//dbg->iob.read_at (dbg->iob.io, npc, buf, sizeof (buf));

	//dbg->anal->reg = dbg->reg; // hack
	ESIL->cb.hook_mem_read = &esilbreak_mem_read;
	ESIL->cb.hook_mem_write = &esilbreak_mem_write;
	ESIL->cb.hook_reg_read = &esilbreak_reg_read;
	ESIL->cb.hook_reg_write = &esilbreak_reg_write;

	if (prestep) {
		// required when a exxpression is like <= == ..
		// otherwise it will stop at the next instruction
		if (r_debug_step (dbg, 1)<1) {
			eprintf ("Step failed\n");
			return 0;
		}
		r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE);
		//	npc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
	}

	if (r_anal_op (dbg->anal, &op, opc, obuf, sizeof (obuf))) {
		if (esilbreak_check_pc (dbg, opc)) {
			eprintf ("STOP AT 0x%08"PFMT64x"\n", opc);
			ret = 0;
		} else {
			r_anal_esil_set_pc (ESIL, opc);
			eprintf ("0x%08"PFMT64x"  %s\n", opc, R_STRBUF_SAFEGET (&op.esil));
			(void)r_anal_esil_parse (ESIL, R_STRBUF_SAFEGET (&op.esil));
			//r_anal_esil_dumpstack (ESIL);
			r_anal_esil_stack_free (ESIL);
			ret = 1;
		}
	}
	if (!prestep) {
		if (ret && !has_match) {
			if (r_debug_step (dbg, 1)<1) {
				eprintf ("Step failed\n");
				return 0;
			}
			r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE);
			//	npc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
		}
	}
	return ret;
}
Exemple #2
0
R_API int r_debug_continue_until_optype(RDebug *dbg, int type, int over) {
	int ret, n = 0;
	ut64 pc, buf_pc = 0;
	RAnalOp op;
	ut8 buf[DBG_BUF_SIZE];

	if (r_debug_is_dead (dbg)) {
		return R_FALSE;
	}

	if (!dbg->anal || !dbg->reg) { 
		eprintf ("Undefined pointer at dbg->anal\n");
		return R_FALSE;
	}

	r_debug_step (dbg, 1);
	r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE);

	// Initial refill
	buf_pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
	dbg->iob.read_at (dbg->iob.io, buf_pc, buf, sizeof (buf));

	// step first, we dont want to check current optype
	for (;;) {
		r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE);
		pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
		// Try to keep the buffer full 
		if (pc - buf_pc > sizeof (buf)) { 
			buf_pc = pc;
			dbg->iob.read_at (dbg->iob.io, buf_pc, buf, sizeof (buf));
		}
		// Analyze the opcode
		if (!r_anal_op (dbg->anal, &op, pc, buf + (pc - buf_pc), sizeof (buf) - (pc - buf_pc))) {
			eprintf ("Decode error at %"PFMT64x"\n", pc);
			return R_FALSE;
		}
		if (op.type == type) 
			break;
		// Step over and repeat
		ret = over ?
			r_debug_step_over (dbg, 1) :
			r_debug_step (dbg, 1);

		if (!ret) {
			eprintf ("r_debug_step: failed\n");
			break;
		}
		n++;
	}

	return n;
}
Exemple #3
0
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;
}
Exemple #4
0
R_API int r_debug_continue_syscalls(RDebug *dbg, int *sc, int n_sc) {
	int i, reg, ret = R_FALSE;
	if (!dbg || !dbg->h || r_debug_is_dead (dbg))
		return R_FALSE;
	if (!dbg->h->contsc) {
		/* user-level syscall tracing */
		r_debug_continue_until_optype (dbg, R_ANAL_OP_TYPE_SWI, 0);
		return show_syscall (dbg, "a0");
	}

	if (!r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE)) {
		eprintf ("--> cannot read registers\n");
		return -1;
	}
	{
		int err;
		reg = (int)r_debug_reg_get_err (dbg, "sn", &err);
		if (err) {
			eprintf ("Cannot find 'sn' register for current arch-os.\n");
			return -1;
		}
	}
	for (;;) {
		if (r_cons_singleton()->breaked)
			break;
#if __linux__
		// step is needed to avoid dupped contsc results
		r_debug_step (dbg, 1);
#endif
		dbg->h->contsc (dbg, dbg->pid, 0); // TODO handle return value
		// wait until continuation
		r_debug_wait (dbg);
		if (!r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE)) {
			eprintf ("--> cannot sync regs, process is probably dead\n");
			return -1;
		}
		reg = show_syscall (dbg, "sn");
		if (n_sc == -1)
			continue;
		if (n_sc == 0) {
			break;
		}
		for (i=0; i<n_sc; i++) {
			if (sc[i] == reg)
				return reg;
		}
		// TODO: must use r_core_cmd(as)..import code from rcore
	}
	return ret;
}
Exemple #5
0
R_API int r_debug_continue_until(RDebug *dbg, ut64 addr) {
// TODO: use breakpoint+continue... more efficient
	RRegItem *ripc = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_PC], R_REG_TYPE_GPR);
	int n = 0;
	ut64 pc = r_reg_get_value (dbg->reg, ripc);
	while (pc != addr && !r_debug_is_dead (dbg)) {
		r_debug_step (dbg, 1);
		// TODO: obey breakpoints too?
	/* TODO: check if the debugger stops at the right address */
		pc = r_reg_get_value (dbg->reg, ripc);
		n++;
	}
	return n;
}
Exemple #6
0
/*
 * replace breakpoints before we continue execution
 *
 * this is called from r_debug_step_hard or r_debug_continue_kill
 *
 * this is a trick process because of breakpoints/tracepoints.
 *
 * if a breakpoint was just hit, we need step over that instruction before
 * allowing the caller to proceed as desired.
 *
 * if the user wants to step, the single step here does the job.
 */
static int r_debug_recoil(RDebug *dbg, RDebugRecoilMode rc_mode) {
	/* if bp_addr is not set, we must not have actually hit a breakpoint */
	if (!dbg->reason.bp_addr) {
		return r_debug_bps_enable (dbg);
	}

	/* don't do anything if we already are recoiling */
	if (dbg->recoil_mode != R_DBG_RECOIL_NONE) {
		/* the first time recoil is called with swstep, we just need to
		 * look up the bp and step past it.
		 * the second time it's called, the new sw breakpoint should exist
		 * so we just restore all except what we originally hit and reset.
		 */
		if (dbg->swstep) {
			if (!r_bp_restore_except (dbg->bp, true, dbg->reason.bp_addr)) {
				return false;
			}
			return true;
		}

		/* otherwise, avoid recursion */
		return true;
	}

	/* we have entered recoil! */
	dbg->recoil_mode = rc_mode;

	/* step over the place with the breakpoint and let the caller resume */
	if (r_debug_step (dbg, 1) != 1) {
		return false;
	}

	/* when stepping away from a breakpoint during recoil in stepping mode,
	 * the r_debug_bp_hit function tells us that it was called
	 * innapropriately by setting bp_addr back to zero. however, recoil_mode
	 * is still set. we use this condition to know not to proceed but
	 * pretend as if we had.
	 */
	if (!dbg->reason.bp_addr && dbg->recoil_mode == R_DBG_RECOIL_STEP) {
		/* restore all sw breakpoints. we are about to step/continue so these need
		 * to be in place. */
		if (!r_bp_restore (dbg->bp, true)) {
			return false;
		}
		return true;
	}

	return r_debug_bps_enable (dbg);
}
Exemple #7
0
R_API int r_debug_continue_until(struct r_debug_t *dbg, ut64 addr) {
// TODO: use breakpoint+continue... more efficient
	int n = 0;
	ut64 pc = 0;
	if (r_debug_is_dead (dbg))
		return R_FALSE;
	do {
		if (pc !=0) r_debug_step (dbg, 1);
		n++;
	} while (pc != addr && !r_debug_is_dead (dbg));
	return n;
	//struct r_debug_bp_t *bp = r_debug_bp_add (dbg, addr);
	//int ret = r_debug_continue(dbg);
	/* TODO: check if the debugger stops at the right address */
	//r_debug_bp_del(dbg, bp);
	//return -1;
}
Exemple #8
0
R_API int r_debug_continue_kill(RDebug *dbg, int sig) {
	ut64 pc;
	int retwait, ret = R_FALSE;
	if (!dbg)
		return R_FALSE;
#if __WINDOWS__
	r_cons_break(w32_break_process, dbg);
#endif
repeat:
	if (r_debug_is_dead (dbg))
		return R_FALSE;
	if (dbg->h && dbg->h->cont) {
		r_bp_restore (dbg->bp, R_TRUE); // set sw breakpoints
		ret = dbg->h->cont (dbg, dbg->pid, dbg->tid, sig);
		dbg->reason.signum = 0;
		retwait = r_debug_wait (dbg);
#if __WINDOWS__
		if (retwait != R_DEBUG_REASON_DEAD) {
			ret = dbg->tid;
		}
#endif
		r_bp_restore (dbg->bp, R_FALSE); // unset sw breakpoints
		//r_debug_recoil (dbg);
		if (r_debug_recoil (dbg) || (dbg->reason.type == R_DEBUG_REASON_BREAKPOINT)) {
			/* check if cur bp demands tracing or not */
			pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
			RBreakpointItem *b = r_bp_get_at (dbg->bp, pc);
			if (b) {
				/* check if cur bp demands tracing or not */
				if (b->trace) {
					eprintf("hit tracepoit at: %"PFMT64x"\n",pc);
				} else {
					eprintf("hit breakpoint at: %"PFMT64x"\n",pc);
				}
				if (dbg->trace->enabled)
					r_debug_trace_pc (dbg);
				// TODO: delegate this to RCore.bphit(RCore, RBreakopintItem)
				if (dbg->corebind.core && dbg->corebind.bphit) {
					dbg->corebind.bphit (dbg->corebind.core, b);
				}
				if (b->trace) {
					r_debug_step (dbg, 1);
					goto repeat;
				}
			}
		}
#if 0
#if __UNIX__
		/* XXX Uh? */
		if (dbg->stop_all_threads && dbg->pid>0)
			r_sandbox_kill (dbg->pid, SIGSTOP);
#endif
#endif
		r_debug_select (dbg, dbg->pid, ret);
		sig = 0; // clear continuation after signal if needed
		if (retwait == R_DEBUG_REASON_SIGNAL && dbg->reason.signum != -1) {
			int what = r_debug_signal_what (dbg, dbg->reason.signum);
			if (what & R_DBG_SIGNAL_CONT) {
				sig = dbg->reason.signum;
				eprintf ("Continue into the signal %d handler\n", sig);
				goto repeat;
			} else if (what & R_DBG_SIGNAL_SKIP) {
				// skip signal. requires skipping one instruction
				ut8 buf[64];
				RAnalOp op = {0};
				ut64 pc = r_debug_reg_get (dbg, "pc");
				dbg->iob.read_at (dbg->iob.io, pc, buf, sizeof (buf));
				r_anal_op (dbg->anal, &op, pc, buf, sizeof (buf));
				if (op.size>0) {
					const char *signame = r_debug_signal_resolve_i (dbg, dbg->reason.signum);
					r_debug_reg_set (dbg, "pc", pc+op.size);
					eprintf ("Skip signal %d handler %s\n",
						dbg->reason.signum, signame);
					goto repeat;
				} else  {
					ut64 pc = r_debug_reg_get (dbg, "pc");
					eprintf ("Stalled with an exception at 0x%08"PFMT64x"\n", pc);
				}
			}
		}
	}
	return ret;
}
Exemple #9
0
R_API int r_debug_step_over(RDebug *dbg, int steps) {
	RAnalOp op;
	ut64 buf_pc, pc;
	ut8 buf[DBG_BUF_SIZE];
	int i;

	if (r_debug_is_dead (dbg))
		return R_FALSE;

	if (steps < 1)
		steps = 1;

	if (dbg->h && dbg->h->step_over) {
		for (i = 0; i < steps; i++)
			if (!dbg->h->step_over (dbg))
				return R_FALSE;
		return i;
	}

	if (!dbg->anal || !dbg->reg)
		return R_FALSE;

	// Initial refill
	buf_pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
	dbg->iob.read_at (dbg->iob.io, buf_pc, buf, sizeof (buf));

	for (i = 0; i < steps; i++) {
		pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]);
		// Try to keep the buffer full 
		if (pc - buf_pc > sizeof (buf)) { 
			buf_pc = pc;
			dbg->iob.read_at (dbg->iob.io, buf_pc, buf, sizeof (buf));
		}
		// Analyze the opcode
		if (!r_anal_op (dbg->anal, &op, pc, buf + (pc - buf_pc), sizeof (buf) - (pc - buf_pc))) {
			eprintf ("Decode error at %"PFMT64x"\n", pc);
			return R_FALSE;
		}

		// Skip over all the subroutine calls
		if (op.type == R_ANAL_OP_TYPE_CALL  ||
			op.type == R_ANAL_OP_TYPE_CCALL ||
			op.type == R_ANAL_OP_TYPE_UCALL ||
			op.type == R_ANAL_OP_TYPE_UCCALL) {

			// Use op.fail here instead of pc+op.size to enforce anal backends to fill in this field
			if (!r_debug_continue_until (dbg, op.fail)) {
				eprintf ("Could not step over call @ 0x%"PFMT64x"\n", pc);
				return R_FALSE;
			}
		} else if ((op.prefix & (R_ANAL_OP_PREFIX_REP | R_ANAL_OP_PREFIX_REPNE | R_ANAL_OP_PREFIX_LOCK))) {
			//eprintf ("REP: skip to next instruction...\n");
			if (!r_debug_continue_until (dbg, pc+op.size)) {
				eprintf ("step over failed over rep\n");
				return R_FALSE;
			}
		} else r_debug_step (dbg, 1);
	}

	return i;
}