| ... | ... | @@ -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 | 142 | /// Platform-specific thread state. This contains register state, and on some platforms |
| 137 | 143 | /// information about the stack. This is not safe to trivially copy, because some platforms |
| 138 | 144 | /// use internal pointers within this structure. To make a copy, use `copyContext`. |
| ... | ... | @@ -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 | 196 | /// Tries to print the stack trace starting from the supplied base pointer to stderr, |
| 150 | 197 | /// unbuffered, and ignores any error returned. |
| 151 | 198 | /// TODO multithreaded awareness |
| ... | ... | @@ -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 | 478 | pub const UnwindError = if (have_ucontext) |
| 477 | 479 | @typeInfo(@typeInfo(@TypeOf(StackIterator.next_unwind)).Fn.return_type.?).ErrorUnion.error_set |
| 478 | 480 | else |
| ... | ... | @@ -855,7 +857,7 @@ fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usiz |
| 855 | 857 | pub fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void { |
| 856 | 858 | const module_name = debug_info.getModuleNameForAddress(address) orelse "???"; |
| 857 | 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 | 861 | try tty_config.setColor(out_stream, .reset); |
| 860 | 862 | } |
| 861 | 863 | |
| ... | ... | @@ -1641,7 +1643,7 @@ pub const DebugInfo = struct { |
| 1641 | 1643 | const seg_start = segment_cmd.vmaddr; |
| 1642 | 1644 | const seg_end = seg_start + segment_cmd.vmsize; |
| 1643 | 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 | 1649 | else => {}, |