fix duplicate stack trace code
This commit is contained in:
parent
4551489b92
commit
971a6fc531
@ -13,6 +13,10 @@ pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
|
||||
error MissingDebugInfo;
|
||||
error InvalidDebugInfo;
|
||||
error UnsupportedDebugInfo;
|
||||
error UnknownObjectFormat;
|
||||
error TodoSupportCoffDebugInfo;
|
||||
error TodoSupportMachoDebugInfo;
|
||||
error TodoSupportCOFFDebugInfo;
|
||||
|
||||
|
||||
/// Tries to write to stderr, unbuffered, and ignores any error returned.
|
||||
@ -40,13 +44,29 @@ 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;
|
||||
const debug_info = openSelfDebugInfo(global_allocator) catch |err| {
|
||||
stderr.print("Unable to open debug info: {}\n", @errorName(err)) catch return;
|
||||
return;
|
||||
};
|
||||
defer debug_info.close();
|
||||
writeCurrentStackTrace(stderr, global_allocator, debug_info, stderr_file.isTty(), 1) catch |err| {
|
||||
stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
|
||||
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;
|
||||
const debug_info = openSelfDebugInfo(global_allocator) catch |err| {
|
||||
stderr.print("Unable to open debug info: {}\n", @errorName(err)) catch return;
|
||||
return;
|
||||
};
|
||||
defer debug_info.close();
|
||||
writeStackTrace(stack_trace, stderr, global_allocator, debug_info, stderr_file.isTty()) catch |err| {
|
||||
stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
/// This function invokes undefined behavior when `ok` is `false`.
|
||||
@ -94,7 +114,7 @@ pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
|
||||
|
||||
const stderr = getStderrStream() catch os.abort();
|
||||
stderr.print(format ++ "\n", args) catch os.abort();
|
||||
writeCurrentStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch os.abort();
|
||||
dumpCurrentStackTrace();
|
||||
|
||||
os.abort();
|
||||
}
|
||||
@ -107,108 +127,88 @@ const RESET = "\x1b[0m";
|
||||
error PathNotFound;
|
||||
error InvalidDebugInfo;
|
||||
|
||||
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();
|
||||
pub fn writeStackTrace(stack_trace: &builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator,
|
||||
debug_info: &ElfStackTrace, tty_color: bool) -> %void
|
||||
{
|
||||
var frame_index: usize = undefined;
|
||||
var frames_left: usize = undefined;
|
||||
if (stack_trace.index < stack_trace.instruction_addresses.len) {
|
||||
frame_index = 0;
|
||||
frames_left = stack_trace.index;
|
||||
} else {
|
||||
frame_index = (stack_trace.index + 1) % stack_trace.instruction_addresses.len;
|
||||
frames_left = stack_trace.instruction_addresses.len;
|
||||
}
|
||||
|
||||
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");
|
||||
},
|
||||
while (frames_left != 0) : ({
|
||||
frames_left -= 1;
|
||||
frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;
|
||||
}) {
|
||||
const return_address = stack_trace.instruction_addresses[frame_index];
|
||||
try printSourceAtAddress(debug_info, out_stream, return_address);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,
|
||||
ignore_frame_count: usize) -> %void
|
||||
pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator,
|
||||
debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) -> %void
|
||||
{
|
||||
var ignored_count: usize = 0;
|
||||
|
||||
var fp = @ptrToInt(@frameAddress());
|
||||
while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
|
||||
if (ignored_count < ignore_frame_count) {
|
||||
ignored_count += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
|
||||
try printSourceAtAddress(debug_info, out_stream, return_address);
|
||||
}
|
||||
}
|
||||
|
||||
fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, address: usize) -> %void {
|
||||
// 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(debug_info, address) catch {
|
||||
try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
|
||||
address);
|
||||
return;
|
||||
};
|
||||
const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
|
||||
if (getLineNumberInfo(debug_info, compile_unit, usize(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,
|
||||
address, compile_unit_name);
|
||||
if (printLineFromFile(debug_info.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", address, compile_unit_name);
|
||||
},
|
||||
else => return err,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn openSelfDebugInfo(allocator: &mem.Allocator) -> %&ElfStackTrace {
|
||||
switch (builtin.object_format) {
|
||||
builtin.ObjectFormat.elf => {
|
||||
var stack_trace = ElfStackTrace {
|
||||
const st = try allocator.create(ElfStackTrace);
|
||||
*st = ElfStackTrace {
|
||||
.self_exe_file = undefined,
|
||||
.elf = undefined,
|
||||
.debug_info = undefined,
|
||||
@ -219,12 +219,11 @@ pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocat
|
||||
.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();
|
||||
%defer st.self_exe_file.close();
|
||||
|
||||
try st.elf.openFile(allocator, &st.self_exe_file);
|
||||
defer st.elf.close();
|
||||
%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;
|
||||
@ -232,67 +231,19 @@ pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocat
|
||||
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 fp = @ptrToInt(@frameAddress());
|
||||
while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
|
||||
if (ignored_count < ignore_frame_count) {
|
||||
ignored_count += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
|
||||
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
return st;
|
||||
},
|
||||
builtin.ObjectFormat.coff => {
|
||||
try out_stream.write("(stack trace unavailable for COFF object format)\n");
|
||||
return error.TodoSupportCoffDebugInfo;
|
||||
},
|
||||
builtin.ObjectFormat.macho => {
|
||||
try out_stream.write("(stack trace unavailable for Mach-O object format)\n");
|
||||
return error.TodoSupportMachoDebugInfo;
|
||||
},
|
||||
builtin.ObjectFormat.wasm => {
|
||||
try out_stream.write("(stack trace unavailable for WASM object format)\n");
|
||||
return error.TodoSupportCOFFDebugInfo;
|
||||
},
|
||||
builtin.ObjectFormat.unknown => {
|
||||
try out_stream.write("(stack trace unavailable for unknown object format)\n");
|
||||
return error.UnknownObjectFormat;
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -330,7 +281,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_
|
||||
}
|
||||
}
|
||||
|
||||
const ElfStackTrace = struct {
|
||||
pub const ElfStackTrace = struct {
|
||||
self_exe_file: io.File,
|
||||
elf: elf.Elf,
|
||||
debug_info: &elf.SectionHeader,
|
||||
@ -350,6 +301,11 @@ const ElfStackTrace = struct {
|
||||
const in_stream = &in_file_stream.stream;
|
||||
return readStringRaw(self.allocator(), in_stream);
|
||||
}
|
||||
|
||||
pub fn close(self: &ElfStackTrace) {
|
||||
self.self_exe_file.close();
|
||||
self.elf.close();
|
||||
}
|
||||
};
|
||||
|
||||
const PcRange = struct {
|
||||
|
@ -8,10 +8,14 @@ pub fn main() -> %void {
|
||||
for (test_fn_list) |test_fn, i| {
|
||||
warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);
|
||||
|
||||
test_fn.func() catch |err| {
|
||||
warn("{}\n", err);
|
||||
return err;
|
||||
};
|
||||
if (builtin.is_test) {
|
||||
test_fn.func() catch unreachable;
|
||||
} else {
|
||||
test_fn.func() catch |err| {
|
||||
warn("{}\n", err);
|
||||
return err;
|
||||
};
|
||||
}
|
||||
|
||||
warn("OK\n");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user