#![forbid(unsafe_code)]
use std::io::{self, Read, Seek, SeekFrom};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MemDumpFormat {
Lime,
Avml,
ElfCore,
WinCrashDump,
}
impl std::fmt::Display for MemDumpFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MemDumpFormat::Lime => write!(f, "lime"),
MemDumpFormat::Avml => write!(f, "avml"),
MemDumpFormat::ElfCore => write!(f, "elf-core"),
MemDumpFormat::WinCrashDump => write!(f, "win-crashdump"),
}
}
}
pub fn detect_memory_dump<R: Read + Seek>(source: &mut R) -> io::Result<Option<MemDumpFormat>> {
source.seek(SeekFrom::Start(0))?;
let mut buf = [0u8; 18];
let n = read_fill(source, &mut buf);
source.seek(SeekFrom::Start(0))?;
if n >= 4 && &buf[0..4] == b"EMiL" {
return Ok(Some(MemDumpFormat::Lime));
}
if n >= 4 && &buf[0..4] == b"AVML" {
return Ok(Some(MemDumpFormat::Avml));
}
if n >= 8 && &buf[0..8] == b"PAGEDU64" {
return Ok(Some(MemDumpFormat::WinCrashDump));
}
if n >= 18 && buf[0..4] == [0x7F, b'E', b'L', b'F'] {
let e_type = u16::from_le_bytes([buf[16], buf[17]]);
if e_type == 4 {
return Ok(Some(MemDumpFormat::ElfCore));
}
}
Ok(None)
}
fn read_fill<R: Read>(source: &mut R, buf: &mut [u8]) -> usize {
let mut total = 0;
while total < buf.len() {
match source.read(&mut buf[total..]) {
Ok(0) | Err(_) => break,
Ok(n) => total += n,
}
}
total
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn detect_mem_lime() {
let mut data = vec![0u8; 64];
data[0..4].copy_from_slice(b"EMiL"); assert_eq!(
detect_memory_dump(&mut Cursor::new(data)).unwrap(),
Some(MemDumpFormat::Lime)
);
}
#[test]
fn detect_mem_avml() {
let mut data = vec![0u8; 64];
data[0..4].copy_from_slice(b"AVML");
assert_eq!(
detect_memory_dump(&mut Cursor::new(data)).unwrap(),
Some(MemDumpFormat::Avml)
);
}
#[test]
fn detect_mem_elf_core() {
let mut data = vec![0u8; 64];
data[0..4].copy_from_slice(&[0x7F, b'E', b'L', b'F']);
data[16..18].copy_from_slice(&4u16.to_le_bytes()); assert_eq!(
detect_memory_dump(&mut Cursor::new(data)).unwrap(),
Some(MemDumpFormat::ElfCore)
);
}
#[test]
fn detect_mem_elf_exec_is_not_a_dump() {
let mut data = vec![0u8; 64];
data[0..4].copy_from_slice(&[0x7F, b'E', b'L', b'F']);
data[16..18].copy_from_slice(&2u16.to_le_bytes()); assert_eq!(detect_memory_dump(&mut Cursor::new(data)).unwrap(), None);
}
#[test]
fn detect_mem_win_crashdump() {
let mut data = vec![0u8; 64];
data[0..8].copy_from_slice(b"PAGEDU64");
assert_eq!(
detect_memory_dump(&mut Cursor::new(data)).unwrap(),
Some(MemDumpFormat::WinCrashDump)
);
}
#[test]
fn detect_mem_none_for_non_dump() {
let data = vec![0u8; 64];
assert_eq!(detect_memory_dump(&mut Cursor::new(data)).unwrap(), None);
}
}