capture_dumps/
capture-dumps.rs1use std::{
2 fs,
3 io::{self, prelude::*},
4 path::Path,
5 process::{ChildStdin, ChildStdout, Command, Stdio},
6};
7
8fn dump_process_to_bytearray(pid: u32, output_dir: &Path, output_name: &Path) -> io::Result<u64> {
9 let output = Command::new("gcore")
10 .args(["-a", &pid.to_string()])
11 .output()?;
12
13 if !output.status.success() {
14 return io::Result::Err(io::Error::other(format!(
15 "Failed to dump process: {output:?}"
16 )));
17 }
18
19 let core_path = format!("core.{pid}");
20 let output_path = output_dir.join(output_name);
21 let len = fs::copy(&core_path, output_path)?;
22 fs::remove_file(&core_path)?;
23 Ok(len)
24}
25
26fn wait_dump_and_continue(
27 stdin: &mut ChildStdin,
28 stdout: &mut ChildStdout,
29 id: u32,
30 base_dir: &Path,
31 name: &Path,
32) -> Result<(), io::Error> {
33 loop {
37 let mut buf = [0u8; 1024];
38 let read = stdout.read(&mut buf).unwrap();
39
40 if read == 0 {
41 panic!("Process exited unexpectedly");
42 }
43
44 let buf_str = std::str::from_utf8(&buf[..read]).unwrap();
45 if buf_str.contains("Waiting for dump...") {
46 break;
47 }
48 }
49 let dump_size = dump_process_to_bytearray(id, &base_dir.join("output"), name)?;
50 println!("Got memory dump of file size: {dump_size}");
51
52 stdin.write_all(b".")?;
53 stdin.flush()?;
54
55 Ok(())
56}
57
58fn main() -> io::Result<()> {
59 let args: Vec<String> = std::env::args().collect();
60 if args.len() < 3 {
61 println!("Usage: ./capture_dumps <binary_path> <base_dir>");
62 std::process::exit(1);
63 }
64
65 let binary_path = &args[1];
66 let base_dir: &Path = args[2].as_ref();
67
68 let mut proc = Command::new(binary_path)
69 .arg(base_dir)
70 .stdout(Stdio::piped())
71 .stdin(Stdio::piped())
72 .spawn()?;
73 let id = proc.id();
74 println!("Started memory testing process with PID: {id}");
75
76 let stdin = proc.stdin.as_mut().expect("Valid stdin");
77 let stdout = proc.stdout.as_mut().expect("Valid stdin");
78
79 wait_dump_and_continue(stdin, stdout, id, base_dir, "initial_dump.bin".as_ref())?;
80 wait_dump_and_continue(stdin, stdout, id, base_dir, "final_dump.bin".as_ref())?;
81
82 let output = proc.wait()?;
84 println!("Return code: {output}");
85
86 std::process::exit(output.code().unwrap_or(1));
87}