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 |
|---|---|
data |
Raw Mach-O bytes as a Buf (owned). Carries its own length and allocator – read via BufLength / BufData / BufAllocator. |
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)
- In
MachoCache.h:34:
Str module_path;
u64 slide;
Macho main;
bool main_open;
Macho dsym;- In
MachoCache.h:36:
Macho main;
bool main_open;
Macho dsym;
bool dsym_open;
DwarfFunctions fns;- In
MachO.h:113:
MachoSections sections;
MachoSymbols symbols;
} Macho;
///
- In
MachO.h:193:
/// TAGS: Parser, MachO, Memory, Ownership
///
bool MachoOpenFromMemory(Macho *out, Buf *in);
///
- In
MachO.h:224:
/// TAGS: Parser, MachO, Deinit, Lifecycle
///
void MachoDeinit(Macho *self);
///
- In
MachO.h:255:
/// TAGS: Parser, MachO, Symbol, Resolve
///
const MachoSymbol *MachoResolveAddress(const Macho *self, u64 vaddr);
#endif // MISRA_PARSERS_MACHO_H
- In
MachO.c:108:
typedef struct MachoContext {
Macho *out;
u32 ncmds;
u32 sizeofcmds;- In
MachO.c:119:
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");- In
MachO.c:419:
// MemSets the caller's view to zero. Anything that fails past the
// snapshot cleans up via MachoDeinit -- the buffer never leaks.
bool MachoOpenFromMemory(Macho *out, Buf *in) {
if (!out || !in || !BufData(in) || !BufAllocator(in)) {
LOG_FATAL("MachoOpenFromMemory: NULL argument (contract violation)");- In
MachO.c:447:
// R-value form: allocate Buf, copy, hand `©` 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)");- In
MachO.c:461:
}
bool macho_open(Macho *out, Zstr path, Allocator *alloc) {
if (!out || !path || !alloc) {
LOG_FATAL("MachoOpen: NULL argument (contract violation)");- In
MachO.c:474:
}
void MachoDeinit(Macho *self) {
if (!self)
return;- In
MachO.c:484:
}
const MachoSection *macho_find_section(const Macho *self, Zstr segment, Zstr section) {
if (!self || !segment || !section)
return NULL;- In
MachO.c:500:
// 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 || VecLen(&self->symbols) == 0)
return NULL;- In
MachO.c:226:
// Open helper. Returns true if opened; *out filled. Caller must
// MachoDeinit on success.
static bool open_blob(Macho *out, const u8 *bytes, u32 len, DefaultAllocator *alloc) {
return MachoOpenFromMemoryCopy(out, bytes, len, ALLOCATOR_OF(alloc));
}- In
MachO.c:351:
build_macho_blob();
Macho m;
bool ok = MachoOpenFromMemoryCopy(&m, blob, sizeof(blob), base);
if (!ok) {- In
MachO.c:380:
build_macho_blob();
Macho m;
if (!MachoOpenFromMemoryCopy(&m, blob, sizeof(blob), base)) {
DefaultAllocatorDeinit(&alloc);- In
MachO.c:411:
wr_u32(&fat[0], 0xCAFEBABEu);
Macho m;
bool ok = !MachoOpenFromMemoryCopy(&m, fat, sizeof(fat), base);- In
MachO.c:428:
build_macho_blob();
Macho m;
if (!MachoOpenFromMemoryCopy(&m, blob, sizeof(blob), base)) {
DefaultAllocatorDeinit(&alloc);- In
MachO.c:449:
static bool macho_rejects(const u8 *bytes, u64 len) {
DefaultAllocator alloc = DefaultAllocatorInit();
Macho m;
bool opened = MachoOpenFromMemoryCopy(&m, bytes, len, ALLOCATOR_OF(&alloc));
if (opened)- In
MachO.c:527:
build_two_symbol_blob();
Macho m;
if (!MachoOpenFromMemoryCopy(&m, two_blob, sizeof(two_blob), base)) {
DefaultAllocatorDeinit(&alloc);- In
MachO.c:576:
Allocator *base = ALLOCATOR_OF(&alloc);
Macho m;
if (!MachoOpen(&m, path, base)) {
DefaultAllocatorDeinit(&alloc);- In
MachO.c:610:
Allocator *base = ALLOCATOR_OF(&alloc);
Macho m;
if (!MachoOpen(&m, path, base)) {
DefaultAllocatorDeinit(&alloc);- In
MachO.c:654:
MemCopy(&b[cfg.stroff + 1], nm, sizeof(nm));
Macho m;
bool ok = open_blob(&m, b, BUF, &alloc);
ok = ok && VecLen(&m.symbols) == 1;- In
MachO.c:678:
build_scaffold(b, &cfg);
Macho m;
bool ok = open_blob(&m, b, BUF, &alloc);
ok = ok && m.has_uuid && MemCompare(m.uuid, kUuid, 16) == 0;- In
MachO.c:711:
MemCopy(&b[stroff + 7], "beta", 5); // includes NUL at stroff+11
Macho m;
bool ok = open_blob(&m, b, BUF, &alloc);
ok = ok && VecLen(&m.symbols) == 2;- In
MachO.c:743:
MemCopy(&b[cfg.stroff + 1], "z", 2);
Macho m;
bool ok = open_blob(&m, b, BUF, &alloc);
ok = ok && VecLen(&m.symbols) == 1 && VecPtrAt(&m.symbols, 0)->section_index == 5;- In
MachO.c:773:
MemCopy(&b[stroff + 1], "fit", 4);
Macho m;
bool ok = open_blob(&m, b, BUF, &alloc); // real: accepts
ok = ok && VecLen(&m.symbols) == 1 && ZstrCompare(VecPtrAt(&m.symbols, 0)->name, "fit") == 0;- In
MachO.c:800:
MemCopy(&b[stroff + 1], "edge", 5);
Macho m;
bool ok = open_blob(&m, b, BUF, &alloc);
ok = ok && VecLen(&m.symbols) == 1 && ZstrCompare(VecPtrAt(&m.symbols, 0)->name, "edge") == 0;- In
MachO.c:834:
MemCopy(&b[stroff + 1], "sym", 4);
Macho m;
bool ok = open_blob(&m, b, BUF, &alloc); // real accepts
ok = ok && VecLen(&m.symbols) == NSY;- In
MachO.c:868:
MemCopy(&b[stroff + 1], "ovr", 4);
Macho m;
bool opened = open_blob(&m, b, BUF, &alloc);
if (opened)- In
MachO.c:891:
build_scaffold(b, &cfg); // symoff + 100*16 = 0x100 + 0x640 >> 320 -> overrun
Macho m;
bool opened = open_blob(&m, b, BUF, &alloc);
if (opened)- In
MachO.c:925:
b[stroff] = 0x41; // ensure byte0 non-zero too
Macho m;
bool ok = open_blob(&m, b, BUF, &alloc);
ok = ok && VecLen(&m.symbols) == 0; // real: symbol skipped
- In
MachO.c:955:
b[stroff + strsize] = 0x00; // the off-by-one byte is NUL
Macho m;
bool ok = open_blob(&m, b, BUF, &alloc);
ok = ok && VecLen(&m.symbols) == 0; // real: skipped (no NUL in range)
- In
MachO.c:989:
b[stroff + n_strx + 2] = 0x00; // forward NUL terminator
Macho m;
bool ok = open_blob(&m, b, BUF, &alloc);
ok = ok && VecLen(&m.symbols) == 1; // real: forward scan finds NUL
- In
MachO.c:1011:
build_scaffold(b, &cfg);
Macho m;
bool ok = open_blob(&m, b, BUF, &alloc);
if (!ok) {- In
MachO.c:1099:
MemCopy(&uc[8], kUuid, 16);
Macho m;
bool ok = open_blob(&m, b, BUF, &alloc);
ok = ok && VecLen(&m.sections) == 2;- In
MachO.c:1126:
put_header(buf, 0, 0); // ncmds = 0, sizeofcmds = 0
Macho m;
bool ok = MachoOpenFromMemoryCopy(&m, buf, sizeof(buf), base);
ok = ok && VecLen(&m.segments) == 0 && VecLen(&m.sections) == 0;- In
MachO.c:1162:
wr_u32(&seg[68], 0); // flags
Macho m;
bool ok = MachoOpenFromMemoryCopy(&m, buf, sizeof(buf), base);
ok = ok && VecLen(&m.segments) == 1 && VecLen(&m.sections) == 0;- In
MachO.c:1194:
wr_u32(&seg[64], 0); // nsects == 0
Macho m;
bool ok = MachoOpenFromMemoryCopy(&m, buf, sizeof(buf), base);
ok = ok && VecLen(&m.segments) == 1;- In
MachO.c:1215:
u64 len = build_seg_with_sections(buf, 2);
Macho m;
bool ok = MachoOpenFromMemoryCopy(&m, buf, len, base);
ok = ok && VecLen(&m.segments) == 1 && VecLen(&m.sections) == 2;- In
MachO.c:1256:
wr_u64(&sec[40], 0x100); // size
Macho m;
bool ok = MachoOpenFromMemoryCopy(&m, buf, sizeof(buf), base);
ok = ok && VecLen(&m.sections) == 1;- In
MachO.c:1287:
wr_u32(&seg[64], 0); // nsects == 0
Macho m;
bool ok = MachoOpenFromMemoryCopy(&m, buf, sizeof(buf), base);
ok = ok && VecLen(&m.segments) == 1;- In
MachO.c:1318:
wr_u32(&lc[4], 8); // cmdsize == 8 (minimum); remaining == 8 here
Macho m;
bool ok = MachoOpenFromMemoryCopy(&m, buf, sizeof(buf), base);
ok = ok && VecLen(&m.segments) == 0 && VecLen(&m.sections) == 0;- In
MachO.c:1342:
u64 len = build_symbol_blob(values, 2);
Macho m;
if (!MachoOpenFromMemoryCopy(&m, g_symblob, len, base)) {
DefaultAllocatorDeinit(&alloc);- In
MachO.c:1382:
g_symblob[nlist_off + 1 * NLIST64_SIZE + 5] = 2; // second -> n_sect 2
Macho m;
if (!MachoOpenFromMemoryCopy(&m, g_symblob, len, base)) {
DefaultAllocatorDeinit(&alloc);- In
MachO.c:1427:
bool ok = (wrote == (i64)sizeof(buf));
Macho m;
bool opened = MachoOpen(&m, &path, base);
ok = ok && opened && VecLen(&m.segments) == 1;- In
MachO.c:1464:
bool ok = (wrote == (i64)sizeof(garbage));
Macho m;
bool opened = MachoOpen(&m, &path, base);
if (opened)- In
MachO.c:1499:
wr_u32(&lc[4], 0x1000); // cmdsize far exceeds remaining -> reject
Macho m;
bool opened = MachoOpenFromMemoryCopy(&m, buf, sizeof(buf), base);
if (opened)- In
MachO.c:1547:
MemCopy(&uc[8], kUuid, 16);
Macho m;
bool ok = MachoOpenFromMemoryCopy(&m, b, BUF, base);
// Canonical-true check: real code stores exactly `true` (== 1); the
Last updated on