133 lines
2.9 KiB
Rust
133 lines
2.9 KiB
Rust
use super::*;
|
|
|
|
fn minimal_elf64() -> [u8; 120] {
|
|
let mut buf = [0u8; 120];
|
|
|
|
// ELF magic
|
|
buf[0] = 0x7f;
|
|
buf[1] = b'E';
|
|
buf[2] = b'L';
|
|
buf[3] = b'F';
|
|
|
|
// EI_CLASS = ELFCLASS64
|
|
buf[4] = 2;
|
|
// EI_DATA = ELFDATA2LSB
|
|
buf[5] = 1;
|
|
// EI_VERSION
|
|
buf[6] = 1;
|
|
|
|
// e_type = ET_EXEC (2)
|
|
buf[16] = 2;
|
|
buf[17] = 0;
|
|
|
|
// e_entry = 0x1000
|
|
let entry: u64 = 0x1000;
|
|
buf[24..32].copy_from_slice(&entry.to_le_bytes());
|
|
|
|
// e_phoff = 64 (right after ELF header)
|
|
let phoff: u64 = 64;
|
|
buf[32..40].copy_from_slice(&phoff.to_le_bytes());
|
|
|
|
// e_phentsize = 56
|
|
buf[54] = 56;
|
|
buf[55] = 0;
|
|
|
|
// e_phnum = 1
|
|
buf[56] = 1;
|
|
buf[57] = 0;
|
|
|
|
// Program header at offset 64:
|
|
let ph = 64;
|
|
|
|
// p_type = PT_LOAD (1)
|
|
buf[ph] = 1;
|
|
|
|
// p_flags = PF_R | PF_X (4 | 1 = 5)
|
|
buf[ph + 4] = 5;
|
|
|
|
// p_offset = 0
|
|
let p_offset: u64 = 0;
|
|
buf[ph + 8..ph + 16].copy_from_slice(&p_offset.to_le_bytes());
|
|
|
|
// p_vaddr = 0x1000
|
|
let p_vaddr: u64 = 0x1000;
|
|
buf[ph + 16..ph + 24].copy_from_slice(&p_vaddr.to_le_bytes());
|
|
|
|
// p_filesz = 120
|
|
let p_filesz: u64 = 120;
|
|
buf[ph + 32..ph + 40].copy_from_slice(&p_filesz.to_le_bytes());
|
|
|
|
// p_memsz = 4096
|
|
let p_memsz: u64 = 4096;
|
|
buf[ph + 40..ph + 48].copy_from_slice(&p_memsz.to_le_bytes());
|
|
|
|
buf
|
|
}
|
|
|
|
#[test]
|
|
fn parse_valid_elf64() {
|
|
let data = minimal_elf64();
|
|
let info = parse(&data).unwrap();
|
|
|
|
assert_eq!(info.entry_point, 0x1000);
|
|
assert_eq!(info.segment_count, 1);
|
|
|
|
let seg = info.segments().next().unwrap();
|
|
assert_eq!(seg.vaddr, 0x1000);
|
|
assert_eq!(seg.file_size, 120);
|
|
assert_eq!(seg.mem_size, 4096);
|
|
assert!(seg.flags.read);
|
|
assert!(seg.flags.execute);
|
|
assert!(!seg.flags.write);
|
|
}
|
|
|
|
#[test]
|
|
fn parse_too_small_fails() {
|
|
let data = [0u8; 10];
|
|
assert_eq!(parse(&data), Err(ElfError::TooSmall));
|
|
}
|
|
|
|
#[test]
|
|
fn parse_bad_magic_fails() {
|
|
let mut data = minimal_elf64();
|
|
data[0] = 0;
|
|
assert_eq!(parse(&data), Err(ElfError::InvalidMagic));
|
|
}
|
|
|
|
#[test]
|
|
fn parse_32bit_fails() {
|
|
let mut data = minimal_elf64();
|
|
data[4] = 1; // ELFCLASS32
|
|
assert_eq!(parse(&data), Err(ElfError::Not64Bit));
|
|
}
|
|
|
|
#[test]
|
|
fn parse_big_endian_fails() {
|
|
let mut data = minimal_elf64();
|
|
data[5] = 2; // ELFDATA2MSB
|
|
assert_eq!(parse(&data), Err(ElfError::NotLittleEndian));
|
|
}
|
|
|
|
#[test]
|
|
fn parse_shared_object_fails() {
|
|
let mut data = minimal_elf64();
|
|
data[16] = 3; // ET_DYN
|
|
assert_eq!(parse(&data), Err(ElfError::NotExecutable));
|
|
}
|
|
|
|
#[test]
|
|
fn total_pages_rounds_up() {
|
|
let data = minimal_elf64();
|
|
let info = parse(&data).unwrap();
|
|
assert_eq!(info.total_pages(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn skips_non_load_segments() {
|
|
let mut data = minimal_elf64();
|
|
// Change p_type to PT_NOTE (4)
|
|
data[64] = 4;
|
|
let info = parse(&data).unwrap();
|
|
assert_eq!(info.segment_count, 0);
|
|
}
|