authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-12 02:12:11-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-12 02:12:11-05:00
log32ea6f54e5f05c4173828c4f4c8ab9965a929120
treef4c48c5be138070207c19629c08d763c8a6a1325
parent7ec783876a565662223268a70ba984e0a132b94a

*WIP* proof of concept error return traces


12 files changed, 238 insertions(+), 33 deletions(-)

build.zig+6-6
...@@ -10,7 +10,7 @@ const ArrayList = std.ArrayList;...@@ -10,7 +10,7 @@ const ArrayList = std.ArrayList;
10const Buffer = std.Buffer;10const Buffer = std.Buffer;
11const io = std.io;11const io = std.io;
1212
13pub fn build(b: &Builder) {13pub fn build(b: &Builder) -> %void {
14 const mode = b.standardReleaseOptions();14 const mode = b.standardReleaseOptions();
1515
16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
...@@ -36,7 +36,7 @@ pub fn build(b: &Builder) {...@@ -36,7 +36,7 @@ pub fn build(b: &Builder) {
36 const test_step = b.step("test", "Run all the tests");36 const test_step = b.step("test", "Run all the tests");
3737
38 // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library38 // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library
39 const build_info = b.exec([][]const u8{b.zig_exe, "BUILD_INFO"});39 const build_info = try b.exec([][]const u8{b.zig_exe, "BUILD_INFO"});
40 var index: usize = 0;40 var index: usize = 0;
41 const cmake_binary_dir = nextValue(&index, build_info);41 const cmake_binary_dir = nextValue(&index, build_info);
42 const cxx_compiler = nextValue(&index, build_info);42 const cxx_compiler = nextValue(&index, build_info);
...@@ -68,7 +68,7 @@ pub fn build(b: &Builder) {...@@ -68,7 +68,7 @@ pub fn build(b: &Builder) {
68 dependOnLib(exe, llvm);68 dependOnLib(exe, llvm);
6969
70 if (exe.target.getOs() == builtin.Os.linux) {70 if (exe.target.getOs() == builtin.Os.linux) {
71 const libstdcxx_path_padded = b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});71 const libstdcxx_path_padded = try b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});
72 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();72 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();
73 exe.addObjectFile(libstdcxx_path);73 exe.addObjectFile(libstdcxx_path);
7474
...@@ -155,9 +155,9 @@ const LibraryDep = struct {...@@ -155,9 +155,9 @@ const LibraryDep = struct {
155};155};
156156
157fn findLLVM(b: &Builder, llvm_config_exe: []const u8) -> %LibraryDep {157fn findLLVM(b: &Builder, llvm_config_exe: []const u8) -> %LibraryDep {
158 const libs_output = b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});158 const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
159 const includes_output = b.exec([][]const u8{llvm_config_exe, "--includedir"});159 const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"});
160 const libdir_output = b.exec([][]const u8{llvm_config_exe, "--libdir"});160 const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"});
161161
162 var result = LibraryDep {162 var result = LibraryDep {
163 .libs = ArrayList([]const u8).init(b.allocator),163 .libs = ArrayList([]const u8).init(b.allocator),
src/all_types.hpp+2
...@@ -1205,6 +1205,7 @@ struct FnTableEntry {...@@ -1205,6 +1205,7 @@ struct FnTableEntry {
1205 uint32_t alignstack_value;1205 uint32_t alignstack_value;
12061206
1207 ZigList<FnExport> export_list;1207 ZigList<FnExport> export_list;
1208 bool calls_errorable_function;
1208};1209};
12091210
1210uint32_t fn_table_entry_hash(FnTableEntry*);1211uint32_t fn_table_entry_hash(FnTableEntry*);
...@@ -1530,6 +1531,7 @@ struct CodeGen {...@@ -1530,6 +1531,7 @@ struct CodeGen {
1530 FnTableEntry *panic_fn;1531 FnTableEntry *panic_fn;
1531 LLVMValueRef cur_ret_ptr;1532 LLVMValueRef cur_ret_ptr;
1532 LLVMValueRef cur_fn_val;1533 LLVMValueRef cur_fn_val;
1534 LLVMValueRef cur_err_ret_trace_val;
1533 bool c_want_stdint;1535 bool c_want_stdint;
1534 bool c_want_stdbool;1536 bool c_want_stdbool;
1535 AstNode *root_export_decl;1537 AstNode *root_export_decl;
src/analyze.cpp+5-1
...@@ -869,7 +869,7 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) {...@@ -869,7 +869,7 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) {
869 zig_unreachable();869 zig_unreachable();
870}870}
871871
872static TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g) {872TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g) {
873 if (g->stack_trace_type == nullptr) {873 if (g->stack_trace_type == nullptr) {
874 ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace");874 ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace");
875 assert(stack_trace_type_val->type->id == TypeTableEntryIdMetaType);875 assert(stack_trace_type_val->type->id == TypeTableEntryIdMetaType);
...@@ -1191,6 +1191,9 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1191,6 +1191,9 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1191 }1191 }
11921192
1193 TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);1193 TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);
1194 if (type_is_invalid(type_entry)) {
1195 return g->builtin_types.entry_invalid;
1196 }
1194 if (fn_type_id.cc != CallingConventionUnspecified) {1197 if (fn_type_id.cc != CallingConventionUnspecified) {
1195 type_ensure_zero_bits_known(g, type_entry);1198 type_ensure_zero_bits_known(g, type_entry);
1196 if (!type_has_bits(type_entry)) {1199 if (!type_has_bits(type_entry)) {
...@@ -2586,6 +2589,7 @@ static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, TypeTableEntr...@@ -2586,6 +2589,7 @@ static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, TypeTableEntr
2586}2589}
25872590
2588static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {2591static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
2592 return; // TODO
2589 AstNode *proto_node = panic_fn->proto_node;2593 AstNode *proto_node = panic_fn->proto_node;
2590 assert(proto_node->type == NodeTypeFnProto);2594 assert(proto_node->type == NodeTypeFnProto);
2591 TypeTableEntry *fn_type = panic_fn->type_entry;2595 TypeTableEntry *fn_type = panic_fn->type_entry;
src/analyze.hpp+1
...@@ -187,6 +187,7 @@ void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, G...@@ -187,6 +187,7 @@ void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, G
187187
188188
189ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);189ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
190TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g);
190191
191192
192#endif193#endif
src/codegen.cpp+93-13
...@@ -22,6 +22,8 @@...@@ -22,6 +22,8 @@
22#include <stdio.h>22#include <stdio.h>
23#include <errno.h>23#include <errno.h>
2424
25static const size_t stack_trace_ptr_count = 31;
26
25static void init_darwin_native(CodeGen *g) {27static void init_darwin_native(CodeGen *g) {
26 char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");28 char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");
27 char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");29 char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");
...@@ -867,16 +869,24 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {...@@ -867,16 +869,24 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
867 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));869 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));
868}870}
869871
870static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {872static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {
871 assert(g->panic_fn != nullptr);873 assert(g->panic_fn != nullptr);
872 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);874 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
873 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);875 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);
874 ZigLLVMBuildCall(g->builder, fn_val, &msg_arg, 1, llvm_cc, ZigLLVM_FnInlineAuto, "");876 if (stack_trace_arg == nullptr) {
877 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
878 stack_trace_arg = LLVMConstNull(ptr_to_stack_trace_type->type_ref);
879 }
880 LLVMValueRef args[] = {
881 msg_arg,
882 stack_trace_arg,
883 };
884 ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, "");
875 LLVMBuildUnreachable(g->builder);885 LLVMBuildUnreachable(g->builder);
876}886}
877887
878static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) {888static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) {
879 gen_panic(g, get_panic_msg_ptr_val(g, msg_id));889 gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);
880}890}
881891
882static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {892static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
...@@ -956,7 +966,11 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -956,7 +966,11 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
956 LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_array, offset_ptr_indices, 2);966 LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_array, offset_ptr_indices, 2);
957967
958 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false);968 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false);
959 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), &g->err_tag_type->type_ref, 1, false);969 LLVMTypeRef arg_types[] = {
970 g->err_tag_type->type_ref,
971 g->ptr_to_stack_trace_type->type_ref,
972 };
973 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
960 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);974 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
961 addLLVMFnAttr(fn_val, "noreturn");975 addLLVMFnAttr(fn_val, "noreturn");
962 addLLVMFnAttr(fn_val, "cold");976 addLLVMFnAttr(fn_val, "cold");
...@@ -1008,7 +1022,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1008,7 +1022,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
1008 LLVMValueRef global_slice_len_field_ptr = LLVMBuildStructGEP(g->builder, global_slice, slice_len_index, "");1022 LLVMValueRef global_slice_len_field_ptr = LLVMBuildStructGEP(g->builder, global_slice, slice_len_index, "");
1009 gen_store(g, full_buf_len, global_slice_len_field_ptr, u8_ptr_type);1023 gen_store(g, full_buf_len, global_slice_len_field_ptr, u8_ptr_type);
10101024
1011 gen_panic(g, global_slice);1025 gen_panic(g, global_slice, LLVMGetParam(fn_val, 1));
10121026
1013 LLVMPositionBuilderAtEnd(g->builder, prev_block);1027 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1014 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);1028 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
...@@ -1019,7 +1033,16 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1019,7 +1033,16 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
10191033
1020static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {1034static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
1021 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);1035 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);
1022 ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified),1036 LLVMValueRef err_ret_trace_val = g->cur_err_ret_trace_val;
1037 if (err_ret_trace_val == nullptr) {
1038 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
1039 err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref);
1040 }
1041 LLVMValueRef args[] = {
1042 err_val,
1043 err_ret_trace_val,
1044 };
1045 ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2, get_llvm_cc(g, CallingConventionUnspecified),
1023 ZigLLVM_FnInlineAuto, "");1046 ZigLLVM_FnInlineAuto, "");
1024 LLVMBuildUnreachable(g->builder);1047 LLVMBuildUnreachable(g->builder);
1025}1048}
...@@ -1299,6 +1322,50 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {...@@ -1299,6 +1322,50 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
1299static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {1322static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
1300 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);1323 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
1301 TypeTableEntry *return_type = return_instruction->value->value.type;1324 TypeTableEntry *return_type = return_instruction->value->value.type;
1325
1326 bool is_err_return = false;
1327 if (return_type->id == TypeTableEntryIdErrorUnion) {
1328 if (return_instruction->value->value.special == ConstValSpecialStatic) {
1329 is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr;
1330 } else if (return_instruction->value->value.special == ConstValSpecialRuntime) {
1331 is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError;
1332 // TODO: emit a branch to check if the return value is an error
1333 }
1334 } else if (return_type->id == TypeTableEntryIdPureError) {
1335 is_err_return = true;
1336 }
1337 if (is_err_return) {
1338 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
1339
1340 // stack_trace.instruction_addresses[stack_trace.index % stack_trace_ptr_count] = @instructionPointer();
1341 // stack_trace.index += 1;
1342
1343 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnError");
1344
1345 LLVMValueRef block_address = LLVMBlockAddress(g->cur_fn_val, return_block);
1346 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
1347 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, "");
1348 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
1349 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)addresses_field_index, "");
1350
1351 // stack_trace.instruction_addresses[stack_trace.index % stack_trace_ptr_count] = @instructionPointer();
1352 LLVMValueRef index_val = gen_load_untyped(g, index_field_ptr, 0, false, "");
1353 LLVMValueRef modded_val = LLVMBuildURem(g->builder, index_val, LLVMConstInt(usize_type_ref, stack_trace_ptr_count, false), "");
1354 LLVMValueRef address_indices[] = {
1355 LLVMConstNull(usize_type_ref),
1356 modded_val,
1357 };
1358 LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, addresses_field_ptr, address_indices, 2, "");
1359 LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, block_address, usize_type_ref, "");
1360 gen_store_untyped(g, address_value, address_slot, 0, false);
1361
1362 // stack_trace.index += 1;
1363 LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");
1364 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);
1365
1366 LLVMBuildBr(g->builder, return_block);
1367 LLVMPositionBuilderAtEnd(g->builder, return_block);
1368 }
1302 if (handle_is_ptr(return_type)) {1369 if (handle_is_ptr(return_type)) {
1303 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {1370 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
1304 assert(g->cur_ret_ptr);1371 assert(g->cur_ret_ptr);
...@@ -2353,7 +2420,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -2353,7 +2420,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
2353 }2420 }
2354 }2421 }
2355 if (last_arg_err_ret_stack) {2422 if (last_arg_err_ret_stack) {
2356 gen_param_values[gen_param_index] = LLVMGetUndef(g->ptr_to_stack_trace_type->type_ref);2423 gen_param_values[gen_param_index] = g->cur_err_ret_trace_val;
2357 gen_param_index += 1;2424 gen_param_index += 1;
2358 }2425 }
23592426
...@@ -3482,7 +3549,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec...@@ -3482,7 +3549,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
3482}3549}
34833550
3484static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {3551static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {
3485 gen_panic(g, ir_llvm_value(g, instruction->msg));3552 gen_panic(g, ir_llvm_value(g, instruction->msg), nullptr);
3486 return nullptr;3553 return nullptr;
3487}3554}
34883555
...@@ -4501,7 +4568,8 @@ static void do_code_gen(CodeGen *g) {...@@ -4501,7 +4568,8 @@ static void do_code_gen(CodeGen *g) {
4501 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);4568 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
4502 g->cur_fn = fn_table_entry;4569 g->cur_fn = fn_table_entry;
4503 g->cur_fn_val = fn;4570 g->cur_fn_val = fn;
4504 if (handle_is_ptr(fn_table_entry->type_entry->data.fn.fn_type_id.return_type)) {4571 TypeTableEntry *return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
4572 if (handle_is_ptr(return_type)) {
4505 g->cur_ret_ptr = LLVMGetParam(fn, 0);4573 g->cur_ret_ptr = LLVMGetParam(fn, 0);
4506 } else {4574 } else {
4507 g->cur_ret_ptr = nullptr;4575 g->cur_ret_ptr = nullptr;
...@@ -4510,6 +4578,18 @@ static void do_code_gen(CodeGen *g) {...@@ -4510,6 +4578,18 @@ static void do_code_gen(CodeGen *g) {
4510 build_all_basic_blocks(g, fn_table_entry);4578 build_all_basic_blocks(g, fn_table_entry);
4511 clear_debug_source_node(g);4579 clear_debug_source_node(g);
45124580
4581 if (return_type->id == TypeTableEntryIdPureError || return_type->id == TypeTableEntryIdErrorUnion) {
4582 g->cur_err_ret_trace_val = LLVMGetParam(fn, LLVMCountParamTypes(fn_table_entry->type_entry->data.fn.raw_type_ref) - 1);
4583 } else if (fn_table_entry->calls_errorable_function) {
4584 g->cur_err_ret_trace_val = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type));
4585 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
4586 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, "");
4587 TypeTableEntry *usize = g->builtin_types.entry_usize;
4588 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
4589 } else {
4590 g->cur_err_ret_trace_val = nullptr;
4591 }
4592
4513 // allocate temporary stack data4593 // allocate temporary stack data
4514 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {4594 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {
4515 IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);4595 IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);
...@@ -5096,12 +5176,11 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -5096,12 +5176,11 @@ static void define_builtin_compile_vars(CodeGen *g) {
5096 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);5176 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
5097 Buf *contents = buf_alloc();5177 Buf *contents = buf_alloc();
50985178
5099 buf_append_str(contents,5179 buf_appendf(contents,
5100 "pub const StackTrace = struct {\n"5180 "pub const StackTrace = struct {\n"
5101 " index: usize,\n"5181 " index: usize,\n"
5102 " instruction_addresses: [31]usize,\n"5182 " instruction_addresses: [%" ZIG_PRI_usize "]usize,\n"
5103 "};\n\n"5183 "};\n\n", stack_trace_ptr_count);
5104 );
51055184
5106 const char *cur_os = nullptr;5185 const char *cur_os = nullptr;
5107 {5186 {
...@@ -5266,6 +5345,7 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -5266,6 +5345,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
5266 g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);5345 g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
5267 g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);5346 g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
5268 g->compile_var_import = add_source_file(g, g->compile_var_package, abs_full_path, contents);5347 g->compile_var_import = add_source_file(g, g->compile_var_package, abs_full_path, contents);
5348 scan_import(g, g->compile_var_import);
5269}5349}
52705350
5271static void init(CodeGen *g) {5351static void init(CodeGen *g) {
src/ir.cpp+12
...@@ -10043,9 +10043,21 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -10043,9 +10043,21 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
10043 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;10043 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
10044 ir_add_alloca(ira, new_call_instruction, return_type);10044 ir_add_alloca(ira, new_call_instruction, return_type);
1004510045
10046 if (return_type->id == TypeTableEntryIdPureError || return_type->id == TypeTableEntryIdErrorUnion) {
10047 parent_fn_entry->calls_errorable_function = true;
10048 }
10049
10046 return ir_finish_anal(ira, return_type);10050 return ir_finish_anal(ira, return_type);
10047 }10051 }
1004810052
10053 FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
10054 assert(fn_type_id->return_type != nullptr);
10055 assert(parent_fn_entry != nullptr);
10056 if (fn_type_id->return_type->id == TypeTableEntryIdPureError || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) {
10057 parent_fn_entry->calls_errorable_function = true;
10058 }
10059
10060
10049 IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);10061 IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
10050 size_t next_arg_index = 0;10062 size_t next_arg_index = 0;
10051 if (first_arg_ptr) {10063 if (first_arg_ptr) {
std/build.zig+2-4
...@@ -721,11 +721,9 @@ pub const Builder = struct {...@@ -721,11 +721,9 @@ pub const Builder = struct {
721 return error.FileNotFound;721 return error.FileNotFound;
722 }722 }
723723
724 pub fn exec(self: &Builder, argv: []const []const u8) -> []u8 {724 pub fn exec(self: &Builder, argv: []const []const u8) -> %[]u8 {
725 const max_output_size = 100 * 1024;725 const max_output_size = 100 * 1024;
726 const result = os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size) catch |err| {726 const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size);
727 std.debug.panic("Unable to spawn {}: {}", argv[0], @errorName(err));
728 };
729 switch (result.term) {727 switch (result.term) {
730 os.ChildProcess.Term.Exited => |code| {728 os.ChildProcess.Term.Exited => |code| {
731 if (code != 0) {729 if (code != 0) {
std/debug/index.zig+106-4
...@@ -37,10 +37,16 @@ fn getStderrStream() -> %&io.OutStream {...@@ -37,10 +37,16 @@ fn getStderrStream() -> %&io.OutStream {
37 }37 }
38}38}
3939
40/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
41pub fn dumpCurrentStackTrace() {
42 const stderr = getStderrStream() catch return;
43 writeCurrentStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch return;
44}
45
40/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.46/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
41pub fn dumpStackTrace() {47pub fn dumpStackTrace(stack_trace: &builtin.StackTrace) {
42 const stderr = getStderrStream() catch return;48 const stderr = getStderrStream() catch return;
43 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch return;49 writeStackTrace(stack_trace, stderr, global_allocator, stderr_file.isTty()) catch return;
44}50}
4551
46/// This function invokes undefined behavior when `ok` is `false`.52/// This function invokes undefined behavior when `ok` is `false`.
...@@ -88,7 +94,7 @@ pub fn panic(comptime format: []const u8, args: ...) -> noreturn {...@@ -88,7 +94,7 @@ pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
8894
89 const stderr = getStderrStream() catch os.abort();95 const stderr = getStderrStream() catch os.abort();
90 stderr.print(format ++ "\n", args) catch os.abort();96 stderr.print(format ++ "\n", args) catch os.abort();
91 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch os.abort();97 writeCurrentStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch os.abort();
9298
93 os.abort();99 os.abort();
94}100}
...@@ -101,7 +107,103 @@ const RESET = "\x1b[0m";...@@ -101,7 +107,103 @@ const RESET = "\x1b[0m";
101error PathNotFound;107error PathNotFound;
102error InvalidDebugInfo;108error InvalidDebugInfo;
103109
104pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,110pub fn writeStackTrace(st_addrs: &builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool) -> %void {
111 switch (builtin.object_format) {
112 builtin.ObjectFormat.elf => {
113 var stack_trace = ElfStackTrace {
114 .self_exe_file = undefined,
115 .elf = undefined,
116 .debug_info = undefined,
117 .debug_abbrev = undefined,
118 .debug_str = undefined,
119 .debug_line = undefined,
120 .debug_ranges = null,
121 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
122 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
123 };
124 const st = &stack_trace;
125 st.self_exe_file = try os.openSelfExe();
126 defer st.self_exe_file.close();
127
128 try st.elf.openFile(allocator, &st.self_exe_file);
129 defer st.elf.close();
130
131 st.debug_info = (try st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
132 st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
133 st.debug_str = (try st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo;
134 st.debug_line = (try st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
135 st.debug_ranges = (try st.elf.findSection(".debug_ranges"));
136 try scanAllCompileUnits(st);
137
138 var ignored_count: usize = 0;
139
140 var frame_index: usize = undefined;
141 var frames_left: usize = undefined;
142 if (st_addrs.index < st_addrs.instruction_addresses.len) {
143 frame_index = 0;
144 frames_left = st_addrs.index;
145 } else {
146 frame_index = (st_addrs.index + 1) % st_addrs.instruction_addresses.len;
147 frames_left = st_addrs.instruction_addresses.len;
148 }
149
150 while (frames_left != 0) : ({frames_left -= 1; frame_index = (frame_index + 1) % st_addrs.instruction_addresses.len;}) {
151 const return_address = st_addrs.instruction_addresses[frame_index];
152
153 // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
154 // at compile time. I'll call it issue #313
155 const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
156
157 const compile_unit = findCompileUnit(st, return_address) catch {
158 try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
159 return_address);
160 continue;
161 };
162 const compile_unit_name = try compile_unit.die.getAttrString(st, DW.AT_name);
163 if (getLineNumberInfo(st, compile_unit, usize(return_address) - 1)) |line_info| {
164 defer line_info.deinit();
165 try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
166 DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
167 line_info.file_name, line_info.line, line_info.column,
168 return_address, compile_unit_name);
169 if (printLineFromFile(st.allocator(), out_stream, line_info)) {
170 if (line_info.column == 0) {
171 try out_stream.write("\n");
172 } else {
173 {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
174 try out_stream.writeByte(' ');
175 }}
176 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
177 }
178 } else |err| switch (err) {
179 error.EndOfFile, error.PathNotFound => {},
180 else => return err,
181 }
182 } else |err| switch (err) {
183 error.MissingDebugInfo, error.InvalidDebugInfo => {
184 try out_stream.print(ptr_hex ++ " in ??? ({})\n",
185 return_address, compile_unit_name);
186 },
187 else => return err,
188 }
189 }
190 },
191 builtin.ObjectFormat.coff => {
192 try out_stream.write("(stack trace unavailable for COFF object format)\n");
193 },
194 builtin.ObjectFormat.macho => {
195 try out_stream.write("(stack trace unavailable for Mach-O object format)\n");
196 },
197 builtin.ObjectFormat.wasm => {
198 try out_stream.write("(stack trace unavailable for WASM object format)\n");
199 },
200 builtin.ObjectFormat.unknown => {
201 try out_stream.write("(stack trace unavailable for unknown object format)\n");
202 },
203 }
204}
205
206pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,
105 ignore_frame_count: usize) -> %void207 ignore_frame_count: usize) -> %void
106{208{
107 switch (builtin.object_format) {209 switch (builtin.object_format) {
std/special/build_runner.zig+2-2
...@@ -112,7 +112,7 @@ pub fn main() -> %void {...@@ -112,7 +112,7 @@ pub fn main() -> %void {
112 }112 }
113113
114 builder.setInstallPrefix(prefix);114 builder.setInstallPrefix(prefix);
115 root.build(&builder);115 root.build(&builder) catch unreachable;
116116
117 if (builder.validateUserInputDidItFail())117 if (builder.validateUserInputDidItFail())
118 return usageAndErr(&builder, true, try stderr_stream);118 return usageAndErr(&builder, true, try stderr_stream);
...@@ -129,7 +129,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)...@@ -129,7 +129,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
129 // run the build script to collect the options129 // run the build script to collect the options
130 if (!already_ran_build) {130 if (!already_ran_build) {
131 builder.setInstallPrefix(null);131 builder.setInstallPrefix(null);
132 root.build(builder);132 root.build(builder) catch unreachable;
133 }133 }
134134
135 // This usage text has to be synchronized with src/main.cpp135 // This usage text has to be synchronized with src/main.cpp
std/special/builtin.zig+1-1
...@@ -5,7 +5,7 @@ const builtin = @import("builtin");...@@ -5,7 +5,7 @@ const builtin = @import("builtin");
55
6// Avoid dragging in the debug safety mechanisms into this .o file,6// Avoid dragging in the debug safety mechanisms into this .o file,
7// unless we're trying to test this file.7// unless we're trying to test this file.
8pub coldcc fn panic(msg: []const u8) -> noreturn {8pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
9 if (builtin.is_test) {9 if (builtin.is_test) {
10 @import("std").debug.panic("{}", msg);10 @import("std").debug.panic("{}", msg);
11 } else {11 } else {
std/special/compiler_rt/index.zig+1-1
...@@ -74,7 +74,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;...@@ -74,7 +74,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
7474
75// Avoid dragging in the debug safety mechanisms into this .o file,75// Avoid dragging in the debug safety mechanisms into this .o file,
76// unless we're trying to test this file.76// unless we're trying to test this file.
77pub coldcc fn panic(msg: []const u8) -> noreturn {77pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
78 if (is_test) {78 if (is_test) {
79 @import("std").debug.panic("{}", msg);79 @import("std").debug.panic("{}", msg);
80 } else {80 } else {
std/special/panic.zig+7-1
...@@ -4,14 +4,20 @@...@@ -4,14 +4,20 @@
4// have to be added in the compiler.4// have to be added in the compiler.
55
6const builtin = @import("builtin");6const builtin = @import("builtin");
7const std = @import("std");
78
8pub coldcc fn panic(msg: []const u8) -> noreturn {9pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
9 switch (builtin.os) {10 switch (builtin.os) {
10 // TODO: fix panic in zen.11 // TODO: fix panic in zen.
11 builtin.Os.freestanding, builtin.Os.zen => {12 builtin.Os.freestanding, builtin.Os.zen => {
12 while (true) {}13 while (true) {}
13 },14 },
14 else => {15 else => {
16 if (error_return_trace) |trace| {
17 std.debug.warn("{}\n", msg);
18 std.debug.dumpStackTrace(trace);
19 @import("std").debug.panic("");
20 }
15 @import("std").debug.panic("{}", msg);21 @import("std").debug.panic("{}", msg);
16 },22 },
17 }23 }