*WIP* proof of concept error return traces
This commit is contained in:
parent
7ec783876a
commit
32ea6f54e5
12
build.zig
12
build.zig
@ -10,7 +10,7 @@ const ArrayList = std.ArrayList;
|
||||
const Buffer = std.Buffer;
|
||||
const io = std.io;
|
||||
|
||||
pub fn build(b: &Builder) {
|
||||
pub fn build(b: &Builder) -> %void {
|
||||
const mode = b.standardReleaseOptions();
|
||||
|
||||
var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
|
||||
@ -36,7 +36,7 @@ pub fn build(b: &Builder) {
|
||||
const test_step = b.step("test", "Run all the tests");
|
||||
|
||||
// find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library
|
||||
const build_info = b.exec([][]const u8{b.zig_exe, "BUILD_INFO"});
|
||||
const build_info = try b.exec([][]const u8{b.zig_exe, "BUILD_INFO"});
|
||||
var index: usize = 0;
|
||||
const cmake_binary_dir = nextValue(&index, build_info);
|
||||
const cxx_compiler = nextValue(&index, build_info);
|
||||
@ -68,7 +68,7 @@ pub fn build(b: &Builder) {
|
||||
dependOnLib(exe, llvm);
|
||||
|
||||
if (exe.target.getOs() == builtin.Os.linux) {
|
||||
const libstdcxx_path_padded = b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});
|
||||
const libstdcxx_path_padded = try b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});
|
||||
const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();
|
||||
exe.addObjectFile(libstdcxx_path);
|
||||
|
||||
@ -155,9 +155,9 @@ const LibraryDep = struct {
|
||||
};
|
||||
|
||||
fn findLLVM(b: &Builder, llvm_config_exe: []const u8) -> %LibraryDep {
|
||||
const libs_output = b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
|
||||
const includes_output = b.exec([][]const u8{llvm_config_exe, "--includedir"});
|
||||
const libdir_output = b.exec([][]const u8{llvm_config_exe, "--libdir"});
|
||||
const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
|
||||
const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"});
|
||||
const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"});
|
||||
|
||||
var result = LibraryDep {
|
||||
.libs = ArrayList([]const u8).init(b.allocator),
|
||||
|
@ -1205,6 +1205,7 @@ struct FnTableEntry {
|
||||
uint32_t alignstack_value;
|
||||
|
||||
ZigList<FnExport> export_list;
|
||||
bool calls_errorable_function;
|
||||
};
|
||||
|
||||
uint32_t fn_table_entry_hash(FnTableEntry*);
|
||||
@ -1530,6 +1531,7 @@ struct CodeGen {
|
||||
FnTableEntry *panic_fn;
|
||||
LLVMValueRef cur_ret_ptr;
|
||||
LLVMValueRef cur_fn_val;
|
||||
LLVMValueRef cur_err_ret_trace_val;
|
||||
bool c_want_stdint;
|
||||
bool c_want_stdbool;
|
||||
AstNode *root_export_decl;
|
||||
|
@ -869,7 +869,7 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g) {
|
||||
TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g) {
|
||||
if (g->stack_trace_type == nullptr) {
|
||||
ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace");
|
||||
assert(stack_trace_type_val->type->id == TypeTableEntryIdMetaType);
|
||||
@ -1191,6 +1191,9 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||
}
|
||||
|
||||
TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);
|
||||
if (type_is_invalid(type_entry)) {
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
if (fn_type_id.cc != CallingConventionUnspecified) {
|
||||
type_ensure_zero_bits_known(g, type_entry);
|
||||
if (!type_has_bits(type_entry)) {
|
||||
@ -2586,6 +2589,7 @@ static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, TypeTableEntr
|
||||
}
|
||||
|
||||
static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
|
||||
return; // TODO
|
||||
AstNode *proto_node = panic_fn->proto_node;
|
||||
assert(proto_node->type == NodeTypeFnProto);
|
||||
TypeTableEntry *fn_type = panic_fn->type_entry;
|
||||
|
@ -187,6 +187,7 @@ void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, G
|
||||
|
||||
|
||||
ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
|
||||
TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g);
|
||||
|
||||
|
||||
#endif
|
||||
|
106
src/codegen.cpp
106
src/codegen.cpp
@ -22,6 +22,8 @@
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
static const size_t stack_trace_ptr_count = 31;
|
||||
|
||||
static void init_darwin_native(CodeGen *g) {
|
||||
char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");
|
||||
char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");
|
||||
@ -867,16 +869,24 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
|
||||
return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));
|
||||
}
|
||||
|
||||
static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {
|
||||
static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {
|
||||
assert(g->panic_fn != nullptr);
|
||||
LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
|
||||
LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);
|
||||
ZigLLVMBuildCall(g->builder, fn_val, &msg_arg, 1, llvm_cc, ZigLLVM_FnInlineAuto, "");
|
||||
if (stack_trace_arg == nullptr) {
|
||||
TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
|
||||
stack_trace_arg = LLVMConstNull(ptr_to_stack_trace_type->type_ref);
|
||||
}
|
||||
LLVMValueRef args[] = {
|
||||
msg_arg,
|
||||
stack_trace_arg,
|
||||
};
|
||||
ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, "");
|
||||
LLVMBuildUnreachable(g->builder);
|
||||
}
|
||||
|
||||
static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) {
|
||||
gen_panic(g, get_panic_msg_ptr_val(g, msg_id));
|
||||
gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);
|
||||
}
|
||||
|
||||
static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
|
||||
@ -956,7 +966,11 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
|
||||
LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_array, offset_ptr_indices, 2);
|
||||
|
||||
Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false);
|
||||
LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), &g->err_tag_type->type_ref, 1, false);
|
||||
LLVMTypeRef arg_types[] = {
|
||||
g->err_tag_type->type_ref,
|
||||
g->ptr_to_stack_trace_type->type_ref,
|
||||
};
|
||||
LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
|
||||
LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
|
||||
addLLVMFnAttr(fn_val, "noreturn");
|
||||
addLLVMFnAttr(fn_val, "cold");
|
||||
@ -1008,7 +1022,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
|
||||
LLVMValueRef global_slice_len_field_ptr = LLVMBuildStructGEP(g->builder, global_slice, slice_len_index, "");
|
||||
gen_store(g, full_buf_len, global_slice_len_field_ptr, u8_ptr_type);
|
||||
|
||||
gen_panic(g, global_slice);
|
||||
gen_panic(g, global_slice, LLVMGetParam(fn_val, 1));
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, prev_block);
|
||||
LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
|
||||
@ -1019,7 +1033,16 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
|
||||
|
||||
static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
|
||||
LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);
|
||||
ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified),
|
||||
LLVMValueRef err_ret_trace_val = g->cur_err_ret_trace_val;
|
||||
if (err_ret_trace_val == nullptr) {
|
||||
TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
|
||||
err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref);
|
||||
}
|
||||
LLVMValueRef args[] = {
|
||||
err_val,
|
||||
err_ret_trace_val,
|
||||
};
|
||||
ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2, get_llvm_cc(g, CallingConventionUnspecified),
|
||||
ZigLLVM_FnInlineAuto, "");
|
||||
LLVMBuildUnreachable(g->builder);
|
||||
}
|
||||
@ -1299,6 +1322,50 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
|
||||
static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
|
||||
LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
|
||||
TypeTableEntry *return_type = return_instruction->value->value.type;
|
||||
|
||||
bool is_err_return = false;
|
||||
if (return_type->id == TypeTableEntryIdErrorUnion) {
|
||||
if (return_instruction->value->value.special == ConstValSpecialStatic) {
|
||||
is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr;
|
||||
} else if (return_instruction->value->value.special == ConstValSpecialRuntime) {
|
||||
is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError;
|
||||
// TODO: emit a branch to check if the return value is an error
|
||||
}
|
||||
} else if (return_type->id == TypeTableEntryIdPureError) {
|
||||
is_err_return = true;
|
||||
}
|
||||
if (is_err_return) {
|
||||
LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
|
||||
|
||||
// stack_trace.instruction_addresses[stack_trace.index % stack_trace_ptr_count] = @instructionPointer();
|
||||
// stack_trace.index += 1;
|
||||
|
||||
LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnError");
|
||||
|
||||
LLVMValueRef block_address = LLVMBlockAddress(g->cur_fn_val, return_block);
|
||||
size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
|
||||
LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, "");
|
||||
size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
|
||||
LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)addresses_field_index, "");
|
||||
|
||||
// stack_trace.instruction_addresses[stack_trace.index % stack_trace_ptr_count] = @instructionPointer();
|
||||
LLVMValueRef index_val = gen_load_untyped(g, index_field_ptr, 0, false, "");
|
||||
LLVMValueRef modded_val = LLVMBuildURem(g->builder, index_val, LLVMConstInt(usize_type_ref, stack_trace_ptr_count, false), "");
|
||||
LLVMValueRef address_indices[] = {
|
||||
LLVMConstNull(usize_type_ref),
|
||||
modded_val,
|
||||
};
|
||||
LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, addresses_field_ptr, address_indices, 2, "");
|
||||
LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, block_address, usize_type_ref, "");
|
||||
gen_store_untyped(g, address_value, address_slot, 0, false);
|
||||
|
||||
// stack_trace.index += 1;
|
||||
LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");
|
||||
gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);
|
||||
|
||||
LLVMBuildBr(g->builder, return_block);
|
||||
LLVMPositionBuilderAtEnd(g->builder, return_block);
|
||||
}
|
||||
if (handle_is_ptr(return_type)) {
|
||||
if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
|
||||
assert(g->cur_ret_ptr);
|
||||
@ -2353,7 +2420,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
||||
}
|
||||
}
|
||||
if (last_arg_err_ret_stack) {
|
||||
gen_param_values[gen_param_index] = LLVMGetUndef(g->ptr_to_stack_trace_type->type_ref);
|
||||
gen_param_values[gen_param_index] = g->cur_err_ret_trace_val;
|
||||
gen_param_index += 1;
|
||||
}
|
||||
|
||||
@ -3482,7 +3549,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {
|
||||
gen_panic(g, ir_llvm_value(g, instruction->msg));
|
||||
gen_panic(g, ir_llvm_value(g, instruction->msg), nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -4501,7 +4568,8 @@ static void do_code_gen(CodeGen *g) {
|
||||
LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
|
||||
g->cur_fn = fn_table_entry;
|
||||
g->cur_fn_val = fn;
|
||||
if (handle_is_ptr(fn_table_entry->type_entry->data.fn.fn_type_id.return_type)) {
|
||||
TypeTableEntry *return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
|
||||
if (handle_is_ptr(return_type)) {
|
||||
g->cur_ret_ptr = LLVMGetParam(fn, 0);
|
||||
} else {
|
||||
g->cur_ret_ptr = nullptr;
|
||||
@ -4510,6 +4578,18 @@ static void do_code_gen(CodeGen *g) {
|
||||
build_all_basic_blocks(g, fn_table_entry);
|
||||
clear_debug_source_node(g);
|
||||
|
||||
if (return_type->id == TypeTableEntryIdPureError || return_type->id == TypeTableEntryIdErrorUnion) {
|
||||
g->cur_err_ret_trace_val = LLVMGetParam(fn, LLVMCountParamTypes(fn_table_entry->type_entry->data.fn.raw_type_ref) - 1);
|
||||
} else if (fn_table_entry->calls_errorable_function) {
|
||||
g->cur_err_ret_trace_val = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type));
|
||||
size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
|
||||
LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, "");
|
||||
TypeTableEntry *usize = g->builtin_types.entry_usize;
|
||||
gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
|
||||
} else {
|
||||
g->cur_err_ret_trace_val = nullptr;
|
||||
}
|
||||
|
||||
// allocate temporary stack data
|
||||
for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {
|
||||
IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);
|
||||
@ -5096,12 +5176,11 @@ static void define_builtin_compile_vars(CodeGen *g) {
|
||||
os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
|
||||
Buf *contents = buf_alloc();
|
||||
|
||||
buf_append_str(contents,
|
||||
buf_appendf(contents,
|
||||
"pub const StackTrace = struct {\n"
|
||||
" index: usize,\n"
|
||||
" instruction_addresses: [31]usize,\n"
|
||||
"};\n\n"
|
||||
);
|
||||
" instruction_addresses: [%" ZIG_PRI_usize "]usize,\n"
|
||||
"};\n\n", stack_trace_ptr_count);
|
||||
|
||||
const char *cur_os = nullptr;
|
||||
{
|
||||
@ -5266,6 +5345,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
|
||||
g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
|
||||
g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
|
||||
g->compile_var_import = add_source_file(g, g->compile_var_package, abs_full_path, contents);
|
||||
scan_import(g, g->compile_var_import);
|
||||
}
|
||||
|
||||
static void init(CodeGen *g) {
|
||||
|
12
src/ir.cpp
12
src/ir.cpp
@ -10043,9 +10043,21 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||
TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
|
||||
ir_add_alloca(ira, new_call_instruction, return_type);
|
||||
|
||||
if (return_type->id == TypeTableEntryIdPureError || return_type->id == TypeTableEntryIdErrorUnion) {
|
||||
parent_fn_entry->calls_errorable_function = true;
|
||||
}
|
||||
|
||||
return ir_finish_anal(ira, return_type);
|
||||
}
|
||||
|
||||
FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
|
||||
assert(fn_type_id->return_type != nullptr);
|
||||
assert(parent_fn_entry != nullptr);
|
||||
if (fn_type_id->return_type->id == TypeTableEntryIdPureError || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) {
|
||||
parent_fn_entry->calls_errorable_function = true;
|
||||
}
|
||||
|
||||
|
||||
IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
|
||||
size_t next_arg_index = 0;
|
||||
if (first_arg_ptr) {
|
||||
|
@ -721,11 +721,9 @@ pub const Builder = struct {
|
||||
return error.FileNotFound;
|
||||
}
|
||||
|
||||
pub fn exec(self: &Builder, argv: []const []const u8) -> []u8 {
|
||||
pub fn exec(self: &Builder, argv: []const []const u8) -> %[]u8 {
|
||||
const max_output_size = 100 * 1024;
|
||||
const result = os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size) catch |err| {
|
||||
std.debug.panic("Unable to spawn {}: {}", argv[0], @errorName(err));
|
||||
};
|
||||
const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size);
|
||||
switch (result.term) {
|
||||
os.ChildProcess.Term.Exited => |code| {
|
||||
if (code != 0) {
|
||||
|
@ -37,10 +37,16 @@ fn getStderrStream() -> %&io.OutStream {
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
|
||||
pub fn dumpStackTrace() {
|
||||
/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
|
||||
pub fn dumpCurrentStackTrace() {
|
||||
const stderr = getStderrStream() catch return;
|
||||
writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch return;
|
||||
writeCurrentStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch return;
|
||||
}
|
||||
|
||||
/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
|
||||
pub fn dumpStackTrace(stack_trace: &builtin.StackTrace) {
|
||||
const stderr = getStderrStream() catch return;
|
||||
writeStackTrace(stack_trace, stderr, global_allocator, stderr_file.isTty()) catch return;
|
||||
}
|
||||
|
||||
/// This function invokes undefined behavior when `ok` is `false`.
|
||||
@ -88,7 +94,7 @@ pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
|
||||
|
||||
const stderr = getStderrStream() catch os.abort();
|
||||
stderr.print(format ++ "\n", args) catch os.abort();
|
||||
writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch os.abort();
|
||||
writeCurrentStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch os.abort();
|
||||
|
||||
os.abort();
|
||||
}
|
||||
@ -101,7 +107,103 @@ const RESET = "\x1b[0m";
|
||||
error PathNotFound;
|
||||
error InvalidDebugInfo;
|
||||
|
||||
pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,
|
||||
pub fn writeStackTrace(st_addrs: &builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool) -> %void {
|
||||
switch (builtin.object_format) {
|
||||
builtin.ObjectFormat.elf => {
|
||||
var stack_trace = ElfStackTrace {
|
||||
.self_exe_file = undefined,
|
||||
.elf = undefined,
|
||||
.debug_info = undefined,
|
||||
.debug_abbrev = undefined,
|
||||
.debug_str = undefined,
|
||||
.debug_line = undefined,
|
||||
.debug_ranges = null,
|
||||
.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
|
||||
.compile_unit_list = ArrayList(CompileUnit).init(allocator),
|
||||
};
|
||||
const st = &stack_trace;
|
||||
st.self_exe_file = try os.openSelfExe();
|
||||
defer st.self_exe_file.close();
|
||||
|
||||
try st.elf.openFile(allocator, &st.self_exe_file);
|
||||
defer st.elf.close();
|
||||
|
||||
st.debug_info = (try st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
|
||||
st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
|
||||
st.debug_str = (try st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo;
|
||||
st.debug_line = (try st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
|
||||
st.debug_ranges = (try st.elf.findSection(".debug_ranges"));
|
||||
try scanAllCompileUnits(st);
|
||||
|
||||
var ignored_count: usize = 0;
|
||||
|
||||
var frame_index: usize = undefined;
|
||||
var frames_left: usize = undefined;
|
||||
if (st_addrs.index < st_addrs.instruction_addresses.len) {
|
||||
frame_index = 0;
|
||||
frames_left = st_addrs.index;
|
||||
} else {
|
||||
frame_index = (st_addrs.index + 1) % st_addrs.instruction_addresses.len;
|
||||
frames_left = st_addrs.instruction_addresses.len;
|
||||
}
|
||||
|
||||
while (frames_left != 0) : ({frames_left -= 1; frame_index = (frame_index + 1) % st_addrs.instruction_addresses.len;}) {
|
||||
const return_address = st_addrs.instruction_addresses[frame_index];
|
||||
|
||||
// TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
|
||||
// at compile time. I'll call it issue #313
|
||||
const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
|
||||
|
||||
const compile_unit = findCompileUnit(st, return_address) catch {
|
||||
try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
|
||||
return_address);
|
||||
continue;
|
||||
};
|
||||
const compile_unit_name = try compile_unit.die.getAttrString(st, DW.AT_name);
|
||||
if (getLineNumberInfo(st, compile_unit, usize(return_address) - 1)) |line_info| {
|
||||
defer line_info.deinit();
|
||||
try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
|
||||
DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
|
||||
line_info.file_name, line_info.line, line_info.column,
|
||||
return_address, compile_unit_name);
|
||||
if (printLineFromFile(st.allocator(), out_stream, line_info)) {
|
||||
if (line_info.column == 0) {
|
||||
try out_stream.write("\n");
|
||||
} else {
|
||||
{var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
|
||||
try out_stream.writeByte(' ');
|
||||
}}
|
||||
try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
|
||||
}
|
||||
} else |err| switch (err) {
|
||||
error.EndOfFile, error.PathNotFound => {},
|
||||
else => return err,
|
||||
}
|
||||
} else |err| switch (err) {
|
||||
error.MissingDebugInfo, error.InvalidDebugInfo => {
|
||||
try out_stream.print(ptr_hex ++ " in ??? ({})\n",
|
||||
return_address, compile_unit_name);
|
||||
},
|
||||
else => return err,
|
||||
}
|
||||
}
|
||||
},
|
||||
builtin.ObjectFormat.coff => {
|
||||
try out_stream.write("(stack trace unavailable for COFF object format)\n");
|
||||
},
|
||||
builtin.ObjectFormat.macho => {
|
||||
try out_stream.write("(stack trace unavailable for Mach-O object format)\n");
|
||||
},
|
||||
builtin.ObjectFormat.wasm => {
|
||||
try out_stream.write("(stack trace unavailable for WASM object format)\n");
|
||||
},
|
||||
builtin.ObjectFormat.unknown => {
|
||||
try out_stream.write("(stack trace unavailable for unknown object format)\n");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,
|
||||
ignore_frame_count: usize) -> %void
|
||||
{
|
||||
switch (builtin.object_format) {
|
||||
|
@ -112,7 +112,7 @@ pub fn main() -> %void {
|
||||
}
|
||||
|
||||
builder.setInstallPrefix(prefix);
|
||||
root.build(&builder);
|
||||
root.build(&builder) catch unreachable;
|
||||
|
||||
if (builder.validateUserInputDidItFail())
|
||||
return usageAndErr(&builder, true, try stderr_stream);
|
||||
@ -129,7 +129,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
|
||||
// run the build script to collect the options
|
||||
if (!already_ran_build) {
|
||||
builder.setInstallPrefix(null);
|
||||
root.build(builder);
|
||||
root.build(builder) catch unreachable;
|
||||
}
|
||||
|
||||
// This usage text has to be synchronized with src/main.cpp
|
||||
|
@ -5,7 +5,7 @@ const builtin = @import("builtin");
|
||||
|
||||
// Avoid dragging in the debug safety mechanisms into this .o file,
|
||||
// unless we're trying to test this file.
|
||||
pub coldcc fn panic(msg: []const u8) -> noreturn {
|
||||
pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
|
||||
if (builtin.is_test) {
|
||||
@import("std").debug.panic("{}", msg);
|
||||
} else {
|
||||
|
@ -74,7 +74,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
|
||||
|
||||
// Avoid dragging in the debug safety mechanisms into this .o file,
|
||||
// unless we're trying to test this file.
|
||||
pub coldcc fn panic(msg: []const u8) -> noreturn {
|
||||
pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
|
||||
if (is_test) {
|
||||
@import("std").debug.panic("{}", msg);
|
||||
} else {
|
||||
|
@ -4,14 +4,20 @@
|
||||
// have to be added in the compiler.
|
||||
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
|
||||
pub coldcc fn panic(msg: []const u8) -> noreturn {
|
||||
pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
|
||||
switch (builtin.os) {
|
||||
// TODO: fix panic in zen.
|
||||
builtin.Os.freestanding, builtin.Os.zen => {
|
||||
while (true) {}
|
||||
},
|
||||
else => {
|
||||
if (error_return_trace) |trace| {
|
||||
std.debug.warn("{}\n", msg);
|
||||
std.debug.dumpStackTrace(trace);
|
||||
@import("std").debug.panic("");
|
||||
}
|
||||
@import("std").debug.panic("{}", msg);
|
||||
},
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user