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 {
133133 }
134134}
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`.
136139pub const ThreadContext = blk: {
137140 if (native_os == .windows) {
138141 break :blk std.os.windows.CONTEXT;
......@@ -457,6 +460,19 @@ pub inline fn getContext(context: *ThreadContext) bool {
457460 return result;
458461}
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
460476pub const UnwindError = if (have_ucontext)
461477 @typeInfo(@typeInfo(@TypeOf(StackIterator.next_dwarf)).Fn.return_type.?).ErrorUnion.error_set
462478else
lib/std/dwarf.zig+11-10
......@@ -1676,7 +1676,7 @@ pub const DwarfInfo = struct {
16761676 var expression_context = .{
16771677 .isValidMemory = context.isValidMemory,
16781678 .compile_unit = di.findCompileUnit(fde.pc_begin) catch null,
1679 .thread_context = &context.thread_context,
1679 .thread_context = context.thread_context,
16801680 .reg_context = context.reg_context,
16811681 .cfa = context.cfa,
16821682 };
......@@ -1690,7 +1690,7 @@ pub const DwarfInfo = struct {
16901690 context.cfa = switch (row.cfa.rule) {
16911691 .val_offset => |offset| blk: {
16921692 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));
16941694 break :blk try call_frame.applyOffset(value, offset);
16951695 },
16961696 .expression => |expression| blk: {
......@@ -1733,7 +1733,7 @@ pub const DwarfInfo = struct {
17331733 has_next_ip = column.rule != .undefined;
17341734 }
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);
17371737 const new_value = try update_allocator.alloc(u8, old_value.len);
17381738
17391739 const prev = update_tail;
......@@ -1758,12 +1758,12 @@ pub const DwarfInfo = struct {
17581758 }
17591759
17601760 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));
17621762 } else {
17631763 context.pc = 0;
17641764 }
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
17681768 // The call instruction will have pushed the address of the instruction that follows the call as the return address
17691769 // 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 {
17791779 allocator: mem.Allocator,
17801780 cfa: ?usize,
17811781 pc: usize,
1782 thread_context: debug.ThreadContext,
1782 thread_context: *debug.ThreadContext,
17831783 reg_context: abi.RegisterContext,
17841784 isValidMemory: *const fn (address: usize) bool,
17851785 vm: call_frame.VirtualMachine = .{},
......@@ -1788,14 +1788,14 @@ pub const UnwindContext = struct {
17881788 pub fn init(allocator: mem.Allocator, thread_context: *const debug.ThreadContext, isValidMemory: *const fn (address: usize) bool) !UnwindContext {
17891789 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
17931794 return .{
17941795 .allocator = allocator,
17951796 .cfa = null,
17961797 .pc = pc,
1797 // TODO: This is broken on macos, need a function that knows how to copy the OSs mcontext properly
1798 .thread_context = thread_context.*,
1798 .thread_context = context_copy,
17991799 .reg_context = undefined,
18001800 .isValidMemory = isValidMemory,
18011801 };
......@@ -1804,10 +1804,11 @@ pub const UnwindContext = struct {
18041804 pub fn deinit(self: *UnwindContext) void {
18051805 self.vm.deinit(self.allocator);
18061806 self.stack_machine.deinit(self.allocator);
1807 self.allocator.destroy(self.thread_context);
18071808 }
18081809
18091810 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));
18111812 }
18121813};
18131814
lib/std/dwarf/call_frame.zig+2-2
......@@ -315,9 +315,9 @@ pub const VirtualMachine = struct {
315315 } else return error.InvalidCFA;
316316 },
317317 .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);
319319 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));
321321 },
322322 .expression => |expression| {
323323 context.stack_machine.reset();
lib/std/dwarf/expressions.zig+4-2
......@@ -1070,8 +1070,10 @@ test "DWARF expressions" {
10701070 }
10711071
10721072 // Register values
1073 var thread_context: std.debug.ThreadContext = undefined;
1074 if (std.debug.getContext(&thread_context)) {
1073 if (@TypeOf(std.debug.ThreadContext) != void) {
1074 var thread_context: std.debug.ThreadContext = undefined;
1075 _ = thread_context;
1076
10751077 // TODO: Test fbreg, breg0..31, bregx, regval_type
10761078 }
10771079}