Current section
Files
Jump to
Current section
Files
priv/beam/stacktrace.zig
const std = @import("std");
const builtin = @import("builtin");
const beam = @import("beam.zig");
const options = @import("options.zig");
const DebugInfo = std.debug.DebugInfo;
var self_debug_info: ?DebugInfo = null;
fn getSelfDebugInfo(opts: anytype) !*DebugInfo {
if (self_debug_info) |*info| {
return info;
} else {
self_debug_info = try std.debug.openSelfDebugInfo(options.allocator(opts));
return &self_debug_info.?;
}
}
fn make_empty_trace_item(opts: anytype) beam.term {
return beam.make(.{
.line_info = null,
.symbol_name = null,
.compile_unit_name = null,
}, opts);
}
fn make_trace_item(debug_info: *DebugInfo, address: usize, opts: anytype) beam.term {
const module = debug_info.getModuleForAddress(address) catch return make_empty_trace_item(opts);
const symbol_info = module.getSymbolAtAddress(beam.allocator, address) catch return make_empty_trace_item(opts);
defer symbol_info.deinit(options.allocator(opts));
return beam.make(.{
.line_info = symbol_info.line_info,
.symbol_name = symbol_info.symbol_name,
.compile_unit_name = symbol_info.compile_unit_name,
}, opts);
}
pub fn to_term(stacktrace: *std.builtin.StackTrace, opts: anytype) beam.term {
if (builtin.strip_debug_info) return beam.make(.nil, opts);
const debug_info = getSelfDebugInfo(opts) catch return beam.make(.nil, opts);
var frame_index: usize = 0;
var frames_left: usize = @min(stacktrace.index, stacktrace.instruction_addresses.len);
var stacktrace_term = beam.make_empty_list(opts);
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(debug_info, return_address - 1, opts);
stacktrace_term = beam.make_list_cell(new_trace_item, stacktrace_term, opts);
}
return stacktrace_term;
}