ostool 0.30.1

A tool for operating system development
Documentation
use anyhow::{Context, bail};
use object::{
    Object, ObjectSegment, ObjectSymbol,
    read::elf::{ElfFile, FileHeader, ProgramHeader},
};

pub(crate) struct ElfMetadata {
    pub(crate) arch: object::Architecture,
    pub(crate) entry: u64,
    pub(crate) load_segments: Vec<LoadSegment>,
    pub(crate) executable_start: Option<u64>,
}

pub(crate) struct LoadSegment {
    pub(crate) virtual_address: u64,
    pub(crate) physical_address: u64,
    pub(crate) file_offset: u64,
    pub(crate) file_size: u64,
    pub(crate) memory_size: u64,
    pub(crate) alignment: u64,
    pub(crate) flags: u32,
}

impl ElfMetadata {
    pub(crate) fn parse(data: &[u8]) -> anyhow::Result<Self> {
        let file = object::File::parse(data).context("failed to parse ELF")?;

        match file {
            object::File::Elf32(file) => Self::from_elf(&file),
            object::File::Elf64(file) => Self::from_elf(&file),
            _ => bail!("expected an ELF file"),
        }
    }

    fn from_elf<Elf>(file: &ElfFile<'_, Elf>) -> anyhow::Result<Self>
    where
        Elf: FileHeader,
    {
        let endian = file.endian();
        let load_segments = file
            .segments()
            .map(|segment| {
                let header = segment.elf_program_header();
                LoadSegment {
                    virtual_address: segment.address(),
                    physical_address: header.p_paddr(endian).into(),
                    file_offset: header.p_offset(endian).into(),
                    file_size: header.p_filesz(endian).into(),
                    memory_size: header.p_memsz(endian).into(),
                    alignment: header.p_align(endian).into(),
                    flags: header.p_flags(endian),
                }
            })
            .collect();

        let mut executable_start = None;
        for symbol in file.symbols() {
            if symbol.name()? == "__executable_start" && symbol.is_definition() {
                executable_start = Some(symbol.address());
                break;
            }
        }

        Ok(Self {
            arch: file.architecture(),
            entry: file.entry(),
            load_segments,
            executable_start,
        })
    }
}