| ... | ... | @@ -1,14 +1,31 @@ |
| 1 | /// We override the panic implementation to our own one, so we can print our own information before |
| 2 | /// calling the default panic handler. This declaration must be re-exposed from `@import("root")`. |
| 3 | pub const panic = std.debug.FullPanic(panicImpl); |
| 4 | |
| 5 | /// We let std install its segfault handler, but we override the target-agnostic handler it calls, |
| 6 | /// so we can print our own information before calling the default segfault logic. This declaration |
| 7 | /// must be re-exposed from `@import("root")`. |
| 8 | pub const debug = struct { |
| 9 | pub const handleSegfault = handleSegfaultImpl; |
| 10 | }; |
| 11 | |
| 1 | 12 | /// Printed in panic messages when suggesting a command to run, allowing copy-pasting the command. |
| 2 | 13 | /// Set by `main` as soon as arguments are known. The value here is a default in case we somehow |
| 3 | 14 | /// crash earlier than that. |
| 4 | 15 | pub var zig_argv0: []const u8 = "zig"; |
| 5 | 16 | |
| 6 | | const enabled = switch (build_options.io_mode) { |
| 7 | | .threaded => build_options.enable_debug_extensions, |
| 8 | | .evented => false, // would use threadlocals in a way incompatible with evented |
| 9 | | }; |
| 17 | fn handleSegfaultImpl(addr: ?usize, name: []const u8, opt_ctx: ?std.debug.CpuContextPtr) noreturn { |
| 18 | @branchHint(.cold); |
| 19 | dumpCrashContext() catch {}; |
| 20 | std.debug.defaultHandleSegfault(addr, name, opt_ctx); |
| 21 | } |
| 22 | fn panicImpl(msg: []const u8, first_trace_addr: ?usize) noreturn { |
| 23 | @branchHint(.cold); |
| 24 | dumpCrashContext() catch {}; |
| 25 | std.debug.defaultPanic(msg, first_trace_addr orelse @returnAddress()); |
| 26 | } |
| 10 | 27 | |
| 11 | | pub const AnalyzeBody = if (enabled) struct { |
| 28 | pub const AnalyzeBody = struct { |
| 12 | 29 | parent: ?*AnalyzeBody, |
| 13 | 30 | sema: *Sema, |
| 14 | 31 | block: *Sema.Block, |
| ... | ... | @@ -35,15 +52,9 @@ pub const AnalyzeBody = if (enabled) struct { |
| 35 | 52 | std.debug.assert(current.? == ab); // `Sema.analyzeBodyInner` did not match push/pop calls |
| 36 | 53 | current = ab.parent; |
| 37 | 54 | } |
| 38 | | } else struct { |
| 39 | | const current: ?noreturn = null; |
| 40 | | // Dummy implementation, with functions marked `inline` to avoid interfering with tail calls. |
| 41 | | pub inline fn push(_: AnalyzeBody, _: *Sema, _: *Sema.Block, _: []const Zir.Inst.Index) void {} |
| 42 | | pub inline fn pop(_: AnalyzeBody) void {} |
| 43 | | pub inline fn setBodyIndex(_: @This(), _: usize) void {} |
| 44 | 55 | }; |
| 45 | 56 | |
| 46 | | pub const CodegenFunc = if (enabled) struct { |
| 57 | pub const CodegenFunc = struct { |
| 47 | 58 | zcu: *const Zcu, |
| 48 | 59 | func_index: InternPool.Index, |
| 49 | 60 | threadlocal var current: ?CodegenFunc = null; |
| ... | ... | @@ -55,21 +66,25 @@ pub const CodegenFunc = if (enabled) struct { |
| 55 | 66 | std.debug.assert(current.?.func_index == func_index); |
| 56 | 67 | current = null; |
| 57 | 68 | } |
| 58 | | } else struct { |
| 59 | | const current: ?noreturn = null; |
| 60 | | // Dummy implementation |
| 61 | | pub fn start(_: *const Zcu, _: InternPool.Index) void {} |
| 62 | | pub fn stop(_: InternPool.Index) void {} |
| 63 | 69 | }; |
| 64 | 70 | |
| 65 | | pub fn dumpCrashContext(terminal: Io.Terminal) Io.Writer.Error!void { |
| 71 | fn dumpCrashContext() Io.Writer.Error!void { |
| 66 | 72 | const S = struct { |
| 73 | /// In the case of recursive panics or segfaults, don't print the context for a second time. |
| 74 | threadlocal var already_dumped = false; |
| 67 | 75 | /// TODO: make this unnecessary. It exists because `print_zir` currently needs an allocator, |
| 68 | 76 | /// but that shouldn't be necessary---it's already only used in one place. |
| 69 | | var crash_heap: [64 * 1024]u8 = undefined; |
| 77 | threadlocal var crash_heap: [64 * 1024]u8 = undefined; |
| 70 | 78 | }; |
| 79 | if (S.already_dumped) return; |
| 80 | S.already_dumped = true; |
| 81 | |
| 82 | // TODO: this does mean that a different thread could grab the stderr mutex between the context |
| 83 | // and the actual panic printing, which would be quite confusing. |
| 84 | const stderr = std.debug.lockStderr(&.{}); |
| 85 | defer std.debug.unlockStderr(); |
| 86 | const w = &stderr.file_writer.interface; |
| 71 | 87 | |
| 72 | | const w = terminal.writer; |
| 73 | 88 | try w.writeAll("Compiler crash context:\n"); |
| 74 | 89 | |
| 75 | 90 | if (CodegenFunc.current) |*cg| { |
| ... | ... | @@ -155,5 +170,3 @@ const Zcu = @import("Zcu.zig"); |
| 155 | 170 | const InternPool = @import("InternPool.zig"); |
| 156 | 171 | const dev = @import("dev.zig"); |
| 157 | 172 | const print_zir = @import("print_zir.zig"); |
| 158 | | |
| 159 | | const build_options = @import("build_options"); |