feature. See also
. The project being documented here (as the example) is the Zig library itself.
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 {
vmaddr_slide: u64,
unwind_info: ?[]const u8,
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);
dwarf.prepare(gpa, @sizeOf(usize), native_endian, false, true) catch |err| switch (err) {
error.ReadFailed => unreachable,
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;
}
}