diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bun.js/bindings/exports.zig | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/wtf-bindings.cpp | 34 | ||||
-rw-r--r-- | src/bun.js/module_loader.zig | 1 | ||||
-rw-r--r-- | src/crash_reporter.zig | 50 | ||||
-rw-r--r-- | src/deps/backtrace.zig | 148 | ||||
-rw-r--r-- | src/main.zig | 8 | ||||
-rw-r--r-- | src/report.zig | 20 |
7 files changed, 105 insertions, 158 deletions
diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig index e6ccc039e..2e2c5e556 100644 --- a/src/bun.js/bindings/exports.zig +++ b/src/bun.js/bindings/exports.zig @@ -26,7 +26,7 @@ const JSModuleLoader = JSC.JSModuleLoader; const JSModuleRecord = JSC.JSModuleRecord; const Microtask = JSC.Microtask; const JSPrivateDataPtr = @import("../base.zig").JSPrivateDataPtr; -const Backtrace = @import("../../deps/backtrace.zig"); +const Backtrace = @import("../../crash_reporter.zig"); const JSPrinter = @import("../../js_printer.zig"); const JSLexer = @import("../../js_lexer.zig"); const typeBaseName = @import("../../meta.zig").typeBaseName; diff --git a/src/bun.js/bindings/wtf-bindings.cpp b/src/bun.js/bindings/wtf-bindings.cpp index 561c83ffa..d1d73a891 100644 --- a/src/bun.js/bindings/wtf-bindings.cpp +++ b/src/bun.js/bindings/wtf-bindings.cpp @@ -1,6 +1,8 @@ #include "wtf-bindings.h" #include "wtf/text/Base64.h" +#include "wtf/StackTrace.h" + extern "C" void WTF__copyLCharsFromUCharSource(LChar* destination, const UChar* source, size_t length) { WTF::StringImpl::copyCharacters(destination, source, length); @@ -11,4 +13,36 @@ extern "C" JSC::EncodedJSValue WTF__toBase64URLStringValue(const uint8_t* bytes, WTF::String string = WTF::base64URLEncodeToString(reinterpret_cast<const LChar*>(bytes), static_cast<unsigned int>(length)); string.impl()->ref(); return JSC::JSValue::encode(JSC::jsString(globalObject->vm(), string)); +} + +extern "C" void Bun__crashReportWrite(void* ctx, const char* message, size_t length); +extern "C" void Bun__crashReportDumpStackTrace(void* ctx) +{ + static constexpr int framesToShow = 32; + static constexpr int framesToSkip = 4; + void* stack[framesToShow + framesToSkip]; + int frames = framesToShow + framesToSkip; + WTFGetBacktrace(stack, &frames); + bool isFirst = true; + WTF::StackTraceSymbolResolver { { stack, static_cast<size_t>(frames) } }.forEach([&](int frameNumber, void* stackFrame, const char* name) { + if (frameNumber < framesToSkip) + return; + + StringPrintStream out; + if (isFirst) { + isFirst = false; + if (name) + out.printf("\n%-3d %p %s", frameNumber, stackFrame, name); + else + out.printf("\n%-3d %p", frameNumber, stackFrame); + } else { + if (name) + out.printf("%-3d %p %s", frameNumber, stackFrame, name); + else + out.printf("%-3d %p", frameNumber, stackFrame); + } + + auto str = out.toCString(); + Bun__crashReportWrite(ctx, str.data(), str.length()); + }); }
\ No newline at end of file diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index 82e96c8ed..59a4288fb 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -1357,6 +1357,7 @@ pub const ModuleLoader = struct { if (err == error.AsyncModule) { unreachable; } + VirtualMachine.processFetchLog(globalObject, specifier.*, referrer.*, &log, ret, err); return true; }) |builtin| { diff --git a/src/crash_reporter.zig b/src/crash_reporter.zig new file mode 100644 index 000000000..4d98b47f4 --- /dev/null +++ b/src/crash_reporter.zig @@ -0,0 +1,50 @@ +const std = @import("std"); + +fn setup_sigactions(act: ?*const os.Sigaction) !void { + try os.sigaction(os.SIG.ABRT, act, null); + try os.sigaction(os.SIG.BUS, act, null); + try os.sigaction(os.SIG.FPE, act, null); + try os.sigaction(os.SIG.ILL, act, null); + try os.sigaction(os.SIG.SEGV, act, null); + try os.sigaction(os.SIG.TRAP, act, null); +} + +const builtin = @import("builtin"); +const ErrorCallback = fn (sig: i32, addr: usize) void; +var on_error: ?ErrorCallback = null; +noinline fn sigaction_handler(sig: i32, info: *const std.os.siginfo_t, _: ?*const anyopaque) callconv(.C) void { + // Prevent recursive calls + setup_sigactions(null) catch unreachable; + + const addr = switch (comptime builtin.target.os.tag) { + .linux => @ptrToInt(info.fields.sigfault.addr), + .macos, .freebsd => @ptrToInt(info.addr), + .netbsd => @ptrToInt(info.info.reason.fault.addr), + .openbsd => @ptrToInt(info.data.fault.addr), + .solaris => @ptrToInt(info.reason.fault.addr), + else => unreachable, + }; + if (on_error) |handle| handle(sig, addr); +} + +pub fn reloadHandlers() !void { + try setup_sigactions(null); + + var act = os.Sigaction{ + .handler = .{ .sigaction = sigaction_handler }, + .mask = os.empty_sigset, + .flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND), + }; + + try setup_sigactions(&act); +} +const os = std.os; +pub fn start() !void { + var act = os.Sigaction{ + .handler = .{ .sigaction = sigaction_handler }, + .mask = os.empty_sigset, + .flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND), + }; + + try setup_sigactions(&act); +} diff --git a/src/deps/backtrace.zig b/src/deps/backtrace.zig index 47293d1cf..e69de29bb 100644 --- a/src/deps/backtrace.zig +++ b/src/deps/backtrace.zig @@ -1,148 +0,0 @@ -const Environment = @import("../env.zig"); -pub const backtrace_state = struct_backtrace_state; -pub const struct_backtrace_state = opaque {}; -pub const backtrace_error_callback = ?fn ( - ?*anyopaque, - [*c]const u8, - c_int, -) callconv(.C) void; -pub extern fn backtrace_create_state( - filename: [*c]const u8, - threaded: c_int, - error_callback: backtrace_error_callback, - data: ?*anyopaque, -) ?*struct_backtrace_state; -pub const backtrace_full_callback = ?fn ( - ?*anyopaque, - usize, - [*c]const u8, - c_int, - [*c]const u8, -) callconv(.C) c_int; -pub extern fn backtrace_full( - state: ?*struct_backtrace_state, - skip: c_int, - callback: backtrace_full_callback, - error_callback: backtrace_error_callback, - data: ?*anyopaque, -) c_int; -pub const backtrace_simple_callback = ?fn (?*anyopaque, usize) callconv(.C) c_int; -pub extern fn backtrace_simple( - state: ?*struct_backtrace_state, - skip: c_int, - callback: backtrace_simple_callback, - error_callback: backtrace_error_callback, - data: ?*anyopaque, -) c_int; -pub extern fn backtrace_print(state: ?*struct_backtrace_state, skip: c_int, [*c]anyopaque) void; -pub extern fn backtrace_pcinfo( - state: ?*struct_backtrace_state, - pc: usize, - callback: backtrace_full_callback, - error_callback: backtrace_error_callback, - data: ?*anyopaque, -) c_int; -pub const backtrace_syminfo_callback = ?fn (?*anyopaque, usize, [*c]const u8, usize, usize) callconv(.C) void; -pub extern fn backtrace_syminfo( - state: ?*struct_backtrace_state, - addr: usize, - callback: backtrace_syminfo_callback, - error_callback: backtrace_error_callback, - data: ?*anyopaque, -) c_int; - -pub const BACKTRACE_SUPPORTED = @as(c_int, 1); -pub const BACKTRACE_USES_MALLOC = @as(c_int, 0); -pub const BACKTRACE_SUPPORTS_THREADS = @as(c_int, 1); -pub const BACKTRACE_SUPPORTS_DATA = @as(c_int, 1); - -fn error_callback(data: *anyopaque, msg: [*c]u8, errnum: c_int) callconv(.C) void { - _ = data; - _ = msg; - _ = errnum; -} - -pub const StackFrame = struct { - pc: usize, - filename: []const u8, - function_name: []const u8, - line_number: c_int, -}; - -pub const PrintCallback = fn (ctx: ?*anyopaque, frame: StackFrame) void; - -var callback: PrintCallback = undefined; -var callback_ctx: ?*anyopaque = null; - -const std = @import("std"); - -noinline fn full_callback(_: ?*anyopaque, pc: usize, filename: [*c]const u8, line_number: c_int, function_name: [*c]const u8) callconv(.C) c_int { - var stack_frame = StackFrame{ - .pc = pc, - .line_number = line_number, - .function_name = if (function_name) |fn_| std.mem.span(fn_) else "", - .filename = if (filename) |fn_| std.mem.span(fn_) else "", - }; - callback(callback_ctx, stack_frame); - return 0; -} - -var state: ?*backtrace_state = null; -pub inline fn print() void { - if (Environment.isMac) return; - state = backtrace_create_state(null, BACKTRACE_SUPPORTS_THREADS, null, null); - _ = backtrace_full(state, 2, full_callback, null, null); -} - -fn setup_sigactions(act: ?*const os.Sigaction) !void { - try os.sigaction(os.SIG.ABRT, act, null); - try os.sigaction(os.SIG.BUS, act, null); - try os.sigaction(os.SIG.FPE, act, null); - try os.sigaction(os.SIG.ILL, act, null); - try os.sigaction(os.SIG.SEGV, act, null); - try os.sigaction(os.SIG.TRAP, act, null); -} - -const builtin = @import("builtin"); -const ErrorCallback = fn (sig: i32, addr: usize) void; -var on_error: ?ErrorCallback = null; -noinline fn sigaction_handler(sig: i32, info: *const std.os.siginfo_t, _: ?*const anyopaque) callconv(.C) void { - // Prevent recursive calls - setup_sigactions(null) catch unreachable; - - const addr = switch (comptime builtin.target.os.tag) { - .linux => @ptrToInt(info.fields.sigfault.addr), - .macos, .freebsd => @ptrToInt(info.addr), - .netbsd => @ptrToInt(info.info.reason.fault.addr), - .openbsd => @ptrToInt(info.data.fault.addr), - .solaris => @ptrToInt(info.reason.fault.addr), - else => unreachable, - }; - if (on_error) |handle| handle(sig, addr); -} - -pub fn reloadHandlers() !void { - try setup_sigactions(null); - - var act = os.Sigaction{ - .handler = .{ .sigaction = sigaction_handler }, - .mask = os.empty_sigset, - .flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND), - }; - - try setup_sigactions(&act); -} -const os = std.os; -pub fn start(ctx: ?*anyopaque, callback_: PrintCallback, onError: ErrorCallback) !void { - callback_ctx = ctx; - callback = callback_; - on_error = onError; - - var act = os.Sigaction{ - .handler = .{ .sigaction = sigaction_handler }, - .mask = os.empty_sigset, - .flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND), - }; - - try setup_sigactions(&act); -} diff --git a/src/main.zig b/src/main.zig index 9d92942be..e7073328f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -30,16 +30,12 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) nore MainPanicHandler.handle_panic(msg, error_return_trace); } -const CrashReporter = @import("crash_reporter"); - -pub fn PLCrashReportHandler() void { - Report.fatal(null, null); -} +const CrashReporter = @import("./crash_reporter.zig"); pub var start_time: i128 = 0; pub fn main() void { if (comptime Environment.isRelease) - CrashReporter.start(null, Report.CrashReportWriter.printFrame, Report.handleCrash) catch unreachable; + CrashReporter.start(null) catch unreachable; start_time = std.time.nanoTimestamp(); diff --git a/src/report.zig b/src/report.zig index a39734a9d..8037c2899 100644 --- a/src/report.zig +++ b/src/report.zig @@ -15,7 +15,7 @@ const CLI = @import("./cli.zig").Cli; const Features = @import("./analytics/analytics_thread.zig").Features; const Platform = @import("./analytics/analytics_thread.zig").GenerateHeader.GeneratePlatform; const HTTP = @import("http").AsyncHTTP; -const CrashReporter = @import("crash_reporter"); +const CrashReporter = @import("./crash_reporter.zig"); const Report = @This(); @@ -230,7 +230,11 @@ pub fn fatal(err_: ?anyerror, msg_: ?string) void { // It only is a real crash report if it's not coming from Zig - CrashReportWriter.dump(); + if (comptime !@import("javascript_core").is_bindgen) { + std.mem.doNotOptimizeAway(&Bun__crashReportWrite); + Bun__crashReportDumpStackTrace(&crash_report_writer); + } + crash_report_writer.flush(); crash_report_writer.printPath(); @@ -244,6 +248,13 @@ pub fn fatal(err_: ?anyerror, msg_: ?string) void { var globalError_ranOnce = false; +export fn Bun__crashReportWrite(ctx: *CrashReportWriter, bytes_ptr: [*]const u8, len: usize) void { + if (len > 0) + ctx.print("{s}\n", .{bytes_ptr[0..len]}); +} + +extern "C" fn Bun__crashReportDumpStackTrace(ctx: *anyopaque) void; + pub noinline fn handleCrash(signal: i32, addr: usize) void { const had_printed_fatal = has_printed_fatal; if (has_printed_fatal) return; @@ -263,7 +274,10 @@ pub noinline fn handleCrash(signal: i32, addr: usize) void { .{ @errorName(name), std.fmt.fmtSliceHexUpper(std.mem.asBytes(&addr)) }, ); printMetadata(); - CrashReportWriter.dump(); + if (comptime !@import("javascript_core").is_bindgen) { + std.mem.doNotOptimizeAway(&Bun__crashReportWrite); + Bun__crashReportDumpStackTrace(&crash_report_writer); + } if (!had_printed_fatal) { crash_report_writer.print("\nAsk for #help in https://bun.sh/discord or go to https://bun.sh/issues\n\n", .{}); |