-
Notifications
You must be signed in to change notification settings - Fork 123
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
lib/analysis/graph: extend intraCFG and add CG
- Loading branch information
Valentin Obst
committed
Sep 13, 2024
1 parent
1bfbc0a
commit 653602c
Showing
7 changed files
with
707 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
//! Some simple graph algorithms. | ||
use std::collections::hash_map::{Entry, HashMap}; | ||
|
||
use petgraph::prelude::*; | ||
use petgraph::unionfind::UnionFind; | ||
use petgraph::visit::{IntoEdgeReferences, NodeCompactIndexable}; | ||
|
||
/// Returns the components of the graph `g`. | ||
pub fn components<G>(g: &G) -> Vec<Vec<G::NodeId>> | ||
where | ||
G: IntoEdgeReferences + NodeCompactIndexable, | ||
{ | ||
let mut vertex_sets = UnionFind::new(g.node_bound()); | ||
for e in g.edge_references() { | ||
let (h, t) = (e.target(), e.source()); | ||
vertex_sets.union(g.to_index(h), g.to_index(t)); | ||
} | ||
let representatives = vertex_sets.into_labeling(); | ||
let mut sets: HashMap<usize, Vec<G::NodeId>> = HashMap::new(); | ||
for (index, repr) in representatives.iter().enumerate() { | ||
match sets.entry(*repr) { | ||
Entry::Vacant(e) => { | ||
e.insert(vec![g.from_index(index)]); | ||
} | ||
Entry::Occupied(e) => e.into_mut().push(g.from_index(index)), | ||
} | ||
} | ||
|
||
sets.into_values().collect() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
//! Call graphs. | ||
use crate::analysis::graph::intraprocedural_cfg::IntraproceduralCfg; | ||
use crate::intermediate_representation::{Jmp, Program, Sub, Term, Tid}; | ||
|
||
use std::collections::HashMap; | ||
|
||
use petgraph::graph::{DiGraph, NodeIndex}; | ||
use petgraph::visit::EdgeRef; | ||
use petgraph::Direction; | ||
|
||
/// Whole-program call graph. | ||
pub struct CallGraph<'a> { | ||
graph: DiGraph<CgNode<'a>, CgEdge<'a>>, | ||
fn_tid_to_idx_map: HashMap<&'a Tid, NodeIndex>, | ||
} | ||
|
||
impl<'a> CallGraph<'a> { | ||
/// Constructs the call graph of the program `p`. | ||
pub fn new(p: &'a Program) -> Self { | ||
CallGraphBuilder::new(p).build() | ||
} | ||
|
||
/// Returns an iterator over all callers of the function `f`. | ||
pub fn callers<'b>( | ||
&'b self, | ||
f: &Tid, | ||
) -> impl Iterator<Item = (&'b CgNode<'a>, &'b CgEdge<'a>)> + 'b { | ||
let fn_idx = self.fn_tid_to_idx_map.get(f).unwrap(); | ||
|
||
self.graph | ||
.edges_directed(*fn_idx, Direction::Incoming) | ||
.map(|e_ref| { | ||
let source = e_ref.source(); | ||
(&self.graph[source], e_ref.weight()) | ||
}) | ||
} | ||
|
||
/// Returns an iterator over all callees of the function `f`. | ||
pub fn callees<'b>( | ||
&'b self, | ||
f: &Tid, | ||
) -> impl Iterator<Item = (&'b CgNode<'a>, &'b CgEdge<'a>)> + 'b { | ||
let fn_idx = self.fn_tid_to_idx_map.get(f).unwrap(); | ||
|
||
self.graph | ||
.edges_directed(*fn_idx, Direction::Outgoing) | ||
.map(|e_ref| { | ||
let target = e_ref.target(); | ||
(&self.graph[target], e_ref.weight()) | ||
}) | ||
} | ||
} | ||
|
||
/// Call graph node. | ||
/// | ||
/// Nodes in a call graph correspond to internal or external (aka. imported) | ||
/// functions. Each function has exactly one node. | ||
pub enum CgNode<'a> { | ||
Function(&'a Term<Sub>, Box<IntraproceduralCfg<'a>>), | ||
ExtFunction, | ||
} | ||
|
||
impl<'a> CgNode<'a> { | ||
/// Returns true iff this node corresponds to an external function. | ||
pub fn is_external(&self) -> bool { | ||
matches!(self, CgNode::ExtFunction) | ||
} | ||
} | ||
|
||
/// Call graph edge. | ||
/// | ||
/// If function `f` may, directly or indirectly, call function `g` the call | ||
/// graph has exactly one edge `f -> g`. Thus, callers can be determined by | ||
/// iterating incoming edges, and callees by iterating outgoing edges. | ||
/// Furthermore, edges include all potential call sites in the caller. | ||
pub struct CgEdge<'a> { | ||
direct_call_sites: Vec<CallSite<'a>>, | ||
indirect_call_sites: Vec<CallSite<'a>>, | ||
} | ||
|
||
impl<'a> CgEdge<'a> { | ||
/// Returns an iterator over the direct call sites of this edge. | ||
pub fn direct_call_sites<'b>(&'b self) -> impl Iterator<Item = &'b CallSite<'a>> + 'b { | ||
self.direct_call_sites.iter() | ||
} | ||
|
||
/// Returns an iterator over the indirect call sites of this edge. | ||
pub fn indirect_call_sites<'b>(&'b self) -> impl Iterator<Item = &'b CallSite<'a>> + 'b { | ||
self.indirect_call_sites.iter() | ||
} | ||
} | ||
|
||
/// Call site. | ||
pub struct CallSite<'a> { | ||
indirect: bool, | ||
insn: &'a Term<Jmp>, | ||
} | ||
|
||
impl<'a> CallSite<'a> { | ||
/// Returns true iff this in an indirect call. | ||
pub fn is_indirect(&self) -> bool { | ||
self.indirect | ||
} | ||
|
||
/// Returns the call instruction. | ||
pub fn insn(&self) -> &'a Term<Jmp> { | ||
self.insn | ||
} | ||
} | ||
|
||
struct CallGraphBuilder<'a> { | ||
_pd: core::marker::PhantomData<&'a u32>, | ||
} | ||
|
||
impl<'a> CallGraphBuilder<'a> { | ||
fn new(_p: &'a Program) -> Self { | ||
todo!() | ||
} | ||
|
||
fn build(self) -> CallGraph<'a> { | ||
todo!() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.