| ... | @@ -133,6 +133,12 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { | ... | @@ -133,6 +133,12 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { |
| 133 | } | 133 | } |
| 134 | } | 134 | } |
| 135 | | 135 | |
| | 136 | pub const have_ucontext = @hasDecl(os.system, "ucontext_t") and |
| | 137 | (builtin.os.tag != .linux or switch (builtin.cpu.arch) { |
| | 138 | .mips, .mipsel, .mips64, .mips64el, .riscv64 => false, |
| | 139 | else => true, |
| | 140 | }); |
| | 141 | |
| 136 | /// Platform-specific thread state. This contains register state, and on some platforms | 142 | /// 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 | 143 | /// 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 `copyContext`. | 144 | /// use internal pointers within this structure. To make a copy, use `copyContext`. |
| ... | @@ -146,6 +152,47 @@ pub const ThreadContext = blk: { | ... | @@ -146,6 +152,47 @@ pub const ThreadContext = blk: { |
| 146 | } | 152 | } |
| 147 | }; | 153 | }; |
| 148 | | 154 | |
| | 155 | /// Copies one context to another, updating any internal pointers |
| | 156 | pub fn copyContext(source: *const ThreadContext, dest: *ThreadContext) void { |
| | 157 | if (!have_ucontext) return {}; |
| | 158 | dest.* = source.*; |
| | 159 | relocateContext(dest); |
| | 160 | } |
| | 161 | |
| | 162 | /// Updates any internal points in the context to reflect its current location |
| | 163 | pub fn relocateContext(context: *ThreadContext) void { |
| | 164 | return switch (native_os) { |
| | 165 | .macos => { |
| | 166 | context.mcontext = &context.__mcontext_data; |
| | 167 | }, |
| | 168 | else => {}, |
| | 169 | }; |
| | 170 | } |
| | 171 | |
| | 172 | pub const have_getcontext = @hasDecl(os.system, "getcontext") and |
| | 173 | (builtin.os.tag != .linux or switch (builtin.cpu.arch) { |
| | 174 | .x86, .x86_64 => true, |
| | 175 | else => false, |
| | 176 | }); |
| | 177 | |
| | 178 | /// Capture the current context. The register values in the context will reflect the |
| | 179 | /// state after the platform `getcontext` function returned. |
| | 180 | /// |
| | 181 | /// It is valid to call this if the platform doesn't have context capturing support, |
| | 182 | /// in that case false will be returned. |
| | 183 | pub inline fn getContext(context: *ThreadContext) bool { |
| | 184 | if (native_os == .windows) { |
| | 185 | context.* = std.mem.zeroes(windows.CONTEXT); |
| | 186 | windows.ntdll.RtlCaptureContext(context); |
| | 187 | return true; |
| | 188 | } |
| | 189 | |
| | 190 | const result = have_getcontext and os.system.getcontext(context) == 0; |
| | 191 | if (native_os == .macos) assert(context.mcsize == @sizeOf(std.c.mcontext_t)); |
| | 192 | |
| | 193 | return result; |
| | 194 | } |
| | 195 | |
| 149 | /// Tries to print the stack trace starting from the supplied base pointer to stderr, | 196 | /// Tries to print the stack trace starting from the supplied base pointer to stderr, |
| 150 | /// unbuffered, and ignores any error returned. | 197 | /// unbuffered, and ignores any error returned. |
| 151 | /// TODO multithreaded awareness | 198 | /// TODO multithreaded awareness |
| ... | @@ -428,51 +475,6 @@ pub fn writeStackTrace( | ... | @@ -428,51 +475,6 @@ pub fn writeStackTrace( |
| 428 | } | 475 | } |
| 429 | } | 476 | } |
| 430 | | 477 | |
| 431 | pub const have_getcontext = @hasDecl(os.system, "getcontext") and | | |
| 432 | (builtin.os.tag != .linux or switch (builtin.cpu.arch) { | | |
| 433 | .x86, .x86_64 => true, | | |
| 434 | else => false, | | |
| 435 | }); | | |
| 436 | | | |
| 437 | pub const have_ucontext = @hasDecl(os.system, "ucontext_t") and | | |
| 438 | (builtin.os.tag != .linux or switch (builtin.cpu.arch) { | | |
| 439 | .mips, .mipsel, .mips64, .mips64el, .riscv64 => false, | | |
| 440 | else => true, | | |
| 441 | }); | | |
| 442 | | | |
| 443 | pub inline fn getContext(context: *ThreadContext) bool { | | |
| 444 | if (native_os == .windows) { | | |
| 445 | context.* = std.mem.zeroes(windows.CONTEXT); | | |
| 446 | windows.ntdll.RtlCaptureContext(context); | | |
| 447 | return true; | | |
| 448 | } | | |
| 449 | | | |
| 450 | const result = have_getcontext and os.system.getcontext(context) == 0; | | |
| 451 | if (native_os == .macos) { | | |
| 452 | // TODO: Temp, to discover this size via aarch64 CI | | |
| 453 | if (context.mcsize != @sizeOf(std.c.mcontext_t)) { | | |
| 454 | print("context.mcsize does not match! {} vs {}\n", .{ context.mcsize, @sizeOf(std.c.mcontext_t) }); | | |
| 455 | } | | |
| 456 | | | |
| 457 | assert(context.mcsize == @sizeOf(std.c.mcontext_t)); | | |
| 458 | } | | |
| 459 | | | |
| 460 | return result; | | |
| 461 | } | | |
| 462 | | | |
| 463 | pub fn copyContext(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 | | | |
| 476 | pub const UnwindError = if (have_ucontext) | 478 | pub const UnwindError = if (have_ucontext) |
| 477 | @typeInfo(@typeInfo(@TypeOf(StackIterator.next_unwind)).Fn.return_type.?).ErrorUnion.error_set | 479 | @typeInfo(@typeInfo(@TypeOf(StackIterator.next_unwind)).Fn.return_type.?).ErrorUnion.error_set |
| 478 | else | 480 | else |
| ... | @@ -855,7 +857,7 @@ fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usiz | ... | @@ -855,7 +857,7 @@ fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usiz |
| 855 | pub fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void { | 857 | pub fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void { |
| 856 | const module_name = debug_info.getModuleNameForAddress(address) orelse "???"; | 858 | const module_name = debug_info.getModuleNameForAddress(address) orelse "???"; |
| 857 | try tty_config.setColor(out_stream, .dim); | 859 | try tty_config.setColor(out_stream, .dim); |
| 858 | try out_stream.print("Unwind information for {s} was not available ({}), trace may be incomplete\n\n", .{ module_name, err }); | 860 | try out_stream.print("Unwind information for `{s}` was not available ({}), trace may be incomplete\n\n", .{ module_name, err }); |
| 859 | try tty_config.setColor(out_stream, .reset); | 861 | try tty_config.setColor(out_stream, .reset); |
| 860 | } | 862 | } |
| 861 | | 863 | |
| ... | @@ -1641,7 +1643,7 @@ pub const DebugInfo = struct { | ... | @@ -1641,7 +1643,7 @@ pub const DebugInfo = struct { |
| 1641 | const seg_start = segment_cmd.vmaddr; | 1643 | const seg_start = segment_cmd.vmaddr; |
| 1642 | const seg_end = seg_start + segment_cmd.vmsize; | 1644 | const seg_end = seg_start + segment_cmd.vmsize; |
| 1643 | if (original_address >= seg_start and original_address < seg_end) { | 1645 | if (original_address >= seg_start and original_address < seg_end) { |
| 1644 | return mem.sliceTo(std.c._dyld_get_image_name(i), 0); | 1646 | return fs.path.basename(mem.sliceTo(std.c._dyld_get_image_name(i), 0)); |
| 1645 | } | 1647 | } |
| 1646 | }, | 1648 | }, |
| 1647 | else => {}, | 1649 | else => {}, |