1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use std::fmt;
use std::fs::File;
use std::io::{self, Read};

use scroll::{self, Gread};
use super::constants::cputype;
use error;

pub const FAT_MAGIC: u32 = 0xcafebabe;
pub const FAT_CIGAM: u32 = 0xbebafeca;

#[repr(C)]
#[derive(Clone, Copy, Default)]
/// The Mach-o `FatHeader` always has its data bigendian
pub struct FatHeader {
    pub magic: u32,
    pub nfat_arch: u32,
}

pub const SIZEOF_FAT_HEADER: usize = 8;

impl fmt::Debug for FatHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "0x{:x} nfat_arch: {}\n", self.magic, self.nfat_arch)
    }
}

#[repr(C)]
#[derive(Clone, Copy, Default)]
/// The Mach-o `FatArch` always has its data bigendian
pub struct FatArch {
    pub cputype: u32,
    pub cpusubtype: u32,
    pub offset: u32,
    pub size: u32,
    pub align: u32,
}

pub const SIZEOF_FAT_ARCH: usize = 20;

impl fmt::Debug for FatArch {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "cputype: {} cpusubtype: {} offset: {} size: {} align: {}\n",
               cputype::cpu_type_to_str(self.cputype),
               self.cpusubtype,
               self.offset,
               self.size,
               self.align)
    }
}

impl FatHeader {
    pub fn from_bytes(bytes: &[u8; SIZEOF_FAT_HEADER]) -> FatHeader {
        let mut offset = 0;
        let magic = bytes.gread_with(&mut offset, scroll::BE).unwrap();
        let nfat_arch = bytes.gread_with(&mut offset, scroll::BE).unwrap();
        FatHeader {
            magic: magic,
            nfat_arch: nfat_arch,
        }
    }

    pub fn from_fd(fd: &mut File) -> io::Result<FatHeader> {
        let mut header = [0; SIZEOF_FAT_HEADER];
        try!(fd.read(&mut header));
        Ok(FatHeader::from_bytes(&header))
    }

    /// Parse a mach-o fat header from the `buffer`
    pub fn parse<S: AsRef<[u8]>>(buffer: &S) -> error::Result<FatHeader> {
        let mut header = FatHeader::default();
        let mut offset = 0;
        header.magic = buffer.gread_with(&mut offset, scroll::BE)?;
        header.nfat_arch = buffer.gread_with(&mut offset, scroll::BE)?;
        Ok(header)
    }

}

impl FatArch {
    pub fn new(bytes: &[u8; SIZEOF_FAT_ARCH]) -> FatArch {
        let mut offset = 0;
        let cputype = bytes.gread_with(&mut offset, scroll::BE).unwrap();
        let cpusubtype = bytes.gread_with(&mut offset, scroll::BE).unwrap();
        let offset_ = bytes.gread_with(&mut offset, scroll::BE).unwrap();
        let size = bytes.gread_with(&mut offset, scroll::BE).unwrap();
        let align = bytes.gread_with(&mut offset, scroll::BE).unwrap();
        FatArch {
            cputype: cputype,
            cpusubtype: cpusubtype,
            offset: offset_,
            size: size,
            align: align,
        }
    }

    pub fn is_64(&self) -> bool {
        self.cputype == cputype::CPU_TYPE_X86_64 || self.cputype == cputype::CPU_TYPE_ARM64
    }

    pub fn parse_arches<S: AsRef<[u8]>>(fd: &S, mut offset: usize, count: usize) -> error::Result<Vec<Self>> {
        let mut archs = Vec::with_capacity(count);
        let offset = &mut offset;
        for _ in 0..count {
            let mut arch = Self::default();
            arch.cputype = fd.gread_with(offset, scroll::BE)?;
            arch.cpusubtype = fd.gread_with(offset, scroll::BE)?;
            arch.offset = fd.gread_with(offset, scroll::BE)?;
            arch.size = fd.gread_with(offset, scroll::BE)?;
            arch.align = fd.gread_with(offset, scroll::BE)?;
            archs.push(arch);
        }
        Ok(archs)
    }

    // pub fn from_path(path: &Path) -> io::Result<Vec<Self>> {
    //     let mut fd = try!(File::open(&path));
    //     let header = try!(FatHeader::from_fd(&mut fd));
    //     let arches = try!(FatArch::from_fd(&mut fd,
    //                                        SIZEOF_FAT_HEADER as u64,
    //                                        header.nfat_arch as usize
    //                                        ));
    //     Ok(arches)
    // }

    pub fn parse<S: AsRef<[u8]>>(buffer: &S) -> error::Result<Vec<Self>> {
        let header = FatHeader::parse(buffer)?;
        let arches = FatArch::parse_arches(buffer,
                                           SIZEOF_FAT_HEADER,
                                           header.nfat_arch as usize)?;
        Ok(arches)
    }

    pub fn find_cputype(arches: &[Self], cputype: u32) -> Option<&Self> {
        arches.iter().find(|arch| arch.cputype == cputype)
    }

    pub fn find_64(arches: &[Self]) -> Option<&Self> {
        arches.iter().find(|arch| arch.is_64())
    }
}