Commit 5c0d4cef1a
Changed files (4)
lib
lib/std/dwarf/call_frame.zig
@@ -315,9 +315,9 @@ pub const VirtualMachine = struct {
} else return error.InvalidCFA;
},
.register => |register| {
- const src = try abi.regBytes(&context.thread_context, register, context.reg_context);
+ const src = try abi.regBytes(context.thread_context, register, context.reg_context);
if (src.len != out.len) return error.RegisterTypeMismatch;
- @memcpy(out, try abi.regBytes(&context.thread_context, register, context.reg_context));
+ @memcpy(out, try abi.regBytes(context.thread_context, register, context.reg_context));
},
.expression => |expression| {
context.stack_machine.reset();
lib/std/dwarf/expressions.zig
@@ -1070,8 +1070,10 @@ test "DWARF expressions" {
}
// Register values
- var thread_context: std.debug.ThreadContext = undefined;
- if (std.debug.getContext(&thread_context)) {
+ if (@TypeOf(std.debug.ThreadContext) != void) {
+ var thread_context: std.debug.ThreadContext = undefined;
+ _ = thread_context;
+
// TODO: Test fbreg, breg0..31, bregx, regval_type
}
}
lib/std/debug.zig
@@ -133,6 +133,9 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
}
}
+/// Platform-specific thread state. This contains register state, and on some platforms
+/// information about the stack. This is not safe to trivially copy, because some platforms
+/// use internal pointers within this structure. To make a copy, use `dupeContext`.
pub const ThreadContext = blk: {
if (native_os == .windows) {
break :blk std.os.windows.CONTEXT;
@@ -457,6 +460,19 @@ pub inline fn getContext(context: *ThreadContext) bool {
return result;
}
+pub fn dupeContext(source: *const ThreadContext, dest: *ThreadContext) void {
+ if (native_os == .windows) dest.* = source.*;
+ if (!have_ucontext) return {};
+
+ return switch (native_os) {
+ .macos => {
+ dest.* = source.*;
+ dest.mcontext = &dest.__mcontext_data;
+ },
+ else => dest.* = source.*,
+ };
+}
+
pub const UnwindError = if (have_ucontext)
@typeInfo(@typeInfo(@TypeOf(StackIterator.next_dwarf)).Fn.return_type.?).ErrorUnion.error_set
else
lib/std/dwarf.zig
@@ -1676,7 +1676,7 @@ pub const DwarfInfo = struct {
var expression_context = .{
.isValidMemory = context.isValidMemory,
.compile_unit = di.findCompileUnit(fde.pc_begin) catch null,
- .thread_context = &context.thread_context,
+ .thread_context = context.thread_context,
.reg_context = context.reg_context,
.cfa = context.cfa,
};
@@ -1690,7 +1690,7 @@ pub const DwarfInfo = struct {
context.cfa = switch (row.cfa.rule) {
.val_offset => |offset| blk: {
const register = row.cfa.register orelse return error.InvalidCFARule;
- const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.thread_context, register, context.reg_context));
+ const value = mem.readIntSliceNative(usize, try abi.regBytes(context.thread_context, register, context.reg_context));
break :blk try call_frame.applyOffset(value, offset);
},
.expression => |expression| blk: {
@@ -1733,7 +1733,7 @@ pub const DwarfInfo = struct {
has_next_ip = column.rule != .undefined;
}
- const old_value = try abi.regBytes(&context.thread_context, register, context.reg_context);
+ const old_value = try abi.regBytes(context.thread_context, register, context.reg_context);
const new_value = try update_allocator.alloc(u8, old_value.len);
const prev = update_tail;
@@ -1758,12 +1758,12 @@ pub const DwarfInfo = struct {
}
if (has_next_ip) {
- context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.thread_context, comptime abi.ipRegNum(), context.reg_context));
+ context.pc = mem.readIntSliceNative(usize, try abi.regBytes(context.thread_context, comptime abi.ipRegNum(), context.reg_context));
} else {
context.pc = 0;
}
- mem.writeIntSliceNative(usize, try abi.regBytes(&context.thread_context, abi.spRegNum(context.reg_context), context.reg_context), context.cfa.?);
+ mem.writeIntSliceNative(usize, try abi.regBytes(context.thread_context, abi.spRegNum(context.reg_context), context.reg_context), context.cfa.?);
// The call instruction will have pushed the address of the instruction that follows the call as the return address
// However, this return address may be past the end of the function if the caller was `noreturn`.
@@ -1779,7 +1779,7 @@ pub const UnwindContext = struct {
allocator: mem.Allocator,
cfa: ?usize,
pc: usize,
- thread_context: debug.ThreadContext,
+ thread_context: *debug.ThreadContext,
reg_context: abi.RegisterContext,
isValidMemory: *const fn (address: usize) bool,
vm: call_frame.VirtualMachine = .{},
@@ -1788,14 +1788,14 @@ pub const UnwindContext = struct {
pub fn init(allocator: mem.Allocator, thread_context: *const debug.ThreadContext, isValidMemory: *const fn (address: usize) bool) !UnwindContext {
const pc = mem.readIntSliceNative(usize, try abi.regBytes(thread_context, abi.ipRegNum(), null));
- if (builtin.os.tag == .macos) @compileError("Fix below TODO");
+ const context_copy = try allocator.create(debug.ThreadContext);
+ debug.dupeContext(thread_context, context_copy);
return .{
.allocator = allocator,
.cfa = null,
.pc = pc,
- // TODO: This is broken on macos, need a function that knows how to copy the OSs mcontext properly
- .thread_context = thread_context.*,
+ .thread_context = context_copy,
.reg_context = undefined,
.isValidMemory = isValidMemory,
};
@@ -1804,10 +1804,11 @@ pub const UnwindContext = struct {
pub fn deinit(self: *UnwindContext) void {
self.vm.deinit(self.allocator);
self.stack_machine.deinit(self.allocator);
+ self.allocator.destroy(self.thread_context);
}
pub fn getFp(self: *const UnwindContext) !usize {
- return mem.readIntSliceNative(usize, try abi.regBytes(&self.thread_context, abi.fpRegNum(self.reg_context), self.reg_context));
+ return mem.readIntSliceNative(usize, try abi.regBytes(self.thread_context, abi.fpRegNum(self.reg_context), self.reg_context));
}
};