From 4d6521c5b4b67a034d806eca9e59f0d82971ba92 Mon Sep 17 00:00:00 2001 From: pantonshire Date: Sat, 10 Aug 2024 17:01:43 +0100 Subject: [PATCH] debug hexdump for elf --- elf/src/main.rs | 125 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 85 insertions(+), 40 deletions(-) diff --git a/elf/src/main.rs b/elf/src/main.rs index 22e432d..df27015 100644 --- a/elf/src/main.rs +++ b/elf/src/main.rs @@ -1,4 +1,5 @@ -use std::{env, fs}; +use core::fmt; +use std::{char, env, fs}; fn main() { let mut args = env::args().skip(1); @@ -6,11 +7,10 @@ fn main() { let bytes = fs::read(path).unwrap(); - let elf = Elf::parse(InputBytes::new(&bytes)).unwrap(); - - println!("{:?}", elf); + let elf = Elf::parse(&bytes).unwrap(); } +#[derive(Clone)] struct InputBytes<'a> { bytes: &'a [u8], offset: usize, @@ -21,13 +21,26 @@ impl<'a> InputBytes<'a> { Self { bytes, offset: 0 } } + fn offset(&self) -> usize { + self.offset + } + + fn advance_offset(&self, n: usize) -> usize { + self.bytes.len().min(self.offset + n) + } + + fn advance(&mut self, n: usize) -> &mut Self { + self.offset = self.advance_offset(n); + self + } + fn peek(&self, n: usize) -> Option<&'a [u8]> { self.bytes.get(self.offset .. (self.offset + n)) } fn pop(&mut self, n: usize) -> Option<&'a [u8]> { let res = self.peek(n); - self.offset = self.bytes.len().min(self.offset + n); + self.advance(n); res } @@ -46,16 +59,39 @@ impl<'a> InputBytes<'a> { Some(endianness.read_u64(bytes)) } - fn pop_width(&mut self, endianness: Endianness, width: Width) -> Option { + fn pop_word(&mut self, endianness: Endianness, width: Width) -> Option { match width { Width::Bits32 => self.pop_u32(endianness).map(u64::from), Width::Bits64 => self.pop_u64(endianness), } } + + fn hexdump(&self, n: usize) { + print!("{: <8}", ""); + for i in 0..16 { + print!(" {:x}", i); + } + println!(); + for (i, chunk) in self.bytes[.. n.min(self.bytes.len())].chunks(16).enumerate() { + print!("{:08x}", i * 16); + for b in chunk { + print!(" {:02x}", b); + } + print!("{: <4}", ""); + for b in chunk { + let c = match char::from(*b) { + c if c.is_ascii_graphic() => c, + _ => '.', + }; + print!("{}", c); + } + println!(); + } + } } -#[derive(Debug)] -struct Elf { +struct Elf<'a> { + bytes: &'a [u8], width: Width, endianness: Endianness, header_version: u8, @@ -65,44 +101,48 @@ struct Elf { elf_version: u32, } -impl Elf { - fn parse(mut bytes: InputBytes) -> Result { - let magic = bytes.pop(4).ok_or(ElfError::Invalid)?; +impl<'a> Elf<'a> { + fn parse(bytes: &'a [u8]) -> Result { + let mut hdr = InputBytes::new(bytes); + + hdr.hexdump(64); + + let magic = hdr.pop(4).ok_or(ElfError)?; if magic != &[0x7f, b'E', b'L', b'F'] { - return Err(ElfError::Invalid); + return Err(ElfError); } - let width = match bytes.pop(1) { + let width = match hdr.pop(1) { Some(&[1]) => Width::Bits32, Some(&[2]) => Width::Bits64, - _ => return Err(ElfError::Invalid), + _ => return Err(ElfError), }; - let endianness = match bytes.pop(1) { + let endianness = match hdr.pop(1) { Some(&[1]) => Endianness::Little, Some(&[2]) => Endianness::Big, - _ => return Err(ElfError::Invalid), + _ => return Err(ElfError), }; - let Some(&[header_version]) = bytes.pop(1) else { - return Err(ElfError::Invalid) + let Some(&[header_version]) = hdr.pop(1) else { + return Err(ElfError) }; - let Some(&[abi]) = bytes.pop(1) else { - return Err(ElfError::Invalid) + let Some(&[abi]) = hdr.pop(1) else { + return Err(ElfError) }; - bytes.pop(8); + hdr.pop(8); - let ty = match bytes.pop_u16(endianness) { + let ty = match hdr.pop_u16(endianness) { Some(1) => ElfType::Relocatable, Some(2) => ElfType::Executable, Some(3) => ElfType::Shared, Some(4) => ElfType::Core, - _ => return Err(ElfError::Invalid), + _ => return Err(ElfError), }; - let instruction_set = match bytes.pop_u16(endianness) { + let instruction_set = match hdr.pop_u16(endianness) { Some(0) => None, Some(0x02) => Some(InstructionSet::Sparc), Some(0x03) => Some(InstructionSet::I386), @@ -114,28 +154,36 @@ impl Elf { Some(0x3e) => Some(InstructionSet::Amd64), Some(0xb7) => Some(InstructionSet::Aarch64), Some(0xf3) => Some(InstructionSet::RiscV), - _ => return Err(ElfError::Invalid), + _ => return Err(ElfError), }; - let elf_version = bytes.pop_u32(endianness).ok_or(ElfError::Invalid)?; - - let entry_offset = bytes.pop_width(endianness, width).ok_or(ElfError::Invalid)?; - let program_header_table_offset = bytes.pop_width(endianness, width).ok_or(ElfError::Invalid)?; - let section_header_table_offset = bytes.pop_width(endianness, width).ok_or(ElfError::Invalid)?; - - let flags = bytes.pop_u32(endianness).ok_or(ElfError::Invalid)?; - - let header_size = bytes.pop_u16(endianness).ok_or(ElfError::Invalid)?; + let elf_version = hdr.pop_u32(endianness).ok_or(ElfError)?; + let entry_offset = hdr.pop_word(endianness, width).ok_or(ElfError)?; + let pht_offset = hdr.pop_word(endianness, width).ok_or(ElfError)?; + let sht_offset = hdr.pop_word(endianness, width).ok_or(ElfError)?; + let flags = hdr.pop_u32(endianness).ok_or(ElfError)?; + let header_size = hdr.pop_u16(endianness).ok_or(ElfError)?; + let pht_entry_size = hdr.pop_u16(endianness).ok_or(ElfError)?; + let pht_len = hdr.pop_u16(endianness).ok_or(ElfError)?; + let sht_entry_size = hdr.pop_u16(endianness).ok_or(ElfError)?; + let sht_len = hdr.pop_u16(endianness).ok_or(ElfError)?; + let string_table_idx = hdr.pop_u16(endianness).ok_or(ElfError)?; dbg!(entry_offset); - dbg!(program_header_table_offset); - dbg!(section_header_table_offset); + dbg!(pht_offset); + dbg!(sht_offset); dbg!(flags); dbg!(header_size); + dbg!(pht_entry_size); + dbg!(pht_len); + dbg!(sht_entry_size); + dbg!(sht_len); + dbg!(string_table_idx); // TODO Ok(Self { + bytes, width, endianness, header_version, @@ -205,7 +253,4 @@ enum InstructionSet { } #[derive(Debug)] -enum ElfError { - Invalid, - Unsupported, -} +struct ElfError;