authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-07 10:13:48-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:15-04:00
log5c0d4cef1afda3e01bded01636ef71846522909b
treee93d46ed7db47bca7c8a3b89de18dcf55bdd6313
parent463bbe7807b236e6e3493fb8551c585620ae266b

debug: add dupeContext, store a pointer to a copy of ThreadContext on UnwindContext


4 files changed, 33 insertions(+), 14 deletions(-)

lib/std/debug.zig+16
...@@ -133,6 +133,9 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {...@@ -133,6 +133,9 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
133 }133 }
134}134}
135135
136/// Platform-specific thread state. This contains register state, and on some platforms
137/// information about the stack. This is not safe to trivially copy, because some platforms
138/// use internal pointers within this structure. To make a copy, use `dupeContext`.
136pub const ThreadContext = blk: {139pub const ThreadContext = blk: {
137 if (native_os == .windows) {140 if (native_os == .windows) {
138 break :blk std.os.windows.CONTEXT;141 break :blk std.os.windows.CONTEXT;
...@@ -457,6 +460,19 @@ pub inline fn getContext(context: *ThreadContext) bool {...@@ -457,6 +460,19 @@ pub inline fn getContext(context: *ThreadContext) bool {
457 return result;460 return result;
458}461}
459462
463pub fn dupeContext(source: *const ThreadContext, dest: *ThreadContext) void {
464 if (native_os == .windows) dest.* = source.*;
465 if (!have_ucontext) return {};
466
467 return switch (native_os) {
468 .macos => {
469 dest.* = source.*;
470 dest.mcontext = &dest.__mcontext_data;
471 },
472 else => dest.* = source.*,
473 };
474}
475
460pub const UnwindError = if (have_ucontext)476pub const UnwindError = if (have_ucontext)
461 @typeInfo(@typeInfo(@TypeOf(StackIterator.next_dwarf)).Fn.return_type.?).ErrorUnion.error_set477 @typeInfo(@typeInfo(@TypeOf(StackIterator.next_dwarf)).Fn.return_type.?).ErrorUnion.error_set
462else478else
lib/std/dwarf.zig+11-10
...@@ -1676,7 +1676,7 @@ pub const DwarfInfo = struct {...@@ -1676,7 +1676,7 @@ pub const DwarfInfo = struct {
1676 var expression_context = .{1676 var expression_context = .{
1677 .isValidMemory = context.isValidMemory,1677 .isValidMemory = context.isValidMemory,
1678 .compile_unit = di.findCompileUnit(fde.pc_begin) catch null,1678 .compile_unit = di.findCompileUnit(fde.pc_begin) catch null,
1679 .thread_context = &context.thread_context,1679 .thread_context = context.thread_context,
1680 .reg_context = context.reg_context,1680 .reg_context = context.reg_context,
1681 .cfa = context.cfa,1681 .cfa = context.cfa,
1682 };1682 };
...@@ -1690,7 +1690,7 @@ pub const DwarfInfo = struct {...@@ -1690,7 +1690,7 @@ pub const DwarfInfo = struct {
1690 context.cfa = switch (row.cfa.rule) {1690 context.cfa = switch (row.cfa.rule) {
1691 .val_offset => |offset| blk: {1691 .val_offset => |offset| blk: {
1692 const register = row.cfa.register orelse return error.InvalidCFARule;1692 const register = row.cfa.register orelse return error.InvalidCFARule;
1693 const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.thread_context, register, context.reg_context));1693 const value = mem.readIntSliceNative(usize, try abi.regBytes(context.thread_context, register, context.reg_context));
1694 break :blk try call_frame.applyOffset(value, offset);1694 break :blk try call_frame.applyOffset(value, offset);
1695 },1695 },
1696 .expression => |expression| blk: {1696 .expression => |expression| blk: {
...@@ -1733,7 +1733,7 @@ pub const DwarfInfo = struct {...@@ -1733,7 +1733,7 @@ pub const DwarfInfo = struct {
1733 has_next_ip = column.rule != .undefined;1733 has_next_ip = column.rule != .undefined;
1734 }1734 }
17351735
1736 const old_value = try abi.regBytes(&context.thread_context, register, context.reg_context);1736 const old_value = try abi.regBytes(context.thread_context, register, context.reg_context);
1737 const new_value = try update_allocator.alloc(u8, old_value.len);1737 const new_value = try update_allocator.alloc(u8, old_value.len);
17381738
1739 const prev = update_tail;1739 const prev = update_tail;
...@@ -1758,12 +1758,12 @@ pub const DwarfInfo = struct {...@@ -1758,12 +1758,12 @@ pub const DwarfInfo = struct {
1758 }1758 }
17591759
1760 if (has_next_ip) {1760 if (has_next_ip) {
1761 context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.thread_context, comptime abi.ipRegNum(), context.reg_context));1761 context.pc = mem.readIntSliceNative(usize, try abi.regBytes(context.thread_context, comptime abi.ipRegNum(), context.reg_context));
1762 } else {1762 } else {
1763 context.pc = 0;1763 context.pc = 0;
1764 }1764 }
17651765
1766 mem.writeIntSliceNative(usize, try abi.regBytes(&context.thread_context, abi.spRegNum(context.reg_context), context.reg_context), context.cfa.?);1766 mem.writeIntSliceNative(usize, try abi.regBytes(context.thread_context, abi.spRegNum(context.reg_context), context.reg_context), context.cfa.?);
17671767
1768 // The call instruction will have pushed the address of the instruction that follows the call as the return address1768 // The call instruction will have pushed the address of the instruction that follows the call as the return address
1769 // However, this return address may be past the end of the function if the caller was `noreturn`.1769 // 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 {...@@ -1779,7 +1779,7 @@ pub const UnwindContext = struct {
1779 allocator: mem.Allocator,1779 allocator: mem.Allocator,
1780 cfa: ?usize,1780 cfa: ?usize,
1781 pc: usize,1781 pc: usize,
1782 thread_context: debug.ThreadContext,1782 thread_context: *debug.ThreadContext,
1783 reg_context: abi.RegisterContext,1783 reg_context: abi.RegisterContext,
1784 isValidMemory: *const fn (address: usize) bool,1784 isValidMemory: *const fn (address: usize) bool,
1785 vm: call_frame.VirtualMachine = .{},1785 vm: call_frame.VirtualMachine = .{},
...@@ -1788,14 +1788,14 @@ pub const UnwindContext = struct {...@@ -1788,14 +1788,14 @@ pub const UnwindContext = struct {
1788 pub fn init(allocator: mem.Allocator, thread_context: *const debug.ThreadContext, isValidMemory: *const fn (address: usize) bool) !UnwindContext {1788 pub fn init(allocator: mem.Allocator, thread_context: *const debug.ThreadContext, isValidMemory: *const fn (address: usize) bool) !UnwindContext {
1789 const pc = mem.readIntSliceNative(usize, try abi.regBytes(thread_context, abi.ipRegNum(), null));1789 const pc = mem.readIntSliceNative(usize, try abi.regBytes(thread_context, abi.ipRegNum(), null));
17901790
1791 if (builtin.os.tag == .macos) @compileError("Fix below TODO");1791 const context_copy = try allocator.create(debug.ThreadContext);
1792 debug.dupeContext(thread_context, context_copy);
17921793
1793 return .{1794 return .{
1794 .allocator = allocator,1795 .allocator = allocator,
1795 .cfa = null,1796 .cfa = null,
1796 .pc = pc,1797 .pc = pc,
1797 // TODO: This is broken on macos, need a function that knows how to copy the OSs mcontext properly1798 .thread_context = context_copy,
1798 .thread_context = thread_context.*,
1799 .reg_context = undefined,1799 .reg_context = undefined,
1800 .isValidMemory = isValidMemory,1800 .isValidMemory = isValidMemory,
1801 };1801 };
...@@ -1804,10 +1804,11 @@ pub const UnwindContext = struct {...@@ -1804,10 +1804,11 @@ pub const UnwindContext = struct {
1804 pub fn deinit(self: *UnwindContext) void {1804 pub fn deinit(self: *UnwindContext) void {
1805 self.vm.deinit(self.allocator);1805 self.vm.deinit(self.allocator);
1806 self.stack_machine.deinit(self.allocator);1806 self.stack_machine.deinit(self.allocator);
1807 self.allocator.destroy(self.thread_context);
1807 }1808 }
18081809
1809 pub fn getFp(self: *const UnwindContext) !usize {1810 pub fn getFp(self: *const UnwindContext) !usize {
1810 return mem.readIntSliceNative(usize, try abi.regBytes(&self.thread_context, abi.fpRegNum(self.reg_context), self.reg_context));1811 return mem.readIntSliceNative(usize, try abi.regBytes(self.thread_context, abi.fpRegNum(self.reg_context), self.reg_context));
1811 }1812 }
1812};1813};
18131814
lib/std/dwarf/call_frame.zig+2-2
...@@ -315,9 +315,9 @@ pub const VirtualMachine = struct {...@@ -315,9 +315,9 @@ pub const VirtualMachine = struct {
315 } else return error.InvalidCFA;315 } else return error.InvalidCFA;
316 },316 },
317 .register => |register| {317 .register => |register| {
318 const src = try abi.regBytes(&context.thread_context, register, context.reg_context);318 const src = try abi.regBytes(context.thread_context, register, context.reg_context);
319 if (src.len != out.len) return error.RegisterTypeMismatch;319 if (src.len != out.len) return error.RegisterTypeMismatch;
320 @memcpy(out, try abi.regBytes(&context.thread_context, register, context.reg_context));320 @memcpy(out, try abi.regBytes(context.thread_context, register, context.reg_context));
321 },321 },
322 .expression => |expression| {322 .expression => |expression| {
323 context.stack_machine.reset();323 context.stack_machine.reset();
lib/std/dwarf/expressions.zig+4-2
...@@ -1070,8 +1070,10 @@ test "DWARF expressions" {...@@ -1070,8 +1070,10 @@ test "DWARF expressions" {
1070 }1070 }
10711071
1072 // Register values1072 // Register values
1073 var thread_context: std.debug.ThreadContext = undefined;1073 if (@TypeOf(std.debug.ThreadContext) != void) {
1074 if (std.debug.getContext(&thread_context)) {1074 var thread_context: std.debug.ThreadContext = undefined;
1075 _ = thread_context;
1076
1075 // TODO: Test fbreg, breg0..31, bregx, regval_type1077 // TODO: Test fbreg, breg0..31, bregx, regval_type
1076 }1078 }
1077}1079}