Commit 412cd789bf
Changed files (5)
lib
std
lib/std/c/darwin/x86_64.zig
@@ -31,6 +31,29 @@ pub const thread_state = extern struct {
gs: u64,
};
+const stmm_reg = [16]u8;
+const xmm_reg = [16]u8;
+pub const float_state = extern struct {
+ reserved: [2]c_int,
+ fcw: u16,
+ fsw: u16,
+ ftw: u8,
+ rsrv1: u8,
+ fop: u16,
+ ip: u32,
+ cs: u16,
+ rsrv2: u16,
+ dp: u32,
+ ds: u16,
+ rsrv3: u16,
+ mxcsr: u32,
+ mxcsrmask: u32,
+ stmm: [8]stmm_reg,
+ xmm: [16]xmm_reg,
+ rsrv4: [96]u8,
+ reserved1: c_int,
+};
+
pub const THREAD_STATE = 4;
pub const THREAD_STATE_COUNT: c.mach_msg_type_number_t = @sizeOf(thread_state) / @sizeOf(c_int);
lib/std/c/darwin.zig
@@ -148,11 +148,13 @@ pub const ucontext_t = extern struct {
link: ?*ucontext_t,
mcsize: u64,
mcontext: *mcontext_t,
+ __mcontext_data: mcontext_t,
};
pub const mcontext_t = extern struct {
es: arch_bits.exception_state,
ss: arch_bits.thread_state,
+ fs: arch_bits.float_state,
};
extern "c" fn __error() *c_int;
lib/std/dwarf/abi.zig
@@ -68,38 +68,41 @@ pub fn regBytes(ucontext_ptr: anytype, reg_number: u8, reg_ctx: ?RegisterContext
var m = &ucontext_ptr.mcontext;
return switch (builtin.cpu.arch) {
- .x86 => switch (reg_number) {
- 0 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EAX]),
- 1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ECX]),
- 2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDX]),
- 3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBX]),
- 4...5 => if (reg_ctx) |r| bytes: {
- if (reg_number == 4) {
- break :bytes if (r.eh_frame and r.is_macho)
- mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBP])
- else
- mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESP]);
- } else {
- break :bytes if (r.eh_frame and r.is_macho)
- mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESP])
- else
- mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBP]);
- }
- } else error.RegisterContextRequired,
- 6 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESI]),
- 7 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDI]),
- 8 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EIP]),
- 9 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EFL]),
- 10 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.CS]),
- 11 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.SS]),
- 12 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.DS]),
- 13 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ES]),
- 14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.FS]),
- 15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.GS]),
- 16...23 => error.InvalidRegister, // TODO: Support loading ST0-ST7 from mcontext.fpregs
- // TODO: Map TRAPNO, ERR, UESP
- 32...39 => error.InvalidRegister, // TODO: Support loading XMM0-XMM7 from mcontext.fpregs
- else => error.InvalidRegister,
+ .x86 => switch (builtin.os.tag) {
+ .linux, .netbsd, .solaris => switch (reg_number) {
+ 0 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EAX]),
+ 1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ECX]),
+ 2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDX]),
+ 3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBX]),
+ 4...5 => if (reg_ctx) |r| bytes: {
+ if (reg_number == 4) {
+ break :bytes if (r.eh_frame and r.is_macho)
+ mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBP])
+ else
+ mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESP]);
+ } else {
+ break :bytes if (r.eh_frame and r.is_macho)
+ mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESP])
+ else
+ mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBP]);
+ }
+ } else error.RegisterContextRequired,
+ 6 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESI]),
+ 7 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDI]),
+ 8 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EIP]),
+ 9 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EFL]),
+ 10 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.CS]),
+ 11 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.SS]),
+ 12 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.DS]),
+ 13 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ES]),
+ 14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.FS]),
+ 15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.GS]),
+ 16...23 => error.InvalidRegister, // TODO: Support loading ST0-ST7 from mcontext.fpregs
+ // TODO: Map TRAPNO, ERR, UESP
+ 32...39 => error.InvalidRegister, // TODO: Support loading XMM0-XMM7 from mcontext.fpregs
+ else => error.InvalidRegister,
+ },
+ else => error.UnimplementedOs,
},
.x86_64 => switch (builtin.os.tag) {
.linux, .netbsd, .solaris => switch (reg_number) {
lib/std/debug.zig
@@ -444,7 +444,10 @@ pub inline fn getContext(context: *StackTraceContext) bool {
return true;
}
- return have_getcontext and os.system.getcontext(context) == 0;
+ const result = have_getcontext and os.system.getcontext(context) == 0;
+ if (native_os == .macos) assert(context.mcsize == @sizeOf(std.c.mcontext_t));
+
+ return result;
}
pub const UnwindError = if (have_ucontext)
@@ -553,6 +556,7 @@ pub const StackIterator = struct {
if (native_os == .freestanding) return true;
const aligned_address = address & ~@as(usize, @intCast((mem.page_size - 1)));
+ if (aligned_address == 0) return false;
const aligned_memory = @as([*]align(mem.page_size) u8, @ptrFromInt(aligned_address))[0..mem.page_size];
if (native_os != .windows) {
@@ -815,11 +819,7 @@ fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usiz
pub fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void {
const module_name = debug_info.getModuleNameForAddress(address) orelse "???";
try tty_config.setColor(out_stream, .dim);
- if (err != error.MissingDebugInfo) {
- try out_stream.print("Unwind information for {s} was not available ({}), trace may be incomplete\n\n", .{ module_name, err });
- } else {
- try out_stream.print("Unwind information for {s} was not available, trace may be incomplete\n\n", .{module_name});
- }
+ try out_stream.print("Unwind information for {s} was not available ({}), trace may be incomplete\n\n", .{ module_name, err });
try tty_config.setColor(out_stream, .reset);
}
@@ -1309,6 +1309,7 @@ fn readMachODebugInfo(allocator: mem.Allocator, macho_file: File) !ModuleDebugIn
return ModuleDebugInfo{
.base_address = undefined,
+ .vmaddr_slide = undefined,
.mapped_memory = mapped_mem,
.ofiles = ModuleDebugInfo.OFileTable.init(allocator),
.symbols = symbols,
@@ -1514,11 +1515,10 @@ pub const DebugInfo = struct {
var i: u32 = 0;
while (i < image_count) : (i += 1) {
- const base_address = std.c._dyld_get_image_vmaddr_slide(i);
-
- if (address < base_address) continue;
-
const header = std.c._dyld_get_image_header(i) orelse continue;
+ const base_address = @intFromPtr(header);
+ if (address < base_address) continue;
+ const vmaddr_slide = std.c._dyld_get_image_vmaddr_slide(i);
var it = macho.LoadCommandIterator{
.ncmds = header.ncmds,
@@ -1527,14 +1527,16 @@ pub const DebugInfo = struct {
@ptrFromInt(@intFromPtr(header) + @sizeOf(macho.mach_header_64)),
)[0..header.sizeofcmds]),
};
+
while (it.next()) |cmd| switch (cmd.cmd()) {
.SEGMENT_64 => {
const segment_cmd = cmd.cast(macho.segment_command_64).?;
- const rebased_address = address - base_address;
+ if (!mem.eql(u8, "__TEXT", segment_cmd.segName())) continue;
+
+ const original_address = address - vmaddr_slide;
const seg_start = segment_cmd.vmaddr;
const seg_end = seg_start + segment_cmd.vmsize;
-
- if (rebased_address >= seg_start and rebased_address < seg_end) {
+ if (original_address >= seg_start and original_address < seg_end) {
if (self.address_map.get(base_address)) |obj_di| {
return obj_di;
}
@@ -1551,6 +1553,7 @@ pub const DebugInfo = struct {
};
obj_di.* = try readMachODebugInfo(self.allocator, macho_file);
obj_di.base_address = base_address;
+ obj_di.vmaddr_slide = vmaddr_slide;
try self.address_map.putNoClobber(base_address, obj_di);
@@ -1808,6 +1811,7 @@ pub const DebugInfo = struct {
pub const ModuleDebugInfo = switch (native_os) {
.macos, .ios, .watchos, .tvos => struct {
base_address: usize,
+ vmaddr_slide: usize,
mapped_memory: []align(mem.page_size) const u8,
symbols: []const MachoSymbol,
strings: [:0]const u8,
@@ -1972,7 +1976,7 @@ pub const ModuleDebugInfo = switch (native_os) {
} {
nosuspend {
// Translate the VA into an address into this object
- const relocated_address = address - self.base_address;
+ const relocated_address = address - self.vmaddr_slide;
// Find the .o file where this symbol is defined
const symbol = machoSearchSymbols(self.symbols, relocated_address) orelse return .{
lib/std/dwarf.zig
@@ -1705,28 +1705,53 @@ pub const DwarfInfo = struct {
if (!context.isValidMemory(context.cfa.?)) return error.InvalidCFA;
- // Update the context with the previous frame's values
- var next_ucontext = context.ucontext;
+ // Buffering the modifications is done because copying the ucontext is not portable,
+ // some implementations (ie. darwin) use internal pointers to the mcontext.
+ var arena = std.heap.ArenaAllocator.init(context.allocator);
+ defer arena.deinit();
+ const update_allocator = arena.allocator();
+
+ const RegisterUpdate = struct {
+ // Backed by ucontext
+ old_value: []u8,
+ // Backed by arena
+ new_value: []const u8,
+ prev: ?*@This(),
+ };
+ var update_tail: ?*RegisterUpdate = null;
var has_next_ip = false;
for (context.vm.rowColumns(row.*)) |column| {
if (column.register) |register| {
- const dest = try abi.regBytes(&next_ucontext, register, context.reg_ctx);
if (register == cie.return_address_register) {
has_next_ip = column.rule != .undefined;
}
+ const old_value = try abi.regBytes(&context.ucontext, register, context.reg_ctx);
+ const new_value = try update_allocator.alloc(u8, old_value.len);
+
+ const prev = update_tail;
+ update_tail = try update_allocator.create(RegisterUpdate);
+ update_tail.?.* = .{
+ .old_value = old_value,
+ .new_value = new_value,
+ .prev = prev,
+ };
+
try column.resolveValue(
context,
compile_unit,
&context.ucontext,
context.reg_ctx,
- dest,
+ new_value,
);
}
}
- context.ucontext = next_ucontext;
+ while (update_tail) |tail| {
+ @memcpy(tail.old_value, tail.new_value);
+ update_tail = tail.prev;
+ }
if (has_next_ip) {
context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, comptime abi.ipRegNum(), context.reg_ctx));