authorgravatar for sahnvour@pm.meSahnvour <sahnvour@pm.me> 2023-08-11 12:19:56+02:00
committergravatar for sahnvour@pm.meSahnvour <sahnvour@pm.me> 2023-08-13 10:56:28+02:00
log078e3305555f117efbaa83a91b2e79444847363c
tree0149ebe23cd28dcbfb5f6ec4d3fe1b65e47467e9
parent0461a64a93f0596e98b62d596bb547e5455577d2

std.Build: make number of collected stack frames configurable


2 files changed, 70 insertions(+), 42 deletions(-)

lib/std/Build.zig+40-20
...@@ -102,6 +102,10 @@ args: ?[][]const u8 = null,...@@ -102,6 +102,10 @@ args: ?[][]const u8 = null,
102debug_log_scopes: []const []const u8 = &.{},102debug_log_scopes: []const []const u8 = &.{},
103debug_compile_errors: bool = false,103debug_compile_errors: bool = false,
104debug_pkg_config: bool = false,104debug_pkg_config: bool = false,
105/// Number of stack frames captured when a `StackTrace` is recorded for debug purposes,
106/// in particular at `Step` creation.
107/// Set to 0 to disable stack collection.
108debug_stack_frames_count: u8 = 8,
105109
106/// Experimental. Use system Darling installation to run cross compiled macOS build artifacts.110/// Experimental. Use system Darling installation to run cross compiled macOS build artifacts.
107enable_darling: bool = false,111enable_darling: bool = false,
...@@ -1764,33 +1768,49 @@ pub fn dumpBadGetPathHelp(...@@ -1764,33 +1768,49 @@ pub fn dumpBadGetPathHelp(
1764 });1768 });
17651769
1766 const tty_config = std.io.tty.detectConfig(stderr);1770 const tty_config = std.io.tty.detectConfig(stderr);
1767 tty_config.setColor(w, .red) catch {};1771 if (s.getStackTrace()) |stack_trace| {
1768 try stderr.writeAll(" The step was created by this stack trace:\n");
1769 tty_config.setColor(w, .reset) catch {};
1770
1771 const debug_info = std.debug.getSelfDebugInfo() catch |err| {
1772 try w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)});
1773 return;
1774 };
1775 const ally = debug_info.allocator;
1776 std.debug.writeStackTrace(s.getStackTrace(), w, ally, debug_info, tty_config) catch |err| {
1777 try stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)});
1778 return;
1779 };
1780 if (asking_step) |as| {
1781 tty_config.setColor(w, .red) catch {};1772 tty_config.setColor(w, .red) catch {};
1782 try stderr.writeAll(" The step that is missing a dependency on the above step was created by this stack trace:\n");1773 try stderr.writeAll(" The step was created by this stack trace:\n");
1783 tty_config.setColor(w, .reset) catch {};1774 tty_config.setColor(w, .reset) catch {};
17841775
1785 std.debug.writeStackTrace(as.getStackTrace(), w, ally, debug_info, tty_config) catch |err| {1776 const debug_info = std.debug.getSelfDebugInfo() catch |err| {
1777 try w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)});
1778 return;
1779 };
1780 const ally = debug_info.allocator;
1781
1782 std.debug.writeStackTrace(stack_trace, w, ally, debug_info, tty_config) catch |err| {
1786 try stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)});1783 try stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)});
1787 return;1784 return;
1788 };1785 };
1786 if (asking_step) |as| {
1787 tty_config.setColor(w, .red) catch {};
1788 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});
1789 tty_config.setColor(w, .reset) catch {};
1790
1791 if (as.getStackTrace()) |as_stack_trace| {
1792 std.debug.writeStackTrace(as_stack_trace, w, ally, debug_info, tty_config) catch |err| {
1793 try stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)});
1794 return;
1795 };
1796 } else {
1797 const field = "debug_stack_frames_count";
1798 comptime assert(@hasField(Build, field));
1799 tty_config.setColor(w, .yellow) catch {};
1800 try stderr.writer().print("no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{});
1801 tty_config.setColor(w, .reset) catch {};
1802 }
1803 }
1804 tty_config.setColor(w, .red) catch {};
1805 try stderr.writeAll(" Hope that helps. Proceeding to panic.\n");
1806 tty_config.setColor(w, .reset) catch {};
1807 } else {
1808 const field = "debug_stack_frames_count";
1809 comptime assert(@hasField(Build, field));
1810 tty_config.setColor(w, .yellow) catch {};
1811 try stderr.writer().print("no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{});
1812 tty_config.setColor(w, .reset) catch {};
1789 }1813 }
1790
1791 tty_config.setColor(w, .red) catch {};
1792 try stderr.writeAll(" Hope that helps. Proceeding to panic.\n");
1793 tty_config.setColor(w, .reset) catch {};
1794}1814}
17951815
1796/// Allocates a new string for assigning a value to a named macro.1816/// Allocates a new string for assigning a value to a named macro.
lib/std/Build/Step.zig+30-22
...@@ -39,7 +39,7 @@ test_results: TestResults,...@@ -39,7 +39,7 @@ test_results: TestResults,
3939
40/// The return address associated with creation of this step that can be useful40/// The return address associated with creation of this step that can be useful
41/// to print along with debugging messages.41/// to print along with debugging messages.
42debug_stack_trace: [n_debug_stack_frames]usize,42debug_stack_trace: []usize,
4343
44pub const TestResults = struct {44pub const TestResults = struct {
45 fail_count: u32 = 0,45 fail_count: u32 = 0,
...@@ -58,8 +58,6 @@ pub const TestResults = struct {...@@ -58,8 +58,6 @@ pub const TestResults = struct {
5858
59pub const MakeFn = *const fn (self: *Step, prog_node: *std.Progress.Node) anyerror!void;59pub const MakeFn = *const fn (self: *Step, prog_node: *std.Progress.Node) anyerror!void;
6060
61const n_debug_stack_frames = 4;
62
63pub const State = enum {61pub const State = enum {
64 precheck_unstarted,62 precheck_unstarted,
65 precheck_started,63 precheck_started,
...@@ -140,14 +138,6 @@ pub const StepOptions = struct {...@@ -140,14 +138,6 @@ pub const StepOptions = struct {
140pub fn init(options: StepOptions) Step {138pub fn init(options: StepOptions) Step {
141 const arena = options.owner.allocator;139 const arena = options.owner.allocator;
142140
143 var addresses = [1]usize{0} ** n_debug_stack_frames;
144 const first_ret_addr = options.first_ret_addr orelse @returnAddress();
145 var stack_trace = std.builtin.StackTrace{
146 .instruction_addresses = &addresses,
147 .index = 0,
148 };
149 std.debug.captureStackTrace(first_ret_addr, &stack_trace);
150
151 return .{141 return .{
152 .id = options.id,142 .id = options.id,
153 .name = arena.dupe(u8, options.name) catch @panic("OOM"),143 .name = arena.dupe(u8, options.name) catch @panic("OOM"),
...@@ -157,7 +147,17 @@ pub fn init(options: StepOptions) Step {...@@ -157,7 +147,17 @@ pub fn init(options: StepOptions) Step {
157 .dependants = .{},147 .dependants = .{},
158 .state = .precheck_unstarted,148 .state = .precheck_unstarted,
159 .max_rss = options.max_rss,149 .max_rss = options.max_rss,
160 .debug_stack_trace = addresses,150 .debug_stack_trace = blk: {
151 const addresses = arena.alloc(usize, options.owner.debug_stack_frames_count) catch @panic("OOM");
152 @memset(addresses, 0);
153 const first_ret_addr = options.first_ret_addr orelse @returnAddress();
154 var stack_trace = std.builtin.StackTrace{
155 .instruction_addresses = addresses,
156 .index = 0,
157 };
158 std.debug.captureStackTrace(first_ret_addr, &stack_trace);
159 break :blk addresses;
160 },
161 .result_error_msgs = .{},161 .result_error_msgs = .{},
162 .result_error_bundle = std.zig.ErrorBundle.empty,162 .result_error_bundle = std.zig.ErrorBundle.empty,
163 .result_cached = false,163 .result_cached = false,
...@@ -199,14 +199,14 @@ pub fn dependOn(self: *Step, other: *Step) void {...@@ -199,14 +199,14 @@ pub fn dependOn(self: *Step, other: *Step) void {
199 self.dependencies.append(other) catch @panic("OOM");199 self.dependencies.append(other) catch @panic("OOM");
200}200}
201201
202pub fn getStackTrace(s: *Step) std.builtin.StackTrace {202pub fn getStackTrace(s: *Step) ?std.builtin.StackTrace {
203 const stack_addresses = &s.debug_stack_trace;
204 var len: usize = 0;203 var len: usize = 0;
205 while (len < n_debug_stack_frames and stack_addresses[len] != 0) {204 while (len < s.debug_stack_trace.len and s.debug_stack_trace[len] != 0) {
206 len += 1;205 len += 1;
207 }206 }
208 return .{207
209 .instruction_addresses = stack_addresses,208 return if (len == 0) null else .{
209 .instruction_addresses = s.debug_stack_trace,
210 .index = len,210 .index = len,
211 };211 };
212}212}
...@@ -245,11 +245,19 @@ pub fn dump(step: *Step) void {...@@ -245,11 +245,19 @@ pub fn dump(step: *Step) void {
245 return;245 return;
246 };246 };
247 const ally = debug_info.allocator;247 const ally = debug_info.allocator;
248 w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};248 if (step.getStackTrace()) |stack_trace| {
249 std.debug.writeStackTrace(step.getStackTrace(), w, ally, debug_info, tty_config) catch |err| {249 w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};
250 stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch {};250 std.debug.writeStackTrace(stack_trace, w, ally, debug_info, tty_config) catch |err| {
251 return;251 stderr.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch {};
252 };252 return;
253 };
254 } else {
255 const field = "debug_stack_frames_count";
256 comptime assert(@hasField(Build, field));
257 tty_config.setColor(w, .yellow) catch {};
258 w.print("name: '{s}'. no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{step.name}) catch {};
259 tty_config.setColor(w, .reset) catch {};
260 }
253}261}
254262
255const Step = @This();263const Step = @This();