Skip to content

Instantly share code, notes, and snippets.

@andrewrk
Last active June 7, 2022 22:04
Show Gist options
  • Select an option

  • Save andrewrk/b2ab3699d070ce6af0cb1da5019513d7 to your computer and use it in GitHub Desktop.

Select an option

Save andrewrk/b2ab3699d070ce6af0cb1da5019513d7 to your computer and use it in GitHub Desktop.
a new std.debug.Trace API
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;
}
}
};
}
@@ -2105,7 +2105,18 @@ pub const SrcLoc = struct {
const token_starts = tree.tokens.items(.start);
return token_starts[tok_index];
},
- .node_offset, .node_offset_bin_op => |traced_off| {
+ .node_offset => |traced_off| {
const node_off = traced_off.x;
const tree = try src_loc.file_scope.getTree(gpa);
const node = src_loc.declRelativeToNodeIndex(node_off);
assert(src_loc.file_scope.tree_loaded);
const main_tokens = tree.nodes.items(.main_token);
+ traced_off.trace.dump();
const tok_index = main_tokens[node];
const token_starts = tree.tokens.items(.start);
return token_starts[tok_index];
},
.node_offset_bin_op => |node_off| {
@@ -2515,6 +2526,17 @@ pub const SrcLoc = struct {
}
};
+/// This wraps a simple integer in debug builds so that later on we can find out
+/// where in semantic analysis the value got set.
+const TracedOffset = struct {
+ x: i32,
+ trace: Trace = trace_init,
+
+ const want_tracing = builtin.mode == .Debug;
+ const trace_init = if (want_tracing) std.debug.Trace(1, 3){} else {};
+ const Trace = @TypeOf(trace_init);
+};
+
@@ -2555,7 +2577,7 @@ pub const LazySrcLoc = union(enum) {
/// The source location points to an AST node, which is this value offset
/// from its containing Decl node AST index.
/// The Decl is determined contextually.
- node_offset: i32,
+ node_offset: TracedOffset,
/// The source location points to two tokens left of the first token of an AST node,
/// which is this value offset from its containing Decl node AST index.
/// The Decl is determined contextually.
@@ -2705,6 +2727,18 @@ pub const LazySrcLoc = union(enum) {
/// The Decl is determined contextually.
node_offset_array_type_elem: i32,
+ pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
+
+ noinline fn nodeOffsetDebug(node_offset: i32) LazySrcLoc {
+ var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } };
+ result.node_offset.trace.addAddr(@returnAddress(), "init");
+ return result;
+ }
+
+ fn nodeOffsetRelease(node_offset: i32) LazySrcLoc {
+ return .{ .node_offset = .{ .x = node_offset } };
+ }
+
/// Upgrade to a `SrcLoc` based on the `Decl` provided.
pub fn toSrcLoc(lazy: LazySrcLoc, decl: *Decl) SrcLoc {
return switch (lazy) {
@@ -4014,7 +4048,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
const body = zir.extra[extra.end..][0..extra.data.body_len];
const result_ref = (try sema.analyzeBodyBreak(&block_scope, body)).?.operand;
try wip_captures.finalize();
- const src: LazySrcLoc = .{ .node_offset = 0 };
+ const src = LazySrcLoc.nodeOffset(0);
[nix-shell:~/dev/zig/build-release]$ stage2/bin/zig test test3.zig
thread 18654 panic: index out of bounds
/home/andy/dev/zig/src/Module.zig:2115:46: 0x2f76876 in Module.SrcLoc.byteOffset (zig)
const tok_index = main_tokens[node];
^
/home/andy/dev/zig/src/Compilation.zig:451:66: 0x2f705f6 in Compilation.AllErrors.add (zig)
const byte_offset = try module_err_msg.src_loc.byteOffset(module.gpa);
^
/home/andy/dev/zig/src/Compilation.zig:2568:38: 0x2dd1aa3 in Compilation.getAllErrorsAlloc (zig)
try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*);
^
/home/andy/dev/zig/src/main.zig:3121:44: 0x2d3bf6a in updateModule (zig)
var errors = try comp.getAllErrorsAlloc();
^
/home/andy/dev/zig/src/main.zig:2808:17: 0x2d04a59 in buildOutputType (zig)
updateModule(gpa, comp, hook) catch |err| switch (err) {
^
/home/andy/dev/zig/src/main.zig:225:31: 0x2cea926 in mainArgs (zig)
return buildOutputType(gpa, arena, args, .zig_test);
^
/home/andy/dev/zig/src/main.zig:174:20: 0x2ce9974 in main (zig)
return mainArgs(gpa, arena, args);
^
/home/andy/dev/zig/lib/std/start.zig:581:37: 0x31d5bf7 in std.start.callMain (zig)
const result = root.main() catch |err| {
^
/home/andy/dev/zig/lib/std/start.zig:515:12: 0x2cec3c7 in std.start.callMainWithArgs (zig)
return @call(.{ .modifier = .always_inline }, callMain, .{});
^
/home/andy/dev/zig/lib/std/start.zig:480:12: 0x2cec172 in std.start.main (zig)
return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
^
Aborted (core dumped)
[nix-shell:~/dev/zig/build-release]$ stage2/bin/zig test test3.zig
init:
/home/andy/dev/zig/src/Zir.zig:2441:45: 0x31b8ba5 in Zir.struct:2432:18.src (zig)
return LazySrcLoc.nodeOffset(self.src_node);
^
/home/andy/dev/zig/src/Sema.zig:5030:35: 0x339fde6 in Sema.zirCall (zig)
const call_src = inst_data.src();
^
/home/andy/dev/zig/src/Sema.zig:712:62: 0x322dbe7 in Sema.analyzeBodyInner (zig)
.call => try sema.zirCall(block, inst),
^
thread 18654 panic: index out of bounds
/home/andy/dev/zig/src/Module.zig:2115:46: 0x2f76876 in Module.SrcLoc.byteOffset (zig)
const tok_index = main_tokens[node];
^
/home/andy/dev/zig/src/Compilation.zig:451:66: 0x2f705f6 in Compilation.AllErrors.add (zig)
const byte_offset = try module_err_msg.src_loc.byteOffset(module.gpa);
^
/home/andy/dev/zig/src/Compilation.zig:2568:38: 0x2dd1aa3 in Compilation.getAllErrorsAlloc (zig)
try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*);
^
/home/andy/dev/zig/src/main.zig:3121:44: 0x2d3bf6a in updateModule (zig)
var errors = try comp.getAllErrorsAlloc();
^
/home/andy/dev/zig/src/main.zig:2808:17: 0x2d04a59 in buildOutputType (zig)
updateModule(gpa, comp, hook) catch |err| switch (err) {
^
/home/andy/dev/zig/src/main.zig:225:31: 0x2cea926 in mainArgs (zig)
return buildOutputType(gpa, arena, args, .zig_test);
^
/home/andy/dev/zig/src/main.zig:174:20: 0x2ce9974 in main (zig)
return mainArgs(gpa, arena, args);
^
/home/andy/dev/zig/lib/std/start.zig:581:37: 0x31d5bf7 in std.start.callMain (zig)
const result = root.main() catch |err| {
^
/home/andy/dev/zig/lib/std/start.zig:515:12: 0x2cec3c7 in std.start.callMainWithArgs (zig)
return @call(.{ .modifier = .always_inline }, callMain, .{});
^
/home/andy/dev/zig/lib/std/start.zig:480:12: 0x2cec172 in std.start.main (zig)
return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
^
Aborted (core dumped)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment