Current section

Files

Jump to
zigler priv beam stacktrace.zig
Raw

priv/beam/stacktrace.zig

const std = @import("std");
const builtin = @import("builtin");
const beam = @import("beam.zig");
const DebugInfo = std.debug.DebugInfo;
var self_debug_info: ?DebugInfo = null;
fn getSelfDebugInfo() !*DebugInfo {
if (self_debug_info) |*info| {
return info;
} else {
self_debug_info = try std.debug.openSelfDebugInfo(beam.allocator);
return &self_debug_info.?;
}
}
fn make_empty_trace_item(env: beam.env) beam.term {
return beam.make(env, .{
.line_info = null,
.symbol_name = null,
.compile_unit_name = null,
}, .{});
}
fn make_trace_item(env: beam.env, debug_info: *DebugInfo, address: usize) beam.term {
const module = debug_info.getModuleForAddress(address) catch return make_empty_trace_item(env);
const symbol_info = module.getSymbolAtAddress(beam.allocator, address) catch return make_empty_trace_item(env);
defer symbol_info.deinit(beam.allocator);
return beam.make(env, .{
.line_info = symbol_info.line_info,
.symbol_name = symbol_info.symbol_name,
.compile_unit_name = symbol_info.compile_unit_name,
}, .{});
}
pub fn to_term(
env: beam.env,
stacktrace: *std.builtin.StackTrace,
) beam.term {
if (builtin.strip_debug_info) return beam.make(env, .nil, .{});
const debug_info = getSelfDebugInfo() catch return beam.make(env, .nil, .{});
var frame_index: usize = 0;
var frames_left: usize = std.math.min(stacktrace.index, stacktrace.instruction_addresses.len);
var stacktrace_term = beam.make_empty_list(env);
while (frames_left != 0) : ({
frames_left -= 1;
frame_index = (frame_index + 1) % stacktrace.instruction_addresses.len;
}) {
const return_address = stacktrace.instruction_addresses[frame_index];
const new_trace_item = make_trace_item(env, debug_info, return_address - 1);
stacktrace_term = beam.make_list_cell(env, new_trace_item, stacktrace_term);
}
return stacktrace_term;
}