analyze_dumps/
analyze-dumps.rs

1use std::{env, io, path::Path, process};
2
3use memory_testing::*;
4
5fn find_subarrays(needle: &[u8], haystack: &[u8]) -> Vec<usize> {
6    let needle_len = needle.len();
7    let haystack_len = haystack.len();
8    let mut subarrays = vec![];
9
10    if needle_len == 0 || haystack_len == 0 || needle_len > haystack_len {
11        return vec![];
12    }
13
14    for i in 0..=(haystack_len - needle_len) {
15        if &haystack[i..i + needle_len] == needle {
16            subarrays.push(i);
17        }
18    }
19
20    subarrays
21}
22
23const OK: &str = "✅";
24const FAIL: &str = "❌";
25
26fn comma_sep(nums: &[usize]) -> String {
27    nums.iter()
28        .map(ToString::to_string)
29        .collect::<Vec<String>>()
30        .join(", ")
31}
32
33fn main() -> io::Result<()> {
34    let args: Vec<String> = env::args().collect();
35    if args.len() < 2 {
36        println!("Usage: ./analyze-dumps <base_dir>");
37        process::exit(1);
38    }
39    let base_dir: &Path = args[1].as_ref();
40
41    println!("Memory testing script started");
42
43    let initial_core = std::fs::read(base_dir.join("output/initial_dump.bin"))?;
44    let final_core = std::fs::read(base_dir.join("output/final_dump.bin"))?;
45
46    let mut error = false;
47    let mut table = comfy_table::Table::new();
48    table.set_header(vec!["Name", "Initial", "Final", "OK"]);
49
50    let cases = memory_testing::load_cases(base_dir);
51
52    let test_string: Vec<u8> = TEST_STRING.as_bytes().to_vec();
53    let test_initial_pos = find_subarrays(&test_string, &initial_core);
54
55    if test_initial_pos.is_empty() {
56        println!("ERROR: Test string not found in initial core dump, is the dump valid?");
57        error = true;
58    }
59
60    for (idx, case) in cases.cases.iter().enumerate() {
61        for lookup in &case.memory_lookups {
62            let value = match &lookup.value {
63                MemoryLookupValue::String { string } => string.as_bytes().to_vec(),
64                MemoryLookupValue::Binary { hex } => hex::decode(hex).unwrap(),
65            };
66
67            let initial_pos = find_subarrays(&value, &initial_core);
68            let final_pos = find_subarrays(&value, &final_core);
69
70            let name = format!("{idx}: {} / {}", case.name, lookup.name);
71            let ok_cond = final_pos.len() <= lookup.allowed_count.unwrap_or(0);
72
73            table.add_row([
74                name.as_str(),
75                &comma_sep(&initial_pos),
76                &comma_sep(&final_pos),
77                if ok_cond { OK } else { FAIL },
78            ]);
79
80            if !ok_cond {
81                error = true;
82            }
83        }
84    }
85
86    println!("{table}");
87
88    process::exit(if error { 1 } else { 0 });
89}