From 5c0d4cef1afda3e01bded01636ef71846522909b Mon Sep 17 00:00:00 2001 From: kcbanner Date: Fri, 7 Jul 2023 10:13:48 -0400 Subject: [PATCH] debug: add dupeContext, store a pointer to a copy of ThreadContext on UnwindContext --- lib/std/debug.zig | 16 ++++++++++++++++ lib/std/dwarf.zig | 21 +++++++++++---------- lib/std/dwarf/call_frame.zig | 4 ++-- lib/std/dwarf/expressions.zig | 6 ++++-- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 7fac160855..7e26b6a4b0 100644 --- a/lib/std/debug.zig +++ b/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 diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig index 0909b6eafb..4b4b0587d5 100644 --- a/lib/std/dwarf.zig +++ b/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)); } }; diff --git a/lib/std/dwarf/call_frame.zig b/lib/std/dwarf/call_frame.zig index 49772e2ae5..c2c95b8104 100644 --- a/lib/std/dwarf/call_frame.zig +++ b/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(); diff --git a/lib/std/dwarf/expressions.zig b/lib/std/dwarf/expressions.zig index 98b06c0cd8..8f07b6f500 100644 --- a/lib/std/dwarf/expressions.zig +++ b/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 } }