aboutsummaryrefslogtreecommitdiff
path: root/src/link/MachO/fat.zig
blob: bc896704b88000bcb25ebbbda9a52318b1e92765 (plain)
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
pub fn isFatLibrary(file: std.fs.File) bool {
    const reader = file.reader();
    const hdr = reader.readStructBig(macho.fat_header) catch return false;
    defer file.seekTo(0) catch {};
    return hdr.magic == macho.FAT_MAGIC;
}

pub const Arch = struct {
    tag: std.Target.Cpu.Arch,
    offset: u64,
};

/// Caller owns the memory.
pub fn parseArchs(gpa: Allocator, file: std.fs.File) ![]const Arch {
    const reader = file.reader();
    const fat_header = try reader.readStructBig(macho.fat_header);
    assert(fat_header.magic == macho.FAT_MAGIC);

    var archs = try std.ArrayList(Arch).initCapacity(gpa, fat_header.nfat_arch);
    defer archs.deinit();

    var fat_arch_index: u32 = 0;
    while (fat_arch_index < fat_header.nfat_arch) : (fat_arch_index += 1) {
        const fat_arch = try reader.readStructBig(macho.fat_arch);
        // If we come across an architecture that we do not know how to handle, that's
        // fine because we can keep looking for one that might match.
        const arch: std.Target.Cpu.Arch = switch (fat_arch.cputype) {
            macho.CPU_TYPE_ARM64 => if (fat_arch.cpusubtype == macho.CPU_SUBTYPE_ARM_ALL) .aarch64 else continue,
            macho.CPU_TYPE_X86_64 => if (fat_arch.cpusubtype == macho.CPU_SUBTYPE_X86_64_ALL) .x86_64 else continue,
            else => continue,
        };

        archs.appendAssumeCapacity(.{ .tag = arch, .offset = fat_arch.offset });
    }

    return archs.toOwnedSlice();
}

const std = @import("std");
const assert = std.debug.assert;
const log = std.log.scoped(.archive);
const macho = std.macho;
const mem = std.mem;
const Allocator = mem.Allocator;