Skip to main content

macho_core/format/
macho.rs

1use crate::error::{Error, Result};
2use crate::format::ParseLimits;
3use crate::format::constants::MachoHeaderFlags;
4use crate::format::io::pod::{self, RawMachHeader32, RawMachHeader64};
5use crate::model::header::*;
6use crate::model::macho_file::MachoFile;
7
8/// Performs parse_macho_file.
9pub fn parse_macho_file(data: &[u8]) -> Result<MachoFile<'_>> {
10    parse_macho_file_with_limits(data, &ParseLimits::default())
11}
12
13pub(crate) fn parse_macho_file_with_limits<'data>(
14    data: &'data [u8],
15    limits: &ParseLimits,
16) -> Result<MachoFile<'data>> {
17    if data.len() < 4 {
18        return Err(Error::format("file too small for Mach-O magic"));
19    }
20
21    let magic_val = u32::from_ne_bytes(data[0..4].try_into().unwrap());
22    let magic = MagicNumber::from_u32(magic_val)?;
23    let endian = magic.endian();
24    let bitness = magic.bitness();
25
26    let header = match bitness {
27        Bitness::Bits32 => {
28            let raw: RawMachHeader32 = pod::read_pod(data, 0)?;
29            MachoHeader {
30                magic,
31                cpu_type: CpuType(endian.interpret_i32(raw.cputype)),
32                cpu_subtype: CpuSubtype(endian.interpret_i32(raw.cpusubtype)),
33                file_type: FileType::from_u32(endian.interpret_u32(raw.filetype)),
34                ncmds: endian.interpret_u32(raw.ncmds),
35                sizeofcmds: endian.interpret_u32(raw.sizeofcmds),
36                flags: MachoHeaderFlags::from_bits_truncate(endian.interpret_u32(raw.flags)),
37                reserved: 0,
38            }
39        }
40        Bitness::Bits64 => {
41            let raw: RawMachHeader64 = pod::read_pod(data, 0)?;
42            MachoHeader {
43                magic,
44                cpu_type: CpuType(endian.interpret_i32(raw.cputype)),
45                cpu_subtype: CpuSubtype(endian.interpret_i32(raw.cpusubtype)),
46                file_type: FileType::from_u32(endian.interpret_u32(raw.filetype)),
47                ncmds: endian.interpret_u32(raw.ncmds),
48                sizeofcmds: endian.interpret_u32(raw.sizeofcmds),
49                flags: MachoHeaderFlags::from_bits_truncate(endian.interpret_u32(raw.flags)),
50                reserved: endian.interpret_u32(raw.reserved),
51            }
52        }
53    };
54
55    let lc_offset = bitness.header_size();
56    let (load_commands, segments) = crate::format::load_commands::parse_load_commands_with_limits(
57        data,
58        endian,
59        lc_offset,
60        header.ncmds,
61        header.sizeofcmds,
62        limits,
63    )?;
64
65    MachoFile::new(data, header, load_commands, segments, endian, bitness)
66}