mirror of
https://github.com/radareorg/radeco.git
synced 2026-11-07 06:36:01 -10:00
rune: explorer error handling
Replaces explicit panics with error handling in the `explorer` module.
This commit is contained in:
1 parent
ce435e3ad4
commit
c30eb12a11
9 files changed
+108
-49
No files matched your search
@@ -706,7 +706,7 @@ impl Tokenize for Tokenizer {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(h) = t.strip_prefix("0x") {
|
||||
} else if let Some(h) = t.strip_prefix("0x") {
|
||||
match u64::from_str_radix(h, 16) {
|
||||
Ok(v) => vec![Token::EConstant(v)],
|
||||
Err(_) => vec![Token::EInvalid],
|
||||
|
||||
+16
-19
@@ -4,7 +4,7 @@ use rune::context::rune_ctx::RuneContext;
|
||||
use rune::context::{Context, Evaluate, MemoryRead, RegisterRead};
|
||||
use rune::engine::rune::RuneControl;
|
||||
use rune::explorer::interactive::Command;
|
||||
use rune::explorer::PathExplorer;
|
||||
use rune::explorer::{ExplorerError, ExplorerResult, PathExplorer};
|
||||
use rune::memory::seg_mem::SegMem;
|
||||
use rune::regstore::regfile::RuneRegFile;
|
||||
|
||||
@@ -89,8 +89,7 @@ impl InteractiveExplorer {
|
||||
|
||||
let op_2 = {
|
||||
if let Some(h) = tokens[2].strip_prefix("0x") {
|
||||
let const_v =
|
||||
u64::from_str_radix(h, 16).expect("Invalid base16 Integer");
|
||||
let const_v = u64::from_str_radix(h, 16).expect("Invalid base16 Integer");
|
||||
ctx.define_const(const_v, 64)
|
||||
} else {
|
||||
ctx.reg_read(tokens[2])
|
||||
@@ -163,29 +162,27 @@ impl PathExplorer for InteractiveExplorer {
|
||||
&mut self,
|
||||
ctx: &mut Self::Ctx,
|
||||
condition: <Self::Ctx as RegisterRead>::VarRef,
|
||||
) -> RuneControl {
|
||||
) -> ExplorerResult<RuneControl> {
|
||||
if self.cmd_q.is_empty() {
|
||||
self.console
|
||||
.print_info(&format!("Encountered Branch At {:#x}", ctx.ip()));
|
||||
self.cmd_q = self.console.read_command();
|
||||
}
|
||||
|
||||
if let Some(cmd) = self.cmd_q.pop() {
|
||||
match cmd {
|
||||
Command::FollowTrue => {
|
||||
let one = ctx.define_const(1, 64);
|
||||
ctx.eval(core::OpCodes::Cmp, [condition, one]);
|
||||
RuneControl::ExploreTrue
|
||||
}
|
||||
Command::FollowFalse => {
|
||||
let zero = ctx.define_const(0, 64);
|
||||
ctx.eval(core::OpCodes::Cmp, [condition, zero]);
|
||||
RuneControl::ExploreFalse
|
||||
}
|
||||
_ => panic!("Incompatible command"),
|
||||
let cmd = self.cmd_q.pop().ok_or(ExplorerError::EmptyCommandQueue)?;
|
||||
|
||||
match cmd {
|
||||
Command::FollowTrue => {
|
||||
let one = ctx.define_const(1, 64);
|
||||
ctx.eval(core::OpCodes::Cmp, [condition, one]);
|
||||
Ok(RuneControl::ExploreTrue)
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
Command::FollowFalse => {
|
||||
let zero = ctx.define_const(0, 64);
|
||||
ctx.eval(core::OpCodes::Cmp, [condition, zero]);
|
||||
Ok(RuneControl::ExploreFalse)
|
||||
}
|
||||
_ => Err(ExplorerError::IncompatibleCommand),
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
-1
@@ -1,5 +1,7 @@
|
||||
//! Defines traits and structs that perform the actual symbolic emulation.
|
||||
|
||||
use crate::explorer::ExplorerError;
|
||||
|
||||
pub mod breakpt;
|
||||
pub mod hook;
|
||||
pub mod rune;
|
||||
@@ -7,7 +9,31 @@ pub mod rune;
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum EngineError {
|
||||
Undefined,
|
||||
InCorrectOperand,
|
||||
IncorrectOperand,
|
||||
Explorer(ExplorerError),
|
||||
}
|
||||
|
||||
impl EngineError {
|
||||
/// Gets the string representation of the error.
|
||||
pub const fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Undefined => "engine: undefined",
|
||||
Self::IncorrectOperand => "engine: incorrect operand",
|
||||
Self::Explorer(err) => err.as_str(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExplorerError> for EngineError {
|
||||
fn from(err: ExplorerError) -> Self {
|
||||
Self::Explorer(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for EngineError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
pub type EngineResult<T> = Result<T, EngineError>;
|
||||
|
||||
@@ -136,12 +136,14 @@ where
|
||||
}
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(EngineError::InCorrectOperand)
|
||||
Err(EngineError::IncorrectOperand)
|
||||
};
|
||||
return res;
|
||||
}
|
||||
Token::EIf => {
|
||||
*control = self.explorer.register_branch(&mut self.ctx, l_op.unwrap());
|
||||
*control = self
|
||||
.explorer
|
||||
.register_branch(&mut self.ctx, l_op.unwrap())?;
|
||||
return Ok(None);
|
||||
}
|
||||
Token::EPoke(size) => {
|
||||
|
||||
@@ -9,6 +9,10 @@ pub mod dfs;
|
||||
pub mod directed;
|
||||
pub mod interactive;
|
||||
|
||||
mod error;
|
||||
pub use error::{ExplorerError, ExplorerResult};
|
||||
|
||||
/// Represents a collection of methods for exploring an instruction path.
|
||||
pub trait PathExplorer {
|
||||
type C: Clone + Debug;
|
||||
type Ctx: Context;
|
||||
@@ -21,5 +25,5 @@ pub trait PathExplorer {
|
||||
&mut self,
|
||||
_: &mut Self::Ctx,
|
||||
_: <Self::Ctx as RegisterRead>::VarRef,
|
||||
) -> Self::C;
|
||||
) -> ExplorerResult<Self::C>;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
//! `PathExplorer` that works by exploring the CFG in Breadth First Order.
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use super::PathExplorer;
|
||||
use super::{ExplorerResult, PathExplorer};
|
||||
use crate::context::{Context, RegisterRead};
|
||||
use crate::engine::rune::RuneControl;
|
||||
|
||||
@@ -74,7 +74,7 @@ where
|
||||
&mut self,
|
||||
ctx: &mut Self::Ctx,
|
||||
_condition: <Self::Ctx as RegisterRead>::VarRef,
|
||||
) -> RuneControl {
|
||||
) -> ExplorerResult<RuneControl> {
|
||||
// When rune encounters a conditional branch instruction, it needs to decide which state to
|
||||
// explore next. To resolve this, it makes a call to the path explorer which decides on the
|
||||
// path to be explored next. Path explorer saves the current context information in order
|
||||
@@ -88,6 +88,6 @@ where
|
||||
|
||||
// Switch to a new path in the BFS Queue and pre-empt the current instruction, forcing run
|
||||
// to load a new job from the queue.
|
||||
RuneControl::TerminatePath
|
||||
Ok(RuneControl::TerminatePath)
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ use std::collections::VecDeque;
|
||||
|
||||
use libsmt::theories::core;
|
||||
|
||||
use super::PathExplorer;
|
||||
use super::{ExplorerResult, PathExplorer};
|
||||
use crate::context::rune_ctx::RuneContext;
|
||||
use crate::context::{Context, Evaluate, RegisterRead};
|
||||
use crate::engine::rune::RuneControl;
|
||||
@@ -73,7 +73,7 @@ impl PathExplorer for DFSExplorer<RuneContext<QWordMemory, RuneRegFile>> {
|
||||
&mut self,
|
||||
ctx: &mut Self::Ctx,
|
||||
condition: <Self::Ctx as RegisterRead>::VarRef,
|
||||
) -> RuneControl {
|
||||
) -> ExplorerResult<RuneControl> {
|
||||
// When a new branch is encountered, push the false branch into the queue and
|
||||
// explore the
|
||||
// true branch. Note that this choice is arbitrary and we could have as well
|
||||
@@ -90,6 +90,6 @@ impl PathExplorer for DFSExplorer<RuneContext<QWordMemory, RuneRegFile>> {
|
||||
let one = ctx.define_const(1, 1);
|
||||
ctx.eval(core::OpCodes::Cmp, [condition, one]);
|
||||
}
|
||||
RuneControl::ExploreTrue
|
||||
Ok(RuneControl::ExploreTrue)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
//! `DirectedExplorer`, an implementation of a `PathExplorer` which allows directed symbolic
|
||||
//! execution
|
||||
|
||||
use super::PathExplorer;
|
||||
use super::{ExplorerError, ExplorerResult, PathExplorer};
|
||||
use crate::engine::rune::RuneControl;
|
||||
|
||||
use crate::context::rune_ctx::RuneContext;
|
||||
@@ -75,25 +75,24 @@ impl PathExplorer for DirectedExplorer {
|
||||
&mut self,
|
||||
ctx: &mut Self::Ctx,
|
||||
condition: <Self::Ctx as RegisterRead>::VarRef,
|
||||
) -> RuneControl {
|
||||
// println!("{:#x}", ctx.ip());
|
||||
if self.d_map.contains_key(&ctx.ip()) {
|
||||
let direction = self.d_map.get(&ctx.ip()).unwrap();
|
||||
match *direction {
|
||||
BranchType::True => {
|
||||
let one = ctx.define_const(1, 64);
|
||||
ctx.eval(core::OpCodes::Cmp, [condition, one]);
|
||||
RuneControl::ExploreTrue
|
||||
}
|
||||
BranchType::False => {
|
||||
let zero = ctx.define_const(0, 64);
|
||||
ctx.eval(core::OpCodes::Cmp, [condition, zero]);
|
||||
RuneControl::ExploreFalse
|
||||
}
|
||||
_ => panic!("Invalid branch type found!"),
|
||||
) -> ExplorerResult<RuneControl> {
|
||||
let direction = self
|
||||
.d_map
|
||||
.get(&ctx.ip())
|
||||
.ok_or(ExplorerError::UnknownBranch)?;
|
||||
|
||||
match *direction {
|
||||
BranchType::True => {
|
||||
let one = ctx.define_const(1, 64);
|
||||
ctx.eval(core::OpCodes::Cmp, [condition, one]);
|
||||
Ok(RuneControl::ExploreTrue)
|
||||
}
|
||||
} else {
|
||||
panic!("Do not know which branch to take. Set a default!");
|
||||
BranchType::False => {
|
||||
let zero = ctx.define_const(0, 64);
|
||||
ctx.eval(core::OpCodes::Cmp, [condition, zero]);
|
||||
Ok(RuneControl::ExploreFalse)
|
||||
}
|
||||
_ => Err(ExplorerError::InvalidBranch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/// Represents a convenience alias for the Rune Explorer [Result](std::result::Result) type.
|
||||
pub type ExplorerResult<T> = std::result::Result<T, ExplorerError>;
|
||||
|
||||
/// Represents error variants for the Rune Explorer.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum ExplorerError {
|
||||
EmptyCommandQueue,
|
||||
IncompatibleCommand,
|
||||
InvalidBranch,
|
||||
UnknownBranch,
|
||||
}
|
||||
|
||||
impl ExplorerError {
|
||||
/// Gets the string representation of the error.
|
||||
pub const fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::EmptyCommandQueue => "explorer: Command queue is empty",
|
||||
Self::IncompatibleCommand => "explorer: Incompatible command",
|
||||
Self::InvalidBranch => "explorer: Invalid branch type found",
|
||||
Self::UnknownBranch => "explorer: Do not know which branch to take. Set a default",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ExplorerError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ExplorerError {}
|
||||
Reference in new issue
Block a user