Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

Module

MachO.Module
const Module = struct

File

Code

const Module = struct {
    text_base: usize,
    unwind: ?(Error!Unwind),
    file: ?(Error!MachOFile),

    const Adapter = struct {
        pub fn hash(_: Adapter, text_base: usize) u32 {
            return @truncate(std.hash.int(text_base));
        }
        pub fn eql(_: Adapter, a_text_base: usize, b_module: Module, b_index: usize) bool {
            _ = b_index;
            return a_text_base == b_module.text_base;
        }
    };
    const Context = struct {
        pub fn hash(_: Context, module: Module) u32 {
            return @truncate(std.hash.int(module.text_base));
        }
        pub fn eql(_: Context, a_module: Module, b_module: Module, b_index: usize) bool {
            _ = b_index;
            return a_module.text_base == b_module.text_base;
        }
    };

    const Unwind = struct {
        /// The slide applied to the `__unwind_info` and `__eh_frame` sections.
        /// So, `unwind_info.ptr` is this many bytes higher than the section's vmaddr.
        vmaddr_slide: u64,
        /// Backed by the in-memory section mapped by the loader.
        unwind_info: ?[]const u8,
        /// Backed by the in-memory `__eh_frame` section mapped by the loader.
        dwarf: ?Dwarf.Unwind,
    };

    fn getUnwindInfo(module: *Module, gpa: Allocator) Error!*Unwind {
        if (module.unwind == null) module.unwind = loadUnwindInfo(module, gpa);
        return if (module.unwind.?) |*unwind| unwind else |err| err;
    }
    fn loadUnwindInfo(module: *const Module, gpa: Allocator) Error!Unwind {
        const header: *std.macho.mach_header_64 = @ptrFromInt(module.text_base);

        const raw_macho: [*]u8 = @ptrCast(header);
        var it = macho.LoadCommandIterator.init(header, raw_macho[@sizeOf(macho.mach_header_64)..][0..header.sizeofcmds]) catch unreachable;
        const sections, const text_vmaddr = while (it.next() catch unreachable) |load_cmd| {
            if (load_cmd.hdr.cmd != .SEGMENT_64) continue;
            const segment_cmd = load_cmd.cast(macho.segment_command_64).?;
            if (!mem.eql(u8, segment_cmd.segName(), "__TEXT")) continue;
            break .{ load_cmd.getSections(), segment_cmd.vmaddr };
        } else unreachable;

        const vmaddr_slide = module.text_base - text_vmaddr;

        var opt_unwind_info: ?[]const u8 = null;
        var opt_eh_frame: ?[]const u8 = null;
        for (sections) |sect| {
            if (mem.eql(u8, sect.sectName(), "__unwind_info")) {
                const sect_ptr: [*]u8 = @ptrFromInt(@as(usize, @intCast(vmaddr_slide + sect.addr)));
                opt_unwind_info = sect_ptr[0..@intCast(sect.size)];
            } else if (mem.eql(u8, sect.sectName(), "__eh_frame")) {
                const sect_ptr: [*]u8 = @ptrFromInt(@as(usize, @intCast(vmaddr_slide + sect.addr)));
                opt_eh_frame = sect_ptr[0..@intCast(sect.size)];
            }
        }
        const eh_frame = opt_eh_frame orelse return .{
            .vmaddr_slide = vmaddr_slide,
            .unwind_info = opt_unwind_info,
            .dwarf = null,
        };
        var dwarf: Dwarf.Unwind = .initSection(.eh_frame, @intFromPtr(eh_frame.ptr) - vmaddr_slide, eh_frame);
        errdefer dwarf.deinit(gpa);
        // We don't need lookups, so this call is just for scanning CIEs.
        dwarf.prepare(gpa, @sizeOf(usize), native_endian, false, true) catch |err| switch (err) {
            error.ReadFailed => unreachable, // it's all fixed buffers
            error.InvalidDebugInfo,
            error.MissingDebugInfo,
            error.OutOfMemory,
            => |e| return e,
            error.EndOfStream,
            error.Overflow,
            error.StreamTooLong,
            error.InvalidOperand,
            error.InvalidOpcode,
            error.InvalidOperation,
            => return error.InvalidDebugInfo,
            error.UnsupportedAddrSize,
            error.UnsupportedDwarfVersion,
            error.UnimplementedUserOpcode,
            => return error.UnsupportedDebugInfo,
        };

        return .{
            .vmaddr_slide = vmaddr_slide,
            .unwind_info = opt_unwind_info,
            .dwarf = dwarf,
        };
    }

    fn getFile(module: *Module, gpa: Allocator, io: Io) Error!*MachOFile {
        if (module.file == null) {
            const path = getModuleNameInner(module.text_base).?;
            module.file = MachOFile.load(gpa, io, path, builtin.cpu.arch) catch |err| switch (err) {
                error.InvalidMachO, error.InvalidDwarf => error.InvalidDebugInfo,
                error.MissingDebugInfo, error.OutOfMemory, error.UnsupportedDebugInfo, error.ReadFailed => |e| e,
            };
        }
        return if (module.file.?) |*f| f else |err| err;
    }
}