neoncore 7.0.0

Core utility library for working with binary data streams.
Documentation
//! This example shows how to read an ELF file and print some information about it.
//! This code is based on the ELF specification, which can be found here:
//! https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html
//! This exaple wont work on big endian systems, because it assumes little endian.
//! but it will distinguish between 32 and 64 bit ELF files.
//! even though the [`EHeader`] struct is defined as 64 bit the reader will read the correct size
//! depending on the ELF file.
#![allow(dead_code)]

use std::io::Read;

use neoncore::const_fn::ascii_to_u32_le;
use neoncore::streams::advanced_readers::StructReader;
use neoncore::streams::AnyInt;

const ELF_MAGIC: u32 = ascii_to_u32_le(b"\x7fELF");

#[derive(Debug)]
struct EIdent {
    ei_mag: u32,
    ei_class: u8,
    ei_data: u8,
    ei_version: u8,
    ei_osabi: u8,
    ei_abiversion: u8,
}

#[derive(Debug)]
struct EHeader {
    e_ident: EIdent,
    e_type: u16,
    e_machine: u16,
    e_version: u32,
    e_entry: u64,
    e_phoff: u64,
    e_shoff: u64,
    e_flags: u32,
    e_ehsize: u16,
    e_phentsize: u16,
    e_phnum: u16,
    e_shentsize: u16,
    e_shnum: u16,
    e_shstrndx: u16,
}

impl EHeader {
    fn read<R: Read>(mut s: R) -> Self {
        let ident_reader = StructReader::new_le()
            .add_u32_field("ei_mag")
            .add_u8_field("ei_class")
            .add_u8_field("ei_data")
            .add_u8_field("ei_version")
            .add_u8_field("ei_osabi")
            .add_u8_field("ei_abiversion")
            .add_padding(7)
            .read(&mut s)
            .unwrap();

        let header_reader = StructReader::new_le()
            .add_u16_field("e_type")
            .add_u16_field("e_machine")
            .add_u32_field("e_version");

        let header_reader = if ident_reader["ei_class"] == AnyInt::U8(2) {
            header_reader
                .add_u64_field("e_entry")
                .add_u64_field("e_phoff")
                .add_u64_field("e_shoff")
        } else {
            header_reader
                .add_u32_field("e_entry")
                .add_u32_field("e_phoff")
                .add_u32_field("e_shoff")
        };

        let header_reader = header_reader
            .add_u32_field("e_flags")
            .add_u16_field("e_ehsize")
            .add_u16_field("e_phentsize")
            .add_u16_field("e_phnum")
            .add_u16_field("e_shentsize")
            .add_u16_field("e_shnum")
            .add_u16_field("e_shstrndx");

        let header = header_reader.read(&mut s).unwrap();
        println!("Header: {:#?}", header);

        let e_ident = EIdent {
            ei_mag: ident_reader["ei_mag"].try_into().unwrap(),
            ei_class: ident_reader["ei_class"].try_into().unwrap(),
            ei_data: ident_reader["ei_data"].try_into().unwrap(),
            ei_version: ident_reader["ei_version"].try_into().unwrap(),
            ei_osabi: ident_reader["ei_osabi"].try_into().unwrap(),
            ei_abiversion: ident_reader["ei_abiversion"].try_into().unwrap(),
        };
        EHeader {
            e_ident,
            e_type: header["e_type"].try_into().unwrap(),
            e_machine: header["e_machine"].try_into().unwrap(),
            e_version: header["e_version"].try_into().unwrap(),
            e_entry: header["e_entry"].try_into().unwrap(),
            e_phoff: header["e_phoff"].try_into().unwrap(),
            e_shoff: header["e_shoff"].try_into().unwrap(),
            e_flags: header["e_flags"].try_into().unwrap(),
            e_ehsize: header["e_ehsize"].try_into().unwrap(),
            e_phentsize: header["e_phentsize"].try_into().unwrap(),
            e_phnum: header["e_phnum"].try_into().unwrap(),
            e_shentsize: header["e_shentsize"].try_into().unwrap(),
            e_shnum: header["e_shnum"].try_into().unwrap(),
            e_shstrndx: header["e_shstrndx"].try_into().unwrap(),
        }
    }
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() != 2 {
        println!("Usage: {} <elf-file>", args[0]);
        return;
    }

    let elf_file = &args[1];

    let file = match std::fs::File::open(elf_file) {
        Ok(file) => file,
        Err(e) => {
            println!("Error opening file: {}", e);
            return;
        }
    };

    let mut reader = std::io::BufReader::new(file);

    let header = EHeader::read(&mut reader);

    println!("Magic: {:#x}", header.e_ident.ei_mag);

    println!("{:#?}", header);
}