use error::*;
use il::*;
use memory::MemoryPermissions;
use std::collections::{BTreeMap, VecDeque};
use types::Endian;
pub mod x86;
pub mod mips;
const DEFAULT_TRANSLATION_BLOCK_BYTES: usize = 64;
pub trait TranslationMemory {
fn permissions(&self, address:u64) -> Option<MemoryPermissions>;
fn get_u8(&self, address: u64) -> Option<u8>;
fn get_bytes(&self, address: u64, length: usize) -> Vec<u8> {
let mut bytes = Vec::new();
for i in 0..length {
match self.permissions(address) {
Some(permissions) => if !permissions.contains(MemoryPermissions::EXECUTE) {
break;
},
None => break
}
match self.get_u8(address + i as u64) {
Some(u) => bytes.push(u),
None => break
};
}
bytes
}
}
pub struct BlockTranslationResult {
control_flow_graph: ControlFlowGraph,
address: u64,
length: usize,
successors: Vec<(u64, Option<Expression>)>
}
impl BlockTranslationResult {
pub fn new(
control_flow_graph: ControlFlowGraph,
address: u64,
length: usize,
successors: Vec<(u64, Option<Expression>)>
) -> BlockTranslationResult {
BlockTranslationResult {
control_flow_graph: control_flow_graph,
address: address,
length: length,
successors: successors
}
}
pub fn control_flow_graph(&self) -> &ControlFlowGraph {
&self.control_flow_graph
}
pub fn address(&self) -> u64 {
self.address
}
pub fn length(&self) -> usize {
self.length
}
pub fn successors(&self) -> &Vec<(u64, Option<Expression>)> {
&self.successors
}
}
pub trait Translator: {
fn translate_block(&self, bytes: &[u8], address: u64) -> Result<BlockTranslationResult>;
fn endian(&self) -> Endian;
fn translate_function(
&self,
memory: &TranslationMemory,
function_address: u64)
-> Result<Function> {
let mut translation_queue = VecDeque::new();
let mut translation_results = BTreeMap::new();
translation_queue.push_front(function_address);
while !translation_queue.is_empty() {
let block_address = translation_queue.pop_front().unwrap();
if translation_results.contains_key(&block_address) {
continue;
}
let block_bytes = memory.get_bytes(block_address, DEFAULT_TRANSLATION_BLOCK_BYTES);
let block_translation_result = self.translate_block(&block_bytes, block_address)?;
for successor in block_translation_result.successors().iter() {
translation_queue.push_back(successor.0);
}
translation_results.insert(block_address, block_translation_result);
}
let mut indices: BTreeMap<u64, (u64, u64)> = BTreeMap::new();
let mut control_flow_graph = ControlFlowGraph::new();
for result in &translation_results {
let (entry, exit) = control_flow_graph.insert(result.1.control_flow_graph())?;
indices.insert(*result.0, (entry, exit));
}
for result in translation_results {
let (_, this_exit) = indices[&result.0];
for successor in result.1.successors().iter() {
let (that_entry, _) = indices[&successor.0];
match successor.1 {
Some(ref condition) => control_flow_graph.conditional_edge(this_exit, that_entry, condition.clone())?,
None => control_flow_graph.unconditional_edge(this_exit, that_entry)?
}
}
}
control_flow_graph.set_entry(indices[&function_address].0)?;
control_flow_graph.merge()?;
Ok(Function::new(function_address, control_flow_graph))
}
}