From bac132bc8fb320620ca5ad554ce515ccb7e4dad1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 7 Jun 2022 17:48:53 -0700 Subject: introduce std.debug.Trace And use it to debug a LazySrcLoc in stage2 that is set to a bogus value. The actual fix in this commit is: ```diff - try sema.emitBackwardBranch(&child_block, call_src); + try sema.emitBackwardBranch(block, call_src); ``` --- lib/std/debug.zig | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'lib/std/debug.zig') diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 7fb632084b..f4ca0f0354 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1943,3 +1943,60 @@ test "#4353: std.debug should manage resources correctly" { noinline fn showMyTrace() usize { return @returnAddress(); } + +pub fn Trace(comptime size: usize, comptime stack_frame_count: usize) type { + return struct { + addrs: [size][stack_frame_count]usize = undefined, + notes: [size][]const u8 = undefined, + index: usize = 0, + + const frames_init = [1]usize{0} ** stack_frame_count; + + pub noinline fn add(t: *@This(), note: []const u8) void { + return addAddr(t, @returnAddress(), note); + } + + pub fn addAddr(t: *@This(), addr: usize, note: []const u8) void { + if (t.index < size) { + t.notes[t.index] = note; + t.addrs[t.index] = [1]usize{0} ** stack_frame_count; + var stack_trace: std.builtin.StackTrace = .{ + .index = 0, + .instruction_addresses = &t.addrs[t.index], + }; + captureStackTrace(addr, &stack_trace); + } + // Keep counting even if the end is reached so that the + // user can find out how much more size they need. + t.index += 1; + } + + pub fn dump(t: @This()) void { + const tty_config = detectTTYConfig(); + const stderr = io.getStdErr().writer(); + const end = @maximum(t.index, size); + const debug_info = getSelfDebugInfo() catch |err| { + stderr.print( + "Unable to dump stack trace: Unable to open debug info: {s}\n", + .{@errorName(err)}, + ) catch return; + return; + }; + for (t.addrs[0..end]) |frames_array, i| { + stderr.print("{s}:\n", .{t.notes[i]}) catch return; + var frames_array_mutable = frames_array; + const frames = mem.sliceTo(frames_array_mutable[0..], 0); + const stack_trace: std.builtin.StackTrace = .{ + .index = frames.len, + .instruction_addresses = frames, + }; + writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, tty_config) catch continue; + } + if (t.index > end) { + stderr.print("{d} more traces not shown; consider increasing trace size\n", .{ + t.index - end, + }) catch return; + } + } + }; +} -- cgit v1.2.3 From af909f6c93f06e409e98cb90a9896aa5216f1563 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 8 Jun 2022 12:55:24 -0700 Subject: std.debug.Trace: improve API Now `std.debug.Trace` is a concrete type with pre-chosen defaults. `std.debug.ConfigurableTrace` can be used for more advanced cases. --- lib/std/debug.zig | 37 +++++++++++++++++++++++++++++++------ src/Module.zig | 6 ++---- 2 files changed, 33 insertions(+), 10 deletions(-) (limited to 'lib/std/debug.zig') diff --git a/lib/std/debug.zig b/lib/std/debug.zig index f4ca0f0354..ba45b16d1b 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1944,19 +1944,42 @@ noinline fn showMyTrace() usize { return @returnAddress(); } -pub fn Trace(comptime size: usize, comptime stack_frame_count: usize) type { +/// This API helps you track where a value originated and where it was mutated, +/// or any other points of interest. +/// In debug mode, it adds a small size penalty (104 bytes on 64-bit architectures) +/// to the aggregate that you add it to. +/// In release mode, it is size 0 and all methods are no-ops. +/// This is a pre-made type with default settings. +/// For more advanced usage, see `ConfigurableTrace`. +pub const Trace = ConfigurableTrace(2, 4, builtin.mode == .Debug); + +pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize, comptime enabled: bool) type { return struct { - addrs: [size][stack_frame_count]usize = undefined, - notes: [size][]const u8 = undefined, - index: usize = 0, + addrs: [actual_size][stack_frame_count]usize = undefined, + notes: [actual_size][]const u8 = undefined, + index: Index = 0, - const frames_init = [1]usize{0} ** stack_frame_count; + const actual_size = if (enabled) size else 0; + const Index = if (enabled) usize else u0; - pub noinline fn add(t: *@This(), note: []const u8) void { + pub const enabled = enabled; + + pub const add = if (enabled) addNoInline else addNoOp; + + pub noinline fn addNoInline(t: *@This(), note: []const u8) void { + comptime assert(enabled); return addAddr(t, @returnAddress(), note); } + pub inline fn addNoOp(t: *@This(), note: []const u8) void { + _ = t; + _ = note; + comptime assert(!enabled); + } + pub fn addAddr(t: *@This(), addr: usize, note: []const u8) void { + if (!enabled) return; + if (t.index < size) { t.notes[t.index] = note; t.addrs[t.index] = [1]usize{0} ** stack_frame_count; @@ -1972,6 +1995,8 @@ pub fn Trace(comptime size: usize, comptime stack_frame_count: usize) type { } pub fn dump(t: @This()) void { + if (!enabled) return; + const tty_config = detectTTYConfig(); const stderr = io.getStdErr().writer(); const end = @maximum(t.index, size); diff --git a/src/Module.zig b/src/Module.zig index 724fa2ebc4..602b91a5ba 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -2529,11 +2529,9 @@ pub const SrcLoc = struct { /// where in semantic analysis the value got set. const TracedOffset = struct { x: i32, - trace: Trace = trace_init, + trace: std.debug.Trace = .{}, - const want_tracing = builtin.mode == .Debug; - const trace_init = if (want_tracing) std.debug.Trace(1, 3){} else {}; - const Trace = @TypeOf(trace_init); + const want_tracing = std.debug.Trace.enabled; }; /// Resolving a source location into a byte offset may require doing work -- cgit v1.2.3