| ... | @@ -1,14 +1,31 @@ | ... | @@ -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 | /// Printed in panic messages when suggesting a command to run, allowing copy-pasting the command. | 12 | /// Printed in panic messages when suggesting a command to run, allowing copy-pasting the command. |
| 2 | /// Set by `main` as soon as arguments are known. The value here is a default in case we somehow | 13 | /// Set by `main` as soon as arguments are known. The value here is a default in case we somehow |
| 3 | /// crash earlier than that. | 14 | /// crash earlier than that. |
| 4 | pub var zig_argv0: []const u8 = "zig"; | 15 | pub var zig_argv0: []const u8 = "zig"; |
| 5 | | 16 | |
| 6 | const enabled = switch (build_options.io_mode) { | 17 | fn handleSegfaultImpl(addr: ?usize, name: []const u8, opt_ctx: ?std.debug.CpuContextPtr) noreturn { |
| 7 | .threaded => build_options.enable_debug_extensions, | 18 | @branchHint(.cold); |
| 8 | .evented => false, // would use threadlocals in a way incompatible with evented | 19 | dumpCrashContext() catch {}; |
| 9 | }; | 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 | parent: ?*AnalyzeBody, | 29 | parent: ?*AnalyzeBody, |
| 13 | sema: *Sema, | 30 | sema: *Sema, |
| 14 | block: *Sema.Block, | 31 | block: *Sema.Block, |
| ... | @@ -35,15 +52,9 @@ pub const AnalyzeBody = if (enabled) struct { | ... | @@ -35,15 +52,9 @@ pub const AnalyzeBody = if (enabled) struct { |
| 35 | std.debug.assert(current.? == ab); // `Sema.analyzeBodyInner` did not match push/pop calls | 52 | std.debug.assert(current.? == ab); // `Sema.analyzeBodyInner` did not match push/pop calls |
| 36 | current = ab.parent; | 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 | zcu: *const Zcu, | 58 | zcu: *const Zcu, |
| 48 | func_index: InternPool.Index, | 59 | func_index: InternPool.Index, |
| 49 | threadlocal var current: ?CodegenFunc = null; | 60 | threadlocal var current: ?CodegenFunc = null; |
| ... | @@ -55,21 +66,25 @@ pub const CodegenFunc = if (enabled) struct { | ... | @@ -55,21 +66,25 @@ pub const CodegenFunc = if (enabled) struct { |
| 55 | std.debug.assert(current.?.func_index == func_index); | 66 | std.debug.assert(current.?.func_index == func_index); |
| 56 | current = null; | 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 | const S = struct { | 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 | /// TODO: make this unnecessary. It exists because `print_zir` currently needs an allocator, | 75 | /// TODO: make this unnecessary. It exists because `print_zir` currently needs an allocator, |
| 68 | /// but that shouldn't be necessary---it's already only used in one place. | 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 | try w.writeAll("Compiler crash context:\n"); | 88 | try w.writeAll("Compiler crash context:\n"); |
| 74 | | 89 | |
| 75 | if (CodegenFunc.current) |*cg| { | 90 | if (CodegenFunc.current) |*cg| { |
| ... | @@ -155,5 +170,3 @@ const Zcu = @import("Zcu.zig"); | ... | @@ -155,5 +170,3 @@ const Zcu = @import("Zcu.zig"); |
| 155 | const InternPool = @import("InternPool.zig"); | 170 | const InternPool = @import("InternPool.zig"); |
| 156 | const dev = @import("dev.zig"); | 171 | const dev = @import("dev.zig"); |
| 157 | const print_zir = @import("print_zir.zig"); | 172 | const print_zir = @import("print_zir.zig"); |
| 158 | | | |
| 159 | const build_options = @import("build_options"); | | |