use crate::architecture::Architecture;
use crate::executor::eval;
use crate::il;
use crate::memory;
use crate::translator::Options;
use crate::Error;
use std::any::Any;
use std::collections::{HashMap, HashSet};
use std::fmt;
mod elf;
mod json;
mod pe;
mod symbol;
pub use self::elf::*;
pub use self::json::*;
pub use self::pe::*;
pub use self::symbol::Symbol;
#[derive(Clone, Debug, PartialEq)]
pub struct FunctionEntry {
address: u64,
name: Option<String>,
}
impl FunctionEntry {
pub fn new(address: u64, name: Option<String>) -> FunctionEntry {
FunctionEntry { address, name }
}
pub fn address(&self) -> u64 {
self.address
}
pub fn name(&self) -> Option<&str> {
self.name.as_deref()
}
}
impl fmt::Display for FunctionEntry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.name {
Some(ref name) => write!(f, "FunctionEntry({} -> 0x{:X})", name, self.address),
None => write!(f, "FunctionEntry(0x{:X})", self.address),
}
}
}
pub trait Loader: fmt::Debug + Send + Sync {
fn memory(&self) -> Result<memory::backing::Memory, Error>;
fn function_entries(&self) -> Result<Vec<FunctionEntry>, Error>;
fn program_entry(&self) -> u64;
fn architecture(&self) -> &dyn Architecture;
fn function(&self, address: u64) -> Result<il::Function, Error> {
self.function_extended(address, &Options::default())
}
fn function_extended(&self, address: u64, options: &Options) -> Result<il::Function, Error> {
let translator = self.architecture().translator();
let memory = self.memory()?;
translator.translate_function_extended(&memory, address, options)
}
fn as_any(&self) -> &dyn Any;
fn symbols(&self) -> Vec<Symbol>;
fn symbols_map(&self) -> HashMap<u64, Symbol> {
self.symbols()
.into_iter()
.map(|symbol| (symbol.address(), symbol))
.collect()
}
fn program(&self) -> Result<il::Program, Error> {
Ok(self.program_verbose(&Options::default())?.0)
}
fn program_verbose(
&self,
options: &Options,
) -> std::result::Result<(il::Program, Vec<(FunctionEntry, Error)>), Error> {
let translator = self.architecture().translator();
let memory = self.memory()?;
let mut program = il::Program::new();
let mut translation_errors: Vec<(FunctionEntry, Error)> = Vec::new();
for function_entry in self.function_entries()? {
let address = function_entry.address();
if memory
.permissions(address)
.is_some_and(|p| p.contains(memory::MemoryPermissions::EXECUTE))
{
match translator.translate_function_extended(&memory, address, options) {
Ok(mut function) => {
function.set_name(function_entry.name().map(|n| n.to_string()));
program.add_function(function);
}
Err(e) => translation_errors.push((function_entry.clone(), e)),
};
}
}
Ok((program, translation_errors))
}
fn program_recursive(&self) -> Result<il::Program, Error> {
Ok(self.program_recursive_verbose(&Options::default())?.0)
}
fn program_recursive_verbose(
&self,
options: &Options,
) -> std::result::Result<(il::Program, Vec<(FunctionEntry, Error)>), Error> {
fn call_targets(function: &il::Function) -> Vec<u64> {
let call_targets =
function
.blocks()
.iter()
.fold(Vec::new(), |mut call_targets, block| {
block.instructions().iter().for_each(|instruction| {
if let il::Operation::Branch { ref target } = *instruction.operation() {
if let Ok(constant) = eval(target) {
call_targets.push(constant.value_u64().unwrap())
}
}
});
call_targets
});
call_targets
}
let (mut program, mut translation_errors) = self.program_verbose(options)?;
let mut processed = HashSet::new();
loop {
let function_addresses = program
.functions()
.into_iter()
.map(|function| function.address())
.collect::<Vec<u64>>();
let addresses = {
let functions = program
.functions()
.into_iter()
.filter(|function| !processed.contains(&function.address()))
.collect::<Vec<&il::Function>>();
functions.iter().for_each(|function| {
processed.insert(function.address());
});
let addresses = functions
.into_iter()
.fold(HashSet::new(), |mut targets, function| {
call_targets(function).into_iter().for_each(|target| {
targets.insert(target);
});
targets
})
.into_iter()
.filter(|address| !function_addresses.contains(address))
.collect::<Vec<u64>>();
if addresses.is_empty() {
break;
}
addresses
};
for address in addresses {
match self.function_extended(address, options) {
Ok(function) => program.add_function(function),
Err(e) => {
let function_entry = FunctionEntry::new(address, None);
translation_errors.push((function_entry, e));
}
}
}
}
Ok((program, translation_errors))
}
}