use std::collections::BTreeMap;
use initial::initial_blocks;
pub(crate) use reachable::get_reachable_nodes;
use resolver::resolve_dynamic_jumps;
mod initial;
mod reachable;
mod resolver;
mod state;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct Block {
pub id: usize,
pub start: usize,
pub end: usize,
#[cfg_attr(feature = "serde", serde(flatten))]
pub btype: BlockType,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct DynamicJump {
pub path: Vec<usize>,
pub to: Option<usize>,
}
#[derive(Debug, Clone)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize),
serde(tag = "type", content = "data")
)]
pub enum BlockType {
Terminate {
success: bool,
},
Jump {
to: usize,
},
Jumpi {
true_to: usize,
false_to: usize,
},
DynamicJump {
to: Vec<DynamicJump>,
},
DynamicJumpi {
true_to: Vec<DynamicJump>,
false_to: usize,
},
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct ControlFlowGraph {
#[cfg_attr(feature = "serde", serde(serialize_with = "crate::serialize::blocks"))]
pub blocks: BTreeMap<usize, Block>,
}
pub(crate) fn basic_blocks(code: &[u8]) -> BTreeMap<usize, Block> {
initial_blocks(code)
}
pub(crate) fn control_flow_graph(
code: &[u8],
mut blocks: BTreeMap<usize, Block>,
) -> ControlFlowGraph {
blocks = resolve_dynamic_jumps(code, blocks);
let reachable = get_reachable_nodes(&blocks, 0, None);
blocks.retain(|start, _| reachable.contains(start));
ControlFlowGraph { blocks }
}