Skip to content

Macho

Description

Parsed Mach-O file. Holds the raw bytes plus decoded indices. All three MachoOpen* constructors leave the parser as the sole owner of data – see the OpenFromMemory / OpenFromMemoryCopy docs below for the L / R semantics (mirrors VecInsertL / VecInsertR).

Fields

Name Description
allocator Allocator backing data and the segments/sections/symbols vectors.
data Raw Mach-O bytes (owned).
data_size Length of data in bytes.
cputype Mach-O cputype value (e.g. 0x01000007 = x86_64, 0x0100000C = arm64).
filetype MachoType value.
uuid 16-byte UUID from LC_UUID if present.
has_uuid True iff LC_UUID was found.
segments All LC_SEGMENT_64 entries.
sections Flat list of all sections across segments.
symbols Entries from LC_SYMTAB; may be empty if stripped.

Usage example (Cross-references)

Usage examples (Cross-references)
        build_macho_blob();
    
        Macho m;
        bool      ok = MachoOpenFromMemoryCopy(&m, blob, sizeof(blob), base);
        if (!ok) {
        build_macho_blob();
    
        Macho m;
        if (!MachoOpenFromMemoryCopy(&m, blob, sizeof(blob), base)) {
            DefaultAllocatorDeinit(&alloc);
        wr_u32(&fat[0], 0xCAFEBABEu);
    
        Macho m;
        bool      ok = !MachoOpenFromMemoryCopy(&m, fat, sizeof(fat), base);
        Allocator       *base  = ALLOCATOR_OF(&alloc);
    
        Macho m;
        if (!MachoOpen(&m, path, base)) {
            DefaultAllocatorDeinit(&alloc);
        Allocator       *base  = ALLOCATOR_OF(&alloc);
    
        Macho m;
        if (!MachoOpen(&m, path, base)) {
            DefaultAllocatorDeinit(&alloc);
    
    typedef struct MachoContext {
        Macho *out;
        u32    ncmds;
        u32    sizeofcmds;
    
    static bool decode_header(MachoContext *ctx) {
        Macho *m = ctx->out;
        if (BufLength(&m->data) < MH_HEADER_64_SIZE) {
            LOG_ERROR("MachO: file too small for header");
    // MemSets the caller's view to zero. Anything that fails past the
    // snapshot cleans up via MachoDeinit -- the buffer never leaks.
    bool macho_open_from_memory(Macho *out, Buf *in) {
        if (!out || !in || !in->data || !in->allocator) {
            LOG_FATAL("MachoOpenFromMemory: NULL argument (contract violation)");
    
    // R-value form: allocate Buf, copy, hand `&copy` to the L-form.
    bool macho_open_from_memory_copy(Macho *out, const u8 *data, size data_size, Allocator *alloc) {
        if (!out || !data || !alloc) {
            LOG_FATAL("MachoOpenFromMemoryCopy: NULL argument (contract violation)");
    }
    
    bool macho_open(Macho *out, const char *path, Allocator *alloc) {
        if (!out || !path || !alloc) {
            LOG_FATAL("MachoOpen: NULL argument (contract violation)");
    }
    
    void MachoDeinit(Macho *self) {
        if (!self)
            return;
    }
    
    const MachoSection *MachoFindSection(const Macho *self, const char *segment, const char *section) {
        if (!self || !segment || !section)
            return NULL;
    // same section (or the section end). N_STAB entries are skipped:
    // stab iff any of the high three bits of n_type is set.
    const MachoSymbol *MachoResolveAddress(const Macho *self, u64 vaddr) {
        if (!self || self->symbols.length == 0)
            return NULL;
        char          *module_path;
        u64            slide;
        Macho      main;
        bool           main_open;
        Macho      dsym;
        Macho      main;
        bool           main_open;
        Macho      dsym;
        bool           dsym_open;
        DwarfFunctions fns;
        MachoSections sections;
        MachoSymbols  symbols;
    } Macho;
    
    ///
    /// TAGS: Parser, MachO, File
    ///
    bool macho_open(Macho *out, const char *path, Allocator *alloc);
    #define MachoOpen(...) MISRA_OVERLOAD(MachoOpen, __VA_ARGS__)
    #define MachoOpen_2(out, path)                                                                                         \
    /// TAGS: Parser, MachO, Memory, Ownership
    ///
    bool macho_open_from_memory(Macho *out, Buf *in);
    #define MachoOpenFromMemory(out, in) macho_open_from_memory((out), (in))
    /// TAGS: Parser, MachO, Memory, Copy
    ///
    bool macho_open_from_memory_copy(Macho *out, const u8 *data, size data_size, Allocator *alloc);
    #define MachoOpenFromMemoryCopy(...) MISRA_OVERLOAD(MachoOpenFromMemoryCopy, __VA_ARGS__)
    #define MachoOpenFromMemoryCopy_3(out, data, data_size)                                                                \
    /// and tears down the vectors. Safe on a zeroed struct.
    ///
    void MachoDeinit(Macho *self);
    
    ///
    /// absent.
    ///
    const MachoSection *MachoFindSection(const Macho *self, const char *segment, const char *section);
    
    ///
    /// FAILURE : Returns NULL.
    ///
    const MachoSymbol *MachoResolveAddress(const Macho *self, u64 vaddr);
    
    #endif // MISRA_PARSERS_MACHO_H
Last updated on