1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
use super::{Blk, ExternSymbol, Sub};
use crate::prelude::*;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt;
/// The `Program` structure represents a disassembled binary.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct Program {
/// The known functions contained in the binary
pub subs: BTreeMap<Tid, Term<Sub>>,
/// Extern symbols linked to the binary by the linker.
pub extern_symbols: BTreeMap<Tid, ExternSymbol>,
/// Entry points into to binary,
/// i.e. the term identifiers of functions that may be called from outside of the binary.
pub entry_points: BTreeSet<Tid>,
/// An offset that has been added to all addresses in the program compared to the addresses
/// as specified in the binary file.
///
/// In certain cases, e.g. if the binary specifies a segment to be loaded at address 0,
/// the Ghidra backend may shift the whole binary image by a constant value in memory.
/// Thus addresses as specified by the binary and addresses as reported by Ghidra may differ by a constant offset,
/// which is stored in this value.
pub address_base_offset: u64,
}
impl Program {
/// Find a block term by its term identifier.
/// WARNING: The function simply iterates through all blocks,
/// i.e. it is very inefficient for large projects!
pub fn find_block(&self, tid: &Tid) -> Option<&Term<Blk>> {
self.subs
.iter()
.flat_map(|(_, sub)| sub.term.blocks.iter())
.find(|block| block.tid == *tid)
}
/// Find the sub containing a specific jump instruction (including call instructions).
/// WARNING: The function simply iterates though all blocks,
/// i.e. it is very inefficient for large projects!
pub fn find_sub_containing_jump(&self, jmp_tid: &Tid) -> Option<Tid> {
for sub in self.subs.values() {
for blk in &sub.term.blocks {
for jmp in &blk.term.jmps {
if &jmp.tid == jmp_tid {
return Some(sub.tid.clone());
}
}
}
}
None
}
}
impl fmt::Display for Program {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for Term { tid, term: sub } in self.subs.values() {
writeln!(
f,
"SUB [{}] name:{} entry:{}",
tid,
sub.name,
if self.entry_points.contains(tid) {
"yes"
} else {
"no"
}
)?;
for Term { tid, term: blk } in sub.blocks.iter() {
writeln!(f, " BLK [{}]", tid)?;
for Term { tid, term: def } in blk.defs.iter() {
writeln!(f, " DEF [{}] {}", tid, def)?;
}
for Term { tid, term: jmp } in blk.jmps.iter() {
writeln!(f, " JMP [{}] {}", tid, jmp)?;
}
}
}
for ext in self.extern_symbols.values() {
writeln!(f, "EXT {}", ext)?;
}
Ok(())
}
}