From 078e3305555f117efbaa83a91b2e79444847363c Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Fri, 11 Aug 2023 12:19:56 +0200 Subject: [PATCH 1/2] std.Build: make number of collected stack frames configurable --- lib/std/Build.zig | 60 ++++++++++++++++++++++++++++-------------- lib/std/Build/Step.zig | 52 ++++++++++++++++++++---------------- 2 files changed, 70 insertions(+), 42 deletions(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 74aea80931..15db8487d4 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -102,6 +102,10 @@ args: ?[][]const u8 = null, debug_log_scopes: []const []const u8 = &.{}, debug_compile_errors: bool = false, debug_pkg_config: bool = false, +/// Number of stack frames captured when a `StackTrace` is recorded for debug purposes, +/// in particular at `Step` creation. +/// Set to 0 to disable stack collection. +debug_stack_frames_count: u8 = 8, /// Experimental. Use system Darling installation to run cross compiled macOS build artifacts. enable_darling: bool = false, @@ -1764,33 +1768,49 @@ pub fn dumpBadGetPathHelp( }); const tty_config = std.io.tty.detectConfig(stderr); - tty_config.setColor(w, .red) catch {}; - try stderr.writeAll(" The step was created by this stack trace:\n"); - tty_config.setColor(w, .reset) catch {}; - - const debug_info = std.debug.getSelfDebugInfo() catch |err| { - try w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}); - return; - }; - const ally = debug_info.allocator; - std.debug.writeStackTrace(s.getStackTrace(), w, ally, debug_info, tty_config) catch |err| { - try stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)}); - return; - }; - if (asking_step) |as| { + if (s.getStackTrace()) |stack_trace| { tty_config.setColor(w, .red) catch {}; - try stderr.writeAll(" The step that is missing a dependency on the above step was created by this stack trace:\n"); + try stderr.writeAll(" The step was created by this stack trace:\n"); tty_config.setColor(w, .reset) catch {}; - std.debug.writeStackTrace(as.getStackTrace(), w, ally, debug_info, tty_config) catch |err| { + const debug_info = std.debug.getSelfDebugInfo() catch |err| { + try w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}); + return; + }; + const ally = debug_info.allocator; + + std.debug.writeStackTrace(stack_trace, w, ally, debug_info, tty_config) catch |err| { try stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)}); return; }; - } + if (asking_step) |as| { + tty_config.setColor(w, .red) catch {}; + try stderr.writer().print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name}); + tty_config.setColor(w, .reset) catch {}; - tty_config.setColor(w, .red) catch {}; - try stderr.writeAll(" Hope that helps. Proceeding to panic.\n"); - tty_config.setColor(w, .reset) catch {}; + if (as.getStackTrace()) |as_stack_trace| { + std.debug.writeStackTrace(as_stack_trace, w, ally, debug_info, tty_config) catch |err| { + try stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)}); + return; + }; + } else { + const field = "debug_stack_frames_count"; + comptime assert(@hasField(Build, field)); + tty_config.setColor(w, .yellow) catch {}; + try stderr.writer().print("no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{}); + tty_config.setColor(w, .reset) catch {}; + } + } + tty_config.setColor(w, .red) catch {}; + try stderr.writeAll(" Hope that helps. Proceeding to panic.\n"); + tty_config.setColor(w, .reset) catch {}; + } else { + const field = "debug_stack_frames_count"; + comptime assert(@hasField(Build, field)); + tty_config.setColor(w, .yellow) catch {}; + try stderr.writer().print("no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{}); + tty_config.setColor(w, .reset) catch {}; + } } /// Allocates a new string for assigning a value to a named macro. diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig index 8fd60b4ad6..b421309eac 100644 --- a/lib/std/Build/Step.zig +++ b/lib/std/Build/Step.zig @@ -39,7 +39,7 @@ test_results: TestResults, /// The return address associated with creation of this step that can be useful /// to print along with debugging messages. -debug_stack_trace: [n_debug_stack_frames]usize, +debug_stack_trace: []usize, pub const TestResults = struct { fail_count: u32 = 0, @@ -58,8 +58,6 @@ pub const TestResults = struct { pub const MakeFn = *const fn (self: *Step, prog_node: *std.Progress.Node) anyerror!void; -const n_debug_stack_frames = 4; - pub const State = enum { precheck_unstarted, precheck_started, @@ -140,14 +138,6 @@ pub const StepOptions = struct { pub fn init(options: StepOptions) Step { const arena = options.owner.allocator; - var addresses = [1]usize{0} ** n_debug_stack_frames; - const first_ret_addr = options.first_ret_addr orelse @returnAddress(); - var stack_trace = std.builtin.StackTrace{ - .instruction_addresses = &addresses, - .index = 0, - }; - std.debug.captureStackTrace(first_ret_addr, &stack_trace); - return .{ .id = options.id, .name = arena.dupe(u8, options.name) catch @panic("OOM"), @@ -157,7 +147,17 @@ pub fn init(options: StepOptions) Step { .dependants = .{}, .state = .precheck_unstarted, .max_rss = options.max_rss, - .debug_stack_trace = addresses, + .debug_stack_trace = blk: { + const addresses = arena.alloc(usize, options.owner.debug_stack_frames_count) catch @panic("OOM"); + @memset(addresses, 0); + const first_ret_addr = options.first_ret_addr orelse @returnAddress(); + var stack_trace = std.builtin.StackTrace{ + .instruction_addresses = addresses, + .index = 0, + }; + std.debug.captureStackTrace(first_ret_addr, &stack_trace); + break :blk addresses; + }, .result_error_msgs = .{}, .result_error_bundle = std.zig.ErrorBundle.empty, .result_cached = false, @@ -199,14 +199,14 @@ pub fn dependOn(self: *Step, other: *Step) void { self.dependencies.append(other) catch @panic("OOM"); } -pub fn getStackTrace(s: *Step) std.builtin.StackTrace { - const stack_addresses = &s.debug_stack_trace; +pub fn getStackTrace(s: *Step) ?std.builtin.StackTrace { var len: usize = 0; - while (len < n_debug_stack_frames and stack_addresses[len] != 0) { + while (len < s.debug_stack_trace.len and s.debug_stack_trace[len] != 0) { len += 1; } - return .{ - .instruction_addresses = stack_addresses, + + return if (len == 0) null else .{ + .instruction_addresses = s.debug_stack_trace, .index = len, }; } @@ -245,11 +245,19 @@ pub fn dump(step: *Step) void { return; }; const ally = debug_info.allocator; - w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {}; - std.debug.writeStackTrace(step.getStackTrace(), w, ally, debug_info, tty_config) catch |err| { - stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch {}; - return; - }; + if (step.getStackTrace()) |stack_trace| { + w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {}; + std.debug.writeStackTrace(stack_trace, w, ally, debug_info, tty_config) catch |err| { + stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch {}; + return; + }; + } else { + const field = "debug_stack_frames_count"; + comptime assert(@hasField(Build, field)); + tty_config.setColor(w, .yellow) catch {}; + w.print("name: '{s}'. no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{step.name}) catch {}; + tty_config.setColor(w, .reset) catch {}; + } } const Step = @This(); From f43402f883bff6c1934c551b5cb29f70dac1b1b6 Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Sun, 13 Aug 2023 11:25:48 +0200 Subject: [PATCH 2/2] std.Build: factorize Step stack trace dumping code --- lib/std/Build.zig | 50 ++++++++++-------------------------------- lib/std/Build/Step.zig | 12 ++++------ 2 files changed, 15 insertions(+), 47 deletions(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 15db8487d4..212c71576b 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -1768,49 +1768,21 @@ pub fn dumpBadGetPathHelp( }); const tty_config = std.io.tty.detectConfig(stderr); - if (s.getStackTrace()) |stack_trace| { + tty_config.setColor(w, .red) catch {}; + try stderr.writeAll(" The step was created by this stack trace:\n"); + tty_config.setColor(w, .reset) catch {}; + + s.dump(stderr); + if (asking_step) |as| { tty_config.setColor(w, .red) catch {}; - try stderr.writeAll(" The step was created by this stack trace:\n"); + try stderr.writer().print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name}); tty_config.setColor(w, .reset) catch {}; - const debug_info = std.debug.getSelfDebugInfo() catch |err| { - try w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}); - return; - }; - const ally = debug_info.allocator; - - std.debug.writeStackTrace(stack_trace, w, ally, debug_info, tty_config) catch |err| { - try stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)}); - return; - }; - if (asking_step) |as| { - tty_config.setColor(w, .red) catch {}; - try stderr.writer().print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name}); - tty_config.setColor(w, .reset) catch {}; - - if (as.getStackTrace()) |as_stack_trace| { - std.debug.writeStackTrace(as_stack_trace, w, ally, debug_info, tty_config) catch |err| { - try stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)}); - return; - }; - } else { - const field = "debug_stack_frames_count"; - comptime assert(@hasField(Build, field)); - tty_config.setColor(w, .yellow) catch {}; - try stderr.writer().print("no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{}); - tty_config.setColor(w, .reset) catch {}; - } - } - tty_config.setColor(w, .red) catch {}; - try stderr.writeAll(" Hope that helps. Proceeding to panic.\n"); - tty_config.setColor(w, .reset) catch {}; - } else { - const field = "debug_stack_frames_count"; - comptime assert(@hasField(Build, field)); - tty_config.setColor(w, .yellow) catch {}; - try stderr.writer().print("no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{}); - tty_config.setColor(w, .reset) catch {}; + as.dump(stderr); } + tty_config.setColor(w, .red) catch {}; + try stderr.writeAll(" Hope that helps. Proceeding to panic.\n"); + tty_config.setColor(w, .reset) catch {}; } /// Allocates a new string for assigning a value to a named macro. diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig index b421309eac..475fc82e1a 100644 --- a/lib/std/Build/Step.zig +++ b/lib/std/Build/Step.zig @@ -231,13 +231,9 @@ pub fn cast(step: *Step, comptime T: type) ?*T { } /// For debugging purposes, prints identifying information about this Step. -pub fn dump(step: *Step) void { - std.debug.getStderrMutex().lock(); - defer std.debug.getStderrMutex().unlock(); - - const stderr = std.io.getStdErr(); - const w = stderr.writer(); - const tty_config = std.io.tty.detectConfig(stderr); +pub fn dump(step: *Step, file: std.fs.File) void { + const w = file.writer(); + const tty_config = std.io.tty.detectConfig(file); const debug_info = std.debug.getSelfDebugInfo() catch |err| { w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{ @errorName(err), @@ -248,7 +244,7 @@ pub fn dump(step: *Step) void { if (step.getStackTrace()) |stack_trace| { w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {}; std.debug.writeStackTrace(stack_trace, w, ally, debug_info, tty_config) catch |err| { - stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch {}; + w.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch {}; return; }; } else {