schnauzer 0.3.5

Library for parsing Mach-O files
Documentation
use scroll::IOread;
use std::fmt::{Debug};

use super::result::Result;
use super::reader::RcReader;

pub mod primitives;
pub use primitives::*;

pub mod magic;
pub use magic::Magic;

pub mod fat_object;
pub use fat_object::*;

pub mod fat_arch;
pub use fat_arch::*;

pub mod mach_object;
pub use mach_object::*;

pub mod mach_header;
pub use mach_header::*;

pub mod load_command;
pub use load_command::*;

pub mod section;
pub use section::*;

pub mod nlist;
pub use nlist::*;

pub mod build_tool_version;
pub use build_tool_version::*;

pub mod dylib;

pub mod reloc;

pub use super::fmt_ext;

pub use super::auto_enum_fields;

pub(crate) use super::constants;

#[derive(Debug)]
pub enum ObjectType {
    Fat(FatObject),
    MachO(MachObject),
}

impl ObjectType {
    pub(super) fn parse(reader: RcReader) -> Result<ObjectType> {
        let magic = reader.borrow_mut().ioread_with::<u32>(scroll::BE)?;
        let magic: Magic = magic.try_into()?;
        if magic.is_fat() {
            let header = FatObject::parse(reader.clone())?;
            Ok(ObjectType::Fat(header))
        } else {
            let header = MachObject::parse(reader.clone(), 0)?;
            Ok(ObjectType::MachO(header))
        }
    }
}

impl ObjectType {
    pub fn mach_object_with_arch(&self, arch: &str) -> Option<MachObject> {
        self.mach_objects().into_iter().find(|o| {
            match o.header.printable_cpu() {
                Some(cpu) => cpu.to_string() == arch,
                None => false,
            }
        })
    }

    pub fn mach_objects(&self) -> Vec<MachObject> {
        match self {
            ObjectType::Fat(f) => f.objects(),
            ObjectType::MachO(o) => vec![o.clone()],
        }
    }

    pub fn arch_with_name(&self, name: &str) -> Option<FatArch> {
        self.archs().into_iter().find(|a| {
            match a.printable_cpu() {
                Some(cpu) => cpu.to_string() == name,
                None => false,
            }
        })
    }

    pub fn archs(&self) -> Vec<FatArch> {
        match &self {
            ObjectType::Fat(fat) => fat.arch_iterator().collect(),
            ObjectType::MachO(_) => vec![],
        }
    }
}

#[cfg(test)]
mod test {
    use crate::*;
    #[test]
    fn test_magic_consistence() {
        check_magic_interchangeability(Magic::Fat);
        check_magic_interchangeability(Magic::FatReverse);
        check_magic_interchangeability(Magic::Bin32);
        check_magic_interchangeability(Magic::Bin32Reverse);
        check_magic_interchangeability(Magic::Bin64);
        check_magic_interchangeability(Magic::Bin64Reverse);
    }

    fn check_magic_interchangeability(magic: Magic) {
        let raw_magic = magic.raw_value();
        let from_raw: Magic = raw_magic.try_into().unwrap_or_else(|_| {
            panic!(
                "Magic '{:#09x}' can not be converted to concrete type",
                raw_magic
            );
        });

        assert_eq!(
            raw_magic,
            from_raw.raw_value(),
            "Expected '{:#09x}', got '{:#09x}'",
            raw_magic,
            from_raw.raw_value()
        );
    }
}