parse section names table header

This commit is contained in:
pantonshire committed 2024-08-10 18:20:59 +01:00
1 parent 4d6521c5b4
commit d1ee14003c
1 file changed
+169 -76
+169 -76
View File
@@ -13,59 +13,79 @@ fn main() {
#[derive(Clone)] #[derive(Clone)]
struct InputBytes<'a> { struct InputBytes<'a> {
bytes: &'a [u8], bytes: &'a [u8],
offset: usize,
} }
impl<'a> InputBytes<'a> { impl<'a> InputBytes<'a> {
fn new(bytes: &'a [u8]) -> Self { fn new(bytes: &'a [u8]) -> Self {
Self { bytes, offset: 0 } Self { bytes }
} }
fn offset(&self) -> usize { fn new_offset(bytes: &'a [u8], offset: usize) -> Self {
self.offset Self::new(bytes).advanced(offset)
} }
fn advance_offset(&self, n: usize) -> usize { fn prefix_len(&self, n: usize) -> usize {
self.bytes.len().min(self.offset + n) self.bytes.len().min(n)
}
fn advanced(&self, n: usize) -> Self {
Self {
bytes: &self.bytes[self.prefix_len(n)..],
}
} }
fn advance(&mut self, n: usize) -> &mut Self { fn advance(&mut self, n: usize) -> &mut Self {
self.offset = self.advance_offset(n); self.bytes = &self.bytes[self.prefix_len(n)..];
self self
} }
fn peek(&self, n: usize) -> Option<&'a [u8]> { fn peek(&self, n: usize) -> Result<&'a [u8], ParseError> {
self.bytes.get(self.offset .. (self.offset + n)) self.bytes.get(..n).ok_or(ParseError::UnexpectedEof)
} }
fn pop(&mut self, n: usize) -> Option<&'a [u8]> { fn pop(&mut self, n: usize) -> Result<&'a [u8], ParseError> {
let res = self.peek(n); let res = self.peek(n);
if res.is_ok() {
self.advance(n); self.advance(n);
}
res res
} }
fn pop_u16(&mut self, endianness: Endianness) -> Option<u16> { fn pop_arr<const N: usize>(&mut self) -> Result<[u8; N], ParseError> {
let bytes = self.pop(2).and_then(|bytes| <[u8; 2]>::try_from(bytes).ok())?; self.pop(N).map(|bs| <[u8; N]>::try_from(bs).unwrap())
Some(endianness.read_u16(bytes))
} }
fn pop_u32(&mut self, endianness: Endianness) -> Option<u32> { fn pop_u8(&mut self) -> Result<u8, ParseError> {
let bytes = self.pop(4).and_then(|bytes| <[u8; 4]>::try_from(bytes).ok())?; self.pop_arr::<1>().map(|[x]| x)
Some(endianness.read_u32(bytes))
} }
fn pop_u64(&mut self, endianness: Endianness) -> Option<u64> { fn pop_u16(&mut self, endianness: Endianness) -> Result<u16, ParseError> {
let bytes = self.pop(8).and_then(|bytes| <[u8; 8]>::try_from(bytes).ok())?; let bytes = self.pop_arr::<2>()?;
Some(endianness.read_u64(bytes)) Ok(endianness.read_u16(bytes))
} }
fn pop_word(&mut self, endianness: Endianness, width: Width) -> Option<u64> { fn pop_u32(&mut self, endianness: Endianness) -> Result<u32, ParseError> {
let bytes = self.pop_arr::<4>()?;
Ok(endianness.read_u32(bytes))
}
fn pop_u64(&mut self, endianness: Endianness) -> Result<u64, ParseError> {
let bytes = self.pop_arr::<8>()?;
Ok(endianness.read_u64(bytes))
}
fn pop_word(&mut self, endianness: Endianness, width: Width) -> Result<u64, ParseError> {
match width { match width {
Width::Bits32 => self.pop_u32(endianness).map(u64::from), Width::Bits32 => self.pop_u32(endianness).map(u64::from),
Width::Bits64 => self.pop_u64(endianness), Width::Bits64 => self.pop_u64(endianness),
} }
} }
fn pop_word_usize(&mut self, endianness: Endianness, width: Width) -> Result<usize, ParseError> {
self.pop_word(endianness, width)
.and_then(|x| usize::try_from(x).map_err(|_| ParseError::OffsetOutOfBounds))
}
fn hexdump(&self, n: usize) { fn hexdump(&self, n: usize) {
print!("{: <8}", ""); print!("{: <8}", "");
for i in 0..16 { for i in 0..16 {
@@ -91,9 +111,8 @@ impl<'a> InputBytes<'a> {
} }
struct Elf<'a> { struct Elf<'a> {
bytes: &'a [u8], elf_bytes: &'a [u8],
width: Width, bl: ByteLayout,
endianness: Endianness,
header_version: u8, header_version: u8,
abi: u8, abi: u8,
ty: ElfType, ty: ElfType,
@@ -107,67 +126,68 @@ impl<'a> Elf<'a> {
hdr.hexdump(64); hdr.hexdump(64);
let magic = hdr.pop(4).ok_or(ElfError)?; let magic = hdr.pop(4)?;
if magic != &[0x7f, b'E', b'L', b'F'] { if magic != &[0x7f, b'E', b'L', b'F'] {
return Err(ElfError); return Err(ElfError::BadMagic);
} }
let width = match hdr.pop(1) { let width = match hdr.pop_u8()? {
Some(&[1]) => Width::Bits32, 1 => Width::Bits32,
Some(&[2]) => Width::Bits64, 2 => Width::Bits64,
_ => return Err(ElfError), _ => return Err(ElfError::UnsupportedValue),
}; };
let endianness = match hdr.pop(1) { let endianness = match hdr.pop_u8()? {
Some(&[1]) => Endianness::Little, 1 => Endianness::Little,
Some(&[2]) => Endianness::Big, 2 => Endianness::Big,
_ => return Err(ElfError), _ => return Err(ElfError::UnsupportedValue),
}; };
let Some(&[header_version]) = hdr.pop(1) else { let bl = ByteLayout {
return Err(ElfError) endianness,
width,
}; };
let Some(&[abi]) = hdr.pop(1) else { let header_version = hdr.pop_u8()?;
return Err(ElfError)
let abi = hdr.pop_u8()?;
hdr.pop(8)?;
let ty = match hdr.pop_u16(endianness)? {
1 => ElfType::Relocatable,
2 => ElfType::Executable,
3 => ElfType::Shared,
4 => ElfType::Core,
_ => return Err(ElfError::UnsupportedValue),
}; };
hdr.pop(8); let instruction_set = match hdr.pop_u16(endianness)? {
0 => None,
let ty = match hdr.pop_u16(endianness) { 0x02 => Some(InstructionSet::Sparc),
Some(1) => ElfType::Relocatable, 0x03 => Some(InstructionSet::I386),
Some(2) => ElfType::Executable, 0x08 => Some(InstructionSet::Mips),
Some(3) => ElfType::Shared, 0x14 => Some(InstructionSet::PowerPc),
Some(4) => ElfType::Core, 0x28 => Some(InstructionSet::Arm),
_ => return Err(ElfError), 0x2a => Some(InstructionSet::SuperH),
0x32 => Some(InstructionSet::Ia64),
0x3e => Some(InstructionSet::Amd64),
0xb7 => Some(InstructionSet::Aarch64),
0xf3 => Some(InstructionSet::RiscV),
_ => return Err(ElfError::UnsupportedValue),
}; };
let instruction_set = match hdr.pop_u16(endianness) { let elf_version = hdr.pop_u32(endianness)?;
Some(0) => None, let entry_offset = hdr.pop_word(endianness, width)?;
Some(0x02) => Some(InstructionSet::Sparc), let pht_offset = hdr.pop_word_usize(endianness, width)?;
Some(0x03) => Some(InstructionSet::I386), let sht_offset = hdr.pop_word_usize(endianness, width)?;
Some(0x08) => Some(InstructionSet::Mips), let flags = hdr.pop_u32(endianness)?;
Some(0x14) => Some(InstructionSet::PowerPc), let header_size = hdr.pop_u16(endianness)?;
Some(0x28) => Some(InstructionSet::Arm), let pht_entry_size = hdr.pop_u16(endianness)?;
Some(0x2a) => Some(InstructionSet::SuperH), let pht_len = hdr.pop_u16(endianness)?;
Some(0x32) => Some(InstructionSet::Ia64), let sht_entry_size = hdr.pop_u16(endianness)?;
Some(0x3e) => Some(InstructionSet::Amd64), let sht_len = hdr.pop_u16(endianness)?;
Some(0xb7) => Some(InstructionSet::Aarch64), let shstr_idx = hdr.pop_u16(endianness)?;
Some(0xf3) => Some(InstructionSet::RiscV),
_ => return Err(ElfError),
};
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!(entry_offset);
dbg!(pht_offset); dbg!(pht_offset);
@@ -178,14 +198,19 @@ impl<'a> Elf<'a> {
dbg!(pht_len); dbg!(pht_len);
dbg!(sht_entry_size); dbg!(sht_entry_size);
dbg!(sht_len); dbg!(sht_len);
dbg!(string_table_idx); dbg!(shstr_idx);
// TODO // TODO
let shstr = SectionHeader::parse(bl,
InputBytes::new_offset(bytes, sht_offset + usize::from(sht_entry_size * shstr_idx)))?;
let str_table = InputBytes::new_offset(bytes, shstr.offset);
str_table.hexdump(shstr.size);
Ok(Self { Ok(Self {
bytes, elf_bytes: bytes,
width, bl,
endianness,
header_version, header_version,
abi, abi,
ty, ty,
@@ -195,6 +220,54 @@ impl<'a> Elf<'a> {
} }
} }
struct SectionHeader {
name: u32,
// FIXME: parse type
ty: u32,
flags: u64,
addr: u64,
offset: usize,
size: usize,
link: u32,
info: u32,
align: u64,
ent_size: usize,
}
impl SectionHeader {
fn parse(bl: ByteLayout, mut bytes: InputBytes) -> Result<Self, ElfError> {
let name = bytes.pop_u32(bl.endianness)?;
let ty = bytes.pop_u32(bl.endianness)?;
let flags = bytes.pop_word(bl.endianness, bl.width)?;
let addr = bytes.pop_word(bl.endianness, bl.width)?;
let offset = bytes.pop_word_usize(bl.endianness, bl.width)?;
let size = bytes.pop_word_usize(bl.endianness, bl.width)?;
let link = bytes.pop_u32(bl.endianness)?;
let info = bytes.pop_u32(bl.endianness)?;
let align = bytes.pop_word(bl.endianness, bl.width)?;
let ent_size = bytes.pop_word_usize(bl.endianness, bl.width)?;
Ok(Self {
name,
ty,
flags,
addr,
offset,
size,
link,
info,
align,
ent_size,
})
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
struct ByteLayout {
endianness: Endianness,
width: Width,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum Width { enum Width {
Bits32, Bits32,
@@ -253,4 +326,24 @@ enum InstructionSet {
} }
#[derive(Debug)] #[derive(Debug)]
struct ElfError; enum ElfError {
BadMagic,
UnexpectedEof,
OffsetOutOfBounds,
UnsupportedValue,
}
impl From<ParseError> for ElfError {
fn from(value: ParseError) -> Self {
match value {
ParseError::UnexpectedEof => Self::UnexpectedEof,
ParseError::OffsetOutOfBounds => Self::OffsetOutOfBounds,
}
}
}
#[derive(Debug)]
enum ParseError {
UnexpectedEof,
OffsetOutOfBounds,
}