analyze_dumps/
analyze-dumps.rs1use 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}