use crate::memory::MemoryPermissions;
pub mod aarch64;
mod block_translation_result;
pub mod mips;
mod options;
pub mod ppc;
pub mod x86;
use crate::il;
use crate::il::*;
use crate::Error;
pub use block_translation_result::BlockTranslationResult;
use falcon_capstone::capstone;
pub use options::{ManualEdge, Options, OptionsBuilder};
use std::collections::{BTreeMap, VecDeque};
pub(crate) 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(crate) fn unhandled_intrinsic(
control_flow_graph: &mut il::ControlFlowGraph,
instruction: &capstone::Instr,
) -> Result<(), Error> {
let block_index = {
let block = control_flow_graph.new_block()?;
block.intrinsic(il::Intrinsic::new(
instruction.mnemonic.clone(),
format!("{} {}", instruction.mnemonic, instruction.op_str),
Vec::new(),
None,
None,
instruction.bytes.get(0..4).unwrap().to_vec(),
));
block.index()
};
control_flow_graph.set_entry(block_index)?;
control_flow_graph.set_exit(block_index)?;
Ok(())
}
pub trait Translator {
fn translate_block(
&self,
bytes: &[u8],
address: u64,
options: &Options,
) -> Result<BlockTranslationResult, Error>;
fn translate_function(
&self,
memory: &dyn TranslationMemory,
function_address: u64,
) -> Result<Function, Error> {
self.translate_function_extended(memory, function_address, &Options::default())
}
fn translate_function_extended(
&self,
memory: &dyn TranslationMemory,
function_address: u64,
options: &Options,
) -> Result<Function, Error> {
let mut translation_queue: VecDeque<u64> = VecDeque::new();
let mut translation_results: BTreeMap<u64, BlockTranslationResult> = BTreeMap::new();
translation_queue.push_front(function_address);
options.manual_edges().iter().for_each(|manual_edge| {
translation_queue.push_back(manual_edge.head_address());
translation_queue.push_back(manual_edge.tail_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);
if block_bytes.is_empty() {
let mut control_flow_graph = ControlFlowGraph::new();
let block_index = control_flow_graph.new_block()?.index();
control_flow_graph.set_entry(block_index)?;
control_flow_graph.set_exit(block_index)?;
translation_results.insert(
block_address,
BlockTranslationResult::new(
vec![(block_address, control_flow_graph)],
block_address,
0,
Vec::new(),
),
);
continue;
}
let block_translation_result =
self.translate_block(&block_bytes, block_address, options)?;
for successor in block_translation_result.successors().iter() {
if !translation_queue.contains(&successor.0) {
translation_queue.push_back(successor.0);
}
}
translation_results.insert(block_address, block_translation_result);
}
let mut instruction_indices: BTreeMap<u64, (usize, usize)> = BTreeMap::new();
let mut block_indices: BTreeMap<u64, (usize, usize)> = BTreeMap::new();
let mut control_flow_graph = ControlFlowGraph::new();
for result in &translation_results {
let block_translation_result = result.1;
let mut block_entry = 0;
let mut block_exit = 0;
let mut previous_exit = None;
for &(address, ref instruction_graph) in block_translation_result.instructions().iter()
{
let (entry, exit) = if let std::collections::btree_map::Entry::Vacant(e) =
instruction_indices.entry(address)
{
let (entry, exit) = control_flow_graph.insert(instruction_graph)?;
e.insert((entry, exit));
(entry, exit)
} else {
instruction_indices[&address]
};
if let Some(previous_exit) = previous_exit {
if control_flow_graph.edge(previous_exit, entry).is_err() {
control_flow_graph.unconditional_edge(previous_exit, entry)?;
}
}
else {
block_entry = entry;
}
block_exit = exit;
previous_exit = Some(exit);
}
block_indices.insert(*result.0, (block_entry, block_exit));
}
for manual_edge in options.manual_edges() {
let (_, edge_head) = block_indices[&manual_edge.head_address()];
let (edge_tail, _) = block_indices[&manual_edge.tail_address()];
if control_flow_graph.edge(edge_head, edge_tail).is_ok() {
continue;
}
if let Some(condition) = manual_edge.condition() {
control_flow_graph.conditional_edge(edge_head, edge_tail, condition.clone())?;
} else {
control_flow_graph.unconditional_edge(edge_head, edge_tail)?;
}
}
for (address, block_translation_result) in translation_results {
let (_, block_exit) = block_indices[&address];
for (successor_address, successor_condition) in
block_translation_result.successors().iter()
{
let (block_entry, _) = block_indices[successor_address];
if control_flow_graph.edge(block_exit, block_entry).is_ok() {
continue;
}
match successor_condition {
Some(ref condition) => control_flow_graph.conditional_edge(
block_exit,
block_entry,
condition.clone(),
)?,
None => control_flow_graph.unconditional_edge(block_exit, block_entry)?,
}
}
}
control_flow_graph.set_entry(block_indices[&function_address].0)?;
control_flow_graph.merge()?;
Ok(Function::new(function_address, control_flow_graph))
}
}