aboutsummaryrefslogtreecommitdiff
path: root/std/debug/index.zig
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2018-01-12 02:12:11 -0500
committerAndrew Kelley <superjoe30@gmail.com>2018-01-12 02:12:11 -0500
commit32ea6f54e5f05c4173828c4f4c8ab9965a929120 (patch)
treef4c48c5be138070207c19629c08d763c8a6a1325 /std/debug/index.zig
parent7ec783876a565662223268a70ba984e0a132b94a (diff)
downloadzig-32ea6f54e5f05c4173828c4f4c8ab9965a929120.tar.gz
zig-32ea6f54e5f05c4173828c4f4c8ab9965a929120.zip
*WIP* proof of concept error return traces
Diffstat (limited to 'std/debug/index.zig')
-rw-r--r--std/debug/index.zig110
1 files changed, 106 insertions, 4 deletions
diff --git a/std/debug/index.zig b/std/debug/index.zig
index 464974b7de..fa23040794 100644
--- a/std/debug/index.zig
+++ b/std/debug/index.zig
@@ -37,10 +37,16 @@ fn getStderrStream() -> %&io.OutStream {
}
}
+/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
+pub fn dumpCurrentStackTrace() {
+ const stderr = getStderrStream() 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() {
+pub fn dumpStackTrace(stack_trace: &builtin.StackTrace) {
const stderr = getStderrStream() catch return;
- writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) 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) {