aboutsummaryrefslogtreecommitdiff
path: root/lib/std/debug.zig
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/debug.zig')
-rw-r--r--lib/std/debug.zig82
1 files changed, 82 insertions, 0 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 7fb632084b..ba45b16d1b 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -1943,3 +1943,85 @@ test "#4353: std.debug should manage resources correctly" {
noinline fn showMyTrace() usize {
return @returnAddress();
}
+
+/// 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: [actual_size][stack_frame_count]usize = undefined,
+ notes: [actual_size][]const u8 = undefined,
+ index: Index = 0,
+
+ const actual_size = if (enabled) size else 0;
+ const Index = if (enabled) usize else u0;
+
+ 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;
+ 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 {
+ if (!enabled) return;
+
+ 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;
+ }
+ }
+ };
+}