Unverified Commit c11c693e by Enkelmann Committed by GitHub

efficient computation of call sequences (#403)

parent e8c6e3a7
...@@ -8,16 +8,16 @@ on: ...@@ -8,16 +8,16 @@ on:
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
GHIDRA_RELEASE_TAG: Ghidra_10.2.2_build GHIDRA_RELEASE_TAG: Ghidra_10.2.3_build
GHIDRA_VERSION: ghidra_10.2.2_PUBLIC_20221115 GHIDRA_VERSION: ghidra_10.2.3_PUBLIC_20230208
jobs: jobs:
acceptance-tests: acceptance-tests:
runs-on: ubuntu-18.04 runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Build and run docker image for cross compiling - name: Build and run docker image for cross compiling
run: | run: |
cd test/artificial_samples cd test/artificial_samples
...@@ -50,7 +50,7 @@ jobs: ...@@ -50,7 +50,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Build the docker image - name: Build the docker image
run: docker build -t cwe_checker . run: docker build -t cwe_checker .
- name: Check functionality of the image - name: Check functionality of the image
......
...@@ -13,7 +13,7 @@ jobs: ...@@ -13,7 +13,7 @@ jobs:
name: Rustfmt name: Rustfmt
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
...@@ -29,7 +29,7 @@ jobs: ...@@ -29,7 +29,7 @@ jobs:
name: Clippy name: Clippy
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
...@@ -45,7 +45,7 @@ jobs: ...@@ -45,7 +45,7 @@ jobs:
name: Rustdoc name: Rustdoc
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
......
...@@ -14,7 +14,7 @@ jobs: ...@@ -14,7 +14,7 @@ jobs:
id: tagName id: tagName
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v2
......
...@@ -10,7 +10,7 @@ jobs: ...@@ -10,7 +10,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v2
......
...@@ -12,7 +12,7 @@ jobs: ...@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
......
...@@ -50,38 +50,59 @@ pub fn find_call_sequences_to_target( ...@@ -50,38 +50,59 @@ pub fn find_call_sequences_to_target(
.node_indices() .node_indices()
.find(|node| callgraph[*node] == *source_sub_tid) .find(|node| callgraph[*node] == *source_sub_tid)
.unwrap_or_else(|| panic!("Function TID not found in call graph.")); .unwrap_or_else(|| panic!("Function TID not found in call graph."));
find_call_sequences_from_node_to_target(callgraph, source_node, target_sub_tid, BTreeSet::new()) let target_node = callgraph
.node_indices()
.find(|node| callgraph[*node] == *target_sub_tid)
.unwrap_or_else(|| panic!("Function TID not found in call graph."));
find_call_sequences_from_node_to_target(callgraph, source_node, target_node)
} }
/// Recursively collects all call TIDs of call sequences that start in the function given by the `source_node` in the call graph /// Collect all call TIDs of calls contained in path in the call graph starting at the source node and ending at the target node.
/// and end in the function given by the `target_sub_tid`.
fn find_call_sequences_from_node_to_target( fn find_call_sequences_from_node_to_target(
callgraph: &CallGraph, callgraph: &CallGraph,
source_node: NodeIndex, source_node: NodeIndex,
target_sub_tid: &Tid, target_node: NodeIndex,
visited_nodes: BTreeSet<NodeIndex>,
) -> BTreeSet<Tid> { ) -> BTreeSet<Tid> {
let mut call_tids = BTreeSet::new(); use petgraph::Direction;
for edge in callgraph.edges_directed(source_node, petgraph::Direction::Outgoing) { // Find all edges on paths starting at source_node using depth-first-search
let (_, target_node) = callgraph.edge_endpoints(edge.id()).unwrap(); let mut nodes_reachable_from_source = BTreeSet::new();
if callgraph[target_node] == *target_sub_tid { let mut edges_reachable_from_source = BTreeSet::new();
call_tids.insert(edge.weight().tid.clone()); let mut stack = vec![source_node];
} else if !visited_nodes.contains(&target_node) { while let Some(node) = stack.pop() {
let mut recursive_visited = visited_nodes.clone(); if nodes_reachable_from_source.insert(node) {
recursive_visited.insert(target_node); for neighbor in callgraph.neighbors_directed(node, Direction::Outgoing) {
let recursive_tids = find_call_sequences_from_node_to_target( stack.push(neighbor);
callgraph, }
target_node, for edge in callgraph.edges_directed(node, Direction::Outgoing) {
target_sub_tid, edges_reachable_from_source.insert(edge.id());
recursive_visited,
);
if !recursive_tids.is_empty() {
call_tids.extend(recursive_tids.into_iter());
call_tids.insert(edge.weight().tid.clone());
} }
} }
} }
call_tids // Find all edges on paths leading to target_node using depth-first-search
let mut nodes_on_paths_to_target = BTreeSet::new();
let mut edges_on_paths_to_target = BTreeSet::new();
let mut stack = vec![target_node];
while let Some(node) = stack.pop() {
if nodes_on_paths_to_target.insert(node) {
for neighbor in callgraph.neighbors_directed(node, petgraph::Direction::Incoming) {
stack.push(neighbor);
}
for edge in callgraph.edges_directed(node, Direction::Incoming) {
edges_on_paths_to_target.insert(edge.id());
}
}
}
// Compute the intersection of both edge sets and return the corresponding call TIDs
edges_reachable_from_source
.iter()
.filter_map(|edge| {
if edges_on_paths_to_target.contains(edge) {
Some(callgraph[*edge].tid.clone())
} else {
None
}
})
.collect()
} }
#[cfg(test)] #[cfg(test)]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment