Skip to main content

gcrecomp_core/recompiler/analysis/
inter_procedural.rs

1// Inter-Procedural Analysis
2use std::collections::{HashMap, HashSet};
3
4#[derive(Debug, Clone)]
5pub struct CallGraph {
6    pub nodes: Vec<FunctionNode>,
7    pub edges: Vec<CallEdge>,
8}
9
10#[derive(Debug, Clone)]
11pub struct FunctionNode {
12    pub address: u32,
13    pub name: String,
14    pub is_entry_point: bool,
15    pub callers: Vec<usize>,
16    pub callees: Vec<usize>,
17}
18
19#[derive(Debug, Clone)]
20pub struct CallEdge {
21    pub caller: usize,
22    pub callee: usize,
23    pub call_sites: Vec<u32>,
24}
25
26pub struct InterProceduralAnalyzer;
27
28impl InterProceduralAnalyzer {
29    pub fn build_call_graph(functions: &[crate::recompiler::ghidra::FunctionInfo]) -> CallGraph {
30        let mut nodes = Vec::new();
31        let mut edges = Vec::new();
32        let mut address_to_index: HashMap<u32, usize> = HashMap::new();
33        
34        // Create nodes for all functions
35        for (idx, func) in functions.iter().enumerate() {
36            address_to_index.insert(func.address, idx);
37            nodes.push(FunctionNode {
38                address: func.address,
39                name: func.name.clone(),
40                is_entry_point: idx == 0, // First function is typically entry point
41                callers: vec![],
42                callees: vec![],
43            });
44        }
45        
46        // Build edges from function calls
47        // This would need to analyze instructions to find call sites
48        // For now, placeholder
49        
50        CallGraph { nodes, edges }
51    }
52    
53    pub fn find_unreachable_functions(call_graph: &CallGraph) -> Vec<usize> {
54        let mut reachable = HashSet::new();
55        let mut queue = Vec::new();
56        
57        // Start from entry points
58        for (idx, node) in call_graph.nodes.iter().enumerate() {
59            if node.is_entry_point {
60                queue.push(idx);
61                reachable.insert(idx);
62            }
63        }
64        
65        // BFS to find all reachable functions
66        while let Some(node_idx) = queue.pop() {
67            for &callee in &call_graph.nodes[node_idx].callees {
68                if !reachable.contains(&callee) {
69                    reachable.insert(callee);
70                    queue.push(callee);
71                }
72            }
73        }
74        
75        // Return unreachable function indices
76        (0..call_graph.nodes.len())
77            .filter(|idx| !reachable.contains(idx))
78            .collect()
79    }
80}
81