| ... | ... | @@ -216,8 +216,12 @@ pub fn unlockStdErr() void { |
| 216 | 216 | /// |
| 217 | 217 | /// During the lock, any `std.Progress` information is cleared from the terminal. |
| 218 | 218 | /// |
| 219 | | /// Returns a `Writer` with empty buffer, meaning that it is |
| 220 | | /// in fact unbuffered and does not need to be flushed. |
| 219 | /// The lock is recursive, so it is valid for the same thread to call `lockStderrWriter` multiple |
| 220 | /// times. The primary motivation is that this allows the panic handler to safely dump the stack |
| 221 | /// trace and panic message even if the mutex was held at the panic site. |
| 222 | /// |
| 223 | /// The returned `Writer` does not need to be manually flushed: flushing is performed automatically |
| 224 | /// when the matching `unlockStderrWriter` call occurs. |
| 221 | 225 | pub fn lockStderrWriter(buffer: []u8) *Writer { |
| 222 | 226 | return std.Progress.lockStderrWriter(buffer); |
| 223 | 227 | } |
| ... | ... | @@ -348,13 +352,12 @@ pub fn relocateContext(dest: *ThreadContext) void { |
| 348 | 352 | } |
| 349 | 353 | } |
| 350 | 354 | |
| 351 | | pub const have_getcontext = @TypeOf(posix.system.getcontext) != void; |
| 352 | | |
| 353 | 355 | /// Capture the current context. The register values in the context will reflect the |
| 354 | 356 | /// state after the platform `getcontext` function returns. |
| 355 | 357 | /// |
| 356 | 358 | /// It is valid to call this if the platform doesn't have context capturing support, |
| 357 | | /// in that case false will be returned. |
| 359 | /// in that case `false` will be returned. This function is `inline` so that the `false` |
| 360 | /// is comptime-known at the call site in that case. |
| 358 | 361 | pub inline fn getContext(context: *ThreadContext) bool { |
| 359 | 362 | if (native_os == .windows) { |
| 360 | 363 | context.* = std.mem.zeroes(windows.CONTEXT); |
| ... | ... | @@ -362,18 +365,19 @@ pub inline fn getContext(context: *ThreadContext) bool { |
| 362 | 365 | return true; |
| 363 | 366 | } |
| 364 | 367 | |
| 365 | | const result = have_getcontext and posix.system.getcontext(context) == 0; |
| 366 | | if (native_os == .macos) { |
| 367 | | assert(context.mcsize == @sizeOf(std.c.mcontext_t)); |
| 368 | if (@TypeOf(posix.system.getcontext) != void) { |
| 369 | if (posix.system.getcontext(context) != 0) return false; |
| 370 | if (native_os == .macos) { |
| 371 | assert(context.mcsize == @sizeOf(std.c.mcontext_t)); |
| 368 | 372 | |
| 369 | | // On aarch64-macos, the system getcontext doesn't write anything into the pc |
| 370 | | // register slot, it only writes lr. This makes the context consistent with |
| 371 | | // other aarch64 getcontext implementations which write the current lr |
| 372 | | // (where getcontext will return to) into both the lr and pc slot of the context. |
| 373 | | if (native_arch == .aarch64) context.mcontext.ss.pc = context.mcontext.ss.lr; |
| 373 | // On aarch64-macos, the system getcontext doesn't write anything into the pc |
| 374 | // register slot, it only writes lr. This makes the context consistent with |
| 375 | // other aarch64 getcontext implementations which write the current lr |
| 376 | // (where getcontext will return to) into both the lr and pc slot of the context. |
| 377 | if (native_arch == .aarch64) context.mcontext.ss.pc = context.mcontext.ss.lr; |
| 378 | } |
| 379 | return true; |
| 374 | 380 | } |
| 375 | | |
| 376 | | return result; |
| 377 | 381 | } |
| 378 | 382 | |
| 379 | 383 | /// Invokes detectable illegal behavior when `ok` is `false`. |
| ... | ... | @@ -413,8 +417,8 @@ pub fn panic(comptime format: []const u8, args: anytype) noreturn { |
| 413 | 417 | panicExtra(@returnAddress(), format, args); |
| 414 | 418 | } |
| 415 | 419 | |
| 416 | | /// Equivalent to `@panic` but with a formatted message, and with an explicitly |
| 417 | | /// provided return address. |
| 420 | /// Equivalent to `@panic` but with a formatted message and an explicitly provided return address |
| 421 | /// which will be the first address in the stack trace. |
| 418 | 422 | pub fn panicExtra( |
| 419 | 423 | ret_addr: ?usize, |
| 420 | 424 | comptime format: []const u8, |
| ... | ... | @@ -952,6 +956,7 @@ fn printLineInfo( |
| 952 | 956 | } |
| 953 | 957 | } |
| 954 | 958 | fn printLineFromFile(writer: *Writer, source_location: SourceLocation) !void { |
| 959 | // Allow overriding the target-agnostic source line printing logic by exposing `root.debug.printLineFromFile`. |
| 955 | 960 | if (@hasDecl(root, "debug") and @hasDecl(root.debug, "printLineFromFile")) { |
| 956 | 961 | return root.debug.printLineFromFile(writer, source_location); |
| 957 | 962 | } |
| ... | ... | @@ -1139,17 +1144,17 @@ test printLineFromFile { |
| 1139 | 1144 | } |
| 1140 | 1145 | |
| 1141 | 1146 | /// TODO multithreaded awareness |
| 1142 | | var debug_info_arena: ?std.heap.ArenaAllocator = null; |
| 1143 | | var debug_info_fba: std.heap.FixedBufferAllocator = .init(&debug_info_fba_buf); |
| 1144 | | var debug_info_fba_buf: [1024 * 1024 * 4]u8 = undefined; |
| 1145 | | fn getDebugInfoAllocator() mem.Allocator { |
| 1146 | | if (false) { |
| 1147 | | if (debug_info_arena == null) { |
| 1148 | | debug_info_arena = .init(std.heap.page_allocator); |
| 1149 | | } |
| 1150 | | return debug_info_arena.?.allocator(); |
| 1147 | fn getDebugInfoAllocator() Allocator { |
| 1148 | // Allow overriding the debug info allocator by exposing `root.debug.getDebugInfoAllocator`. |
| 1149 | if (@hasDecl(root, "debug") and @hasDecl(root.debug, "getDebugInfoAllocator")) { |
| 1150 | return root.debug.getDebugInfoAllocator(); |
| 1151 | 1151 | } |
| 1152 | | return debug_info_fba.allocator(); |
| 1152 | // Otherwise, use a global arena backed by the page allocator |
| 1153 | const S = struct { |
| 1154 | var arena: ?std.heap.ArenaAllocator = null; |
| 1155 | }; |
| 1156 | if (S.arena == null) S.arena = .init(std.heap.page_allocator); |
| 1157 | return S.arena.?.allocator(); |
| 1153 | 1158 | } |
| 1154 | 1159 | |
| 1155 | 1160 | /// Whether or not the current target can print useful debug information when a segfault occurs. |
| ... | ... | @@ -1184,7 +1189,16 @@ pub fn updateSegfaultHandler(act: ?*const posix.Sigaction) void { |
| 1184 | 1189 | posix.sigaction(posix.SIG.FPE, act, null); |
| 1185 | 1190 | } |
| 1186 | 1191 | |
| 1187 | | /// Attaches a global SIGSEGV handler which calls `@panic("segmentation fault");` |
| 1192 | /// Attaches a global handler for several signals which, when triggered, prints output to stderr |
| 1193 | /// similar to the default panic handler, with a message containing the type of signal and a stack |
| 1194 | /// trace if possible. This implementation does not just call the panic handler, because unwinding |
| 1195 | /// the stack (for a stack trace) when a signal is received requires special target-specific logic. |
| 1196 | /// |
| 1197 | /// The signals for which a handler is installed are: |
| 1198 | /// * SIGSEGV (segmentation fault) |
| 1199 | /// * SIGILL (illegal instruction) |
| 1200 | /// * SIGBUS (bus error) |
| 1201 | /// * SIGFPE (arithmetic exception) |
| 1188 | 1202 | pub fn attachSegfaultHandler() void { |
| 1189 | 1203 | if (!have_segfault_handling_support) { |
| 1190 | 1204 | @compileError("segfault handler not supported for this target"); |
| ... | ... | @@ -1305,6 +1319,14 @@ fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(.winapi) c_ |
| 1305 | 1319 | } |
| 1306 | 1320 | |
| 1307 | 1321 | fn handleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?*ThreadContext) noreturn { |
| 1322 | // Allow overriding the target-agnostic segfault handler by exposing `root.debug.handleSegfault`. |
| 1323 | if (@hasDecl(root, "debug") and @hasDecl(root.debug, "handleSegfault")) { |
| 1324 | return root.debug.handleSegfault(addr, name, opt_ctx); |
| 1325 | } |
| 1326 | return defaultHandleSegfault(addr, name, opt_ctx); |
| 1327 | } |
| 1328 | |
| 1329 | pub fn defaultHandleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?*ThreadContext) noreturn { |
| 1308 | 1330 | // There is very similar logic to the following in `defaultPanic`. |
| 1309 | 1331 | switch (panic_stage) { |
| 1310 | 1332 | 0 => { |