start elf parser
parent
8f94f4b5e9
commit
0474360fef
@ -0,0 +1,4 @@
|
|||||||
|
*.bin
|
||||||
|
.pc
|
||||||
|
target/
|
||||||
|
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "elf"
|
||||||
|
version = "0.1.0"
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
[workspace]
|
||||||
|
resolver = "2"
|
||||||
|
members = [
|
||||||
|
"elf"
|
||||||
|
]
|
||||||
|
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "elf"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
@ -0,0 +1,211 @@
|
|||||||
|
use std::{env, fs};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut args = env::args().skip(1);
|
||||||
|
let path = args.next().unwrap();
|
||||||
|
|
||||||
|
let bytes = fs::read(path).unwrap();
|
||||||
|
|
||||||
|
let elf = Elf::parse(InputBytes::new(&bytes)).unwrap();
|
||||||
|
|
||||||
|
println!("{:?}", elf);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InputBytes<'a> {
|
||||||
|
bytes: &'a [u8],
|
||||||
|
offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> InputBytes<'a> {
|
||||||
|
fn new(bytes: &'a [u8]) -> Self {
|
||||||
|
Self { bytes, offset: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_u16(&mut self, endianness: Endianness) -> Option<u16> {
|
||||||
|
let bytes = self.pop(2).and_then(|bytes| <[u8; 2]>::try_from(bytes).ok())?;
|
||||||
|
Some(endianness.read_u16(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_u32(&mut self, endianness: Endianness) -> Option<u32> {
|
||||||
|
let bytes = self.pop(4).and_then(|bytes| <[u8; 4]>::try_from(bytes).ok())?;
|
||||||
|
Some(endianness.read_u32(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_u64(&mut self, endianness: Endianness) -> Option<u64> {
|
||||||
|
let bytes = self.pop(8).and_then(|bytes| <[u8; 8]>::try_from(bytes).ok())?;
|
||||||
|
Some(endianness.read_u64(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_width(&mut self, endianness: Endianness, width: Width) -> Option<u64> {
|
||||||
|
match width {
|
||||||
|
Width::Bits32 => self.pop_u32(endianness).map(u64::from),
|
||||||
|
Width::Bits64 => self.pop_u64(endianness),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Elf {
|
||||||
|
width: Width,
|
||||||
|
endianness: Endianness,
|
||||||
|
header_version: u8,
|
||||||
|
abi: u8,
|
||||||
|
ty: ElfType,
|
||||||
|
instruction_set: Option<InstructionSet>,
|
||||||
|
elf_version: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Elf {
|
||||||
|
fn parse(mut bytes: InputBytes) -> Result<Self, ElfError> {
|
||||||
|
let magic = bytes.pop(4).ok_or(ElfError::Invalid)?;
|
||||||
|
if magic != &[0x7f, b'E', b'L', b'F'] {
|
||||||
|
return Err(ElfError::Invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
let width = match bytes.pop(1) {
|
||||||
|
Some(&[1]) => Width::Bits32,
|
||||||
|
Some(&[2]) => Width::Bits64,
|
||||||
|
_ => return Err(ElfError::Invalid),
|
||||||
|
};
|
||||||
|
|
||||||
|
let endianness = match bytes.pop(1) {
|
||||||
|
Some(&[1]) => Endianness::Little,
|
||||||
|
Some(&[2]) => Endianness::Big,
|
||||||
|
_ => return Err(ElfError::Invalid),
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(&[header_version]) = bytes.pop(1) else {
|
||||||
|
return Err(ElfError::Invalid)
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(&[abi]) = bytes.pop(1) else {
|
||||||
|
return Err(ElfError::Invalid)
|
||||||
|
};
|
||||||
|
|
||||||
|
bytes.pop(8);
|
||||||
|
|
||||||
|
let ty = match bytes.pop_u16(endianness) {
|
||||||
|
Some(1) => ElfType::Relocatable,
|
||||||
|
Some(2) => ElfType::Executable,
|
||||||
|
Some(3) => ElfType::Shared,
|
||||||
|
Some(4) => ElfType::Core,
|
||||||
|
_ => return Err(ElfError::Invalid),
|
||||||
|
};
|
||||||
|
|
||||||
|
let instruction_set = match bytes.pop_u16(endianness) {
|
||||||
|
Some(0) => None,
|
||||||
|
Some(0x02) => Some(InstructionSet::Sparc),
|
||||||
|
Some(0x03) => Some(InstructionSet::I386),
|
||||||
|
Some(0x08) => Some(InstructionSet::Mips),
|
||||||
|
Some(0x14) => Some(InstructionSet::PowerPc),
|
||||||
|
Some(0x28) => Some(InstructionSet::Arm),
|
||||||
|
Some(0x2a) => Some(InstructionSet::SuperH),
|
||||||
|
Some(0x32) => Some(InstructionSet::Ia64),
|
||||||
|
Some(0x3e) => Some(InstructionSet::Amd64),
|
||||||
|
Some(0xb7) => Some(InstructionSet::Aarch64),
|
||||||
|
Some(0xf3) => Some(InstructionSet::RiscV),
|
||||||
|
_ => return Err(ElfError::Invalid),
|
||||||
|
};
|
||||||
|
|
||||||
|
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)?;
|
||||||
|
|
||||||
|
dbg!(entry_offset);
|
||||||
|
dbg!(program_header_table_offset);
|
||||||
|
dbg!(section_header_table_offset);
|
||||||
|
dbg!(flags);
|
||||||
|
dbg!(header_size);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
width,
|
||||||
|
endianness,
|
||||||
|
header_version,
|
||||||
|
abi,
|
||||||
|
ty,
|
||||||
|
instruction_set,
|
||||||
|
elf_version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
enum Width {
|
||||||
|
Bits32,
|
||||||
|
Bits64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
enum Endianness {
|
||||||
|
Little,
|
||||||
|
Big,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Endianness {
|
||||||
|
fn read_u16(self, bytes: [u8; 2]) -> u16 {
|
||||||
|
match self {
|
||||||
|
Self::Little => u16::from_le_bytes(bytes),
|
||||||
|
Self::Big => u16::from_be_bytes(bytes),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u32(self, bytes: [u8; 4]) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::Little => u32::from_le_bytes(bytes),
|
||||||
|
Self::Big => u32::from_be_bytes(bytes),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u64(self, bytes: [u8; 8]) -> u64 {
|
||||||
|
match self {
|
||||||
|
Self::Little => u64::from_le_bytes(bytes),
|
||||||
|
Self::Big => u64::from_be_bytes(bytes),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
enum ElfType {
|
||||||
|
Relocatable,
|
||||||
|
Executable,
|
||||||
|
Shared,
|
||||||
|
Core,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
enum InstructionSet {
|
||||||
|
Sparc,
|
||||||
|
I386,
|
||||||
|
Mips,
|
||||||
|
PowerPc,
|
||||||
|
Arm,
|
||||||
|
SuperH,
|
||||||
|
Ia64,
|
||||||
|
Amd64,
|
||||||
|
Aarch64,
|
||||||
|
RiscV,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum ElfError {
|
||||||
|
Invalid,
|
||||||
|
Unsupported,
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue