1#![forbid(unsafe_code)]
2
3use std::io::{self, Read, Seek, SeekFrom};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum MemDumpFormat {
9 Lime,
11 Avml,
13 ElfCore,
15 WinCrashDump,
17}
18
19impl std::fmt::Display for MemDumpFormat {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 match self {
22 MemDumpFormat::Lime => write!(f, "lime"),
23 MemDumpFormat::Avml => write!(f, "avml"),
24 MemDumpFormat::ElfCore => write!(f, "elf-core"),
25 MemDumpFormat::WinCrashDump => write!(f, "win-crashdump"),
26 }
27 }
28}
29
30pub fn detect_memory_dump<R: Read + Seek>(source: &mut R) -> io::Result<Option<MemDumpFormat>> {
37 source.seek(SeekFrom::Start(0))?;
38 let mut buf = [0u8; 18];
39 let n = read_fill(source, &mut buf);
40 source.seek(SeekFrom::Start(0))?;
41
42 if n >= 4 && &buf[0..4] == b"EMiL" {
44 return Ok(Some(MemDumpFormat::Lime));
45 }
46 if n >= 4 && &buf[0..4] == b"AVML" {
48 return Ok(Some(MemDumpFormat::Avml));
49 }
50 if n >= 8 && &buf[0..8] == b"PAGEDU64" {
52 return Ok(Some(MemDumpFormat::WinCrashDump));
53 }
54 if n >= 18 && buf[0..4] == [0x7F, b'E', b'L', b'F'] {
56 let e_type = u16::from_le_bytes([buf[16], buf[17]]);
57 if e_type == 4 {
58 return Ok(Some(MemDumpFormat::ElfCore));
59 }
60 }
61 Ok(None)
62}
63
64fn read_fill<R: Read>(source: &mut R, buf: &mut [u8]) -> usize {
66 let mut total = 0;
67 while total < buf.len() {
68 match source.read(&mut buf[total..]) {
69 Ok(0) | Err(_) => break,
70 Ok(n) => total += n,
71 }
72 }
73 total
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use std::io::Cursor;
80
81 #[test]
82 fn detect_mem_lime() {
83 let mut data = vec![0u8; 64];
84 data[0..4].copy_from_slice(b"EMiL"); assert_eq!(
86 detect_memory_dump(&mut Cursor::new(data)).unwrap(),
87 Some(MemDumpFormat::Lime)
88 );
89 }
90
91 #[test]
92 fn detect_mem_avml() {
93 let mut data = vec![0u8; 64];
94 data[0..4].copy_from_slice(b"AVML");
95 assert_eq!(
96 detect_memory_dump(&mut Cursor::new(data)).unwrap(),
97 Some(MemDumpFormat::Avml)
98 );
99 }
100
101 #[test]
102 fn detect_mem_elf_core() {
103 let mut data = vec![0u8; 64];
104 data[0..4].copy_from_slice(&[0x7F, b'E', b'L', b'F']);
105 data[16..18].copy_from_slice(&4u16.to_le_bytes()); assert_eq!(
107 detect_memory_dump(&mut Cursor::new(data)).unwrap(),
108 Some(MemDumpFormat::ElfCore)
109 );
110 }
111
112 #[test]
113 fn detect_mem_elf_exec_is_not_a_dump() {
114 let mut data = vec![0u8; 64];
116 data[0..4].copy_from_slice(&[0x7F, b'E', b'L', b'F']);
117 data[16..18].copy_from_slice(&2u16.to_le_bytes()); assert_eq!(detect_memory_dump(&mut Cursor::new(data)).unwrap(), None);
119 }
120
121 #[test]
122 fn detect_mem_win_crashdump() {
123 let mut data = vec![0u8; 64];
124 data[0..8].copy_from_slice(b"PAGEDU64");
125 assert_eq!(
126 detect_memory_dump(&mut Cursor::new(data)).unwrap(),
127 Some(MemDumpFormat::WinCrashDump)
128 );
129 }
130
131 #[test]
132 fn detect_mem_none_for_non_dump() {
133 let data = vec![0u8; 64];
134 assert_eq!(detect_memory_dump(&mut Cursor::new(data)).unwrap(), None);
135 }
136}