aboutsummaryrefslogtreecommitdiff
path: root/lib/std/debug.zig
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/debug.zig')
-rw-r--r--lib/std/debug.zig128
1 files changed, 74 insertions, 54 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index a87dbe292d..efe4f1fa76 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -50,7 +50,7 @@ pub fn warn(comptime fmt: []const u8, args: var) void {
const held = stderr_mutex.acquire();
defer held.release();
const stderr = getStderrStream();
- stderr.print(fmt, args) catch return;
+ noasync stderr.print(fmt, args) catch return;
}
pub fn getStderrStream() *io.OutStream(File.WriteError) {
@@ -102,15 +102,15 @@ pub fn detectTTYConfig() TTY.Config {
pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
const stderr = getStderrStream();
if (builtin.strip_debug_info) {
- stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
+ noasync stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
return;
}
const debug_info = getSelfDebugInfo() catch |err| {
- stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
+ noasync stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
return;
};
writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(), start_addr) catch |err| {
- stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;
+ noasync stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;
return;
};
}
@@ -121,22 +121,16 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
const stderr = getStderrStream();
if (builtin.strip_debug_info) {
- stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
+ noasync stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
return;
}
const debug_info = getSelfDebugInfo() catch |err| {
- stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
+ noasync stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
return;
};
const tty_config = detectTTYConfig();
printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return;
- const first_return_address = @intToPtr(*const usize, bp + @sizeOf(usize)).*;
- if (first_return_address == 0) return; // The whole call stack may be optimized out
- printSourceAtAddress(debug_info, stderr, first_return_address - 1, tty_config) catch return;
- var it = StackIterator{
- .first_addr = null,
- .fp = bp,
- };
+ var it = StackIterator.init(null, bp);
while (it.next()) |return_address| {
printSourceAtAddress(debug_info, stderr, return_address - 1, tty_config) catch return;
}
@@ -179,7 +173,7 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace
}
stack_trace.index = slice.len;
} else {
- var it = StackIterator.init(first_address);
+ var it = StackIterator.init(first_address, null);
for (stack_trace.instruction_addresses) |*addr, i| {
addr.* = it.next() orelse {
stack_trace.index = i;
@@ -195,15 +189,15 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace
pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
const stderr = getStderrStream();
if (builtin.strip_debug_info) {
- stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
+ noasync stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
return;
}
const debug_info = getSelfDebugInfo() catch |err| {
- stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
+ noasync stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
return;
};
writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, detectTTYConfig()) catch |err| {
- stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;
+ noasync stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;
return;
};
}
@@ -244,7 +238,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
switch (@atomicRmw(u8, &panicking, .Add, 1, .SeqCst)) {
0 => {
const stderr = getStderrStream();
- stderr.print(format ++ "\n", args) catch os.abort();
+ noasync stderr.print(format ++ "\n", args) catch os.abort();
if (trace) |t| {
dumpStackTrace(t.*);
}
@@ -291,13 +285,15 @@ pub fn writeStackTrace(
}
pub const StackIterator = struct {
- first_addr: ?usize,
+ // Skip every frame before this address is found
+ first_address: ?usize,
+ // Last known value of the frame pointer register
fp: usize,
- pub fn init(first_addr: ?usize) StackIterator {
+ pub fn init(first_address: ?usize, fp: ?usize) StackIterator {
return StackIterator{
- .first_addr = first_addr,
- .fp = @frameAddress(),
+ .first_address = first_address,
+ .fp = fp orelse @frameAddress(),
};
}
@@ -305,29 +301,45 @@ pub const StackIterator = struct {
// the previous fp is stored, while on some other architectures such as
// RISC-V it points to the "top" of the frame, just above where the previous
// fp and the return address are stored.
- const fp_adjust_factor = if (builtin.arch == .riscv32 or builtin.arch == .riscv64)
+ const fp_offset = if (builtin.arch.isRISCV())
2 * @sizeOf(usize)
else
0;
fn next(self: *StackIterator) ?usize {
- if (self.fp <= fp_adjust_factor) return null;
- self.fp = @intToPtr(*const usize, self.fp - fp_adjust_factor).*;
- if (self.fp <= fp_adjust_factor) return null;
-
- if (self.first_addr) |addr| {
- while (self.fp > fp_adjust_factor) : (self.fp = @intToPtr(*const usize, self.fp - fp_adjust_factor).*) {
- const return_address = @intToPtr(*const usize, self.fp - fp_adjust_factor + @sizeOf(usize)).*;
- if (addr == return_address) {
- self.first_addr = null;
- return return_address;
- }
+ var address = self.next_internal() orelse return null;
+
+ if (self.first_address) |first_address| {
+ while (address != first_address) {
+ address = self.next_internal() orelse return null;
}
+ self.first_address = null;
}
- const return_address = @intToPtr(*const usize, self.fp - fp_adjust_factor + @sizeOf(usize)).*;
- if (return_address == 0) return null;
- return return_address;
+ return address;
+ }
+
+ fn next_internal(self: *StackIterator) ?usize {
+ const fp = math.sub(usize, self.fp, fp_offset) catch return null;
+
+ // Sanity check
+ if (fp == 0 or !mem.isAligned(fp, @alignOf(usize)))
+ return null;
+
+ const new_fp = @intToPtr(*const usize, fp).*;
+
+ // Sanity check: the stack grows down thus all the parent frames must be
+ // be at addresses that are greater (or equal) than the previous one.
+ // A zero frame pointer often signals this is the last frame, that case
+ // is gracefully handled by the next call to next_internal
+ if (new_fp != 0 and new_fp < self.fp)
+ return null;
+
+ const new_pc = @intToPtr(*const usize, fp + @sizeOf(usize)).*;
+
+ self.fp = new_fp;
+
+ return new_pc;
}
};
@@ -340,7 +352,7 @@ pub fn writeCurrentStackTrace(
if (builtin.os == .windows) {
return writeCurrentStackTraceWindows(out_stream, debug_info, tty_config, start_addr);
}
- var it = StackIterator.init(start_addr);
+ var it = StackIterator.init(start_addr, null);
while (it.next()) |return_address| {
try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_config);
}
@@ -378,6 +390,7 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: us
return noasync printSourceAtAddressPosix(debug_info, out_stream, address, tty_config);
}
+/// TODO resources https://github.com/ziglang/zig/issues/4353
fn printSourceAtAddressWindows(
di: *DebugInfo,
out_stream: var,
@@ -555,12 +568,12 @@ pub const TTY = struct {
switch (conf) {
.no_color => return,
.escape_codes => switch (color) {
- .Red => out_stream.write(RED) catch return,
- .Green => out_stream.write(GREEN) catch return,
- .Cyan => out_stream.write(CYAN) catch return,
- .White, .Bold => out_stream.write(WHITE) catch return,
- .Dim => out_stream.write(DIM) catch return,
- .Reset => out_stream.write(RESET) catch return,
+ .Red => noasync out_stream.write(RED) catch return,
+ .Green => noasync out_stream.write(GREEN) catch return,
+ .Cyan => noasync out_stream.write(CYAN) catch return,
+ .White, .Bold => noasync out_stream.write(WHITE) catch return,
+ .Dim => noasync out_stream.write(DIM) catch return,
+ .Reset => noasync out_stream.write(RESET) catch return,
},
.windows_api => if (builtin.os == .windows) {
const S = struct {
@@ -604,6 +617,7 @@ pub const TTY = struct {
};
};
+/// TODO resources https://github.com/ziglang/zig/issues/4353
fn populateModule(di: *DebugInfo, mod: *Module) !void {
if (mod.populated)
return;
@@ -715,17 +729,17 @@ fn printLineInfo(
tty_config.setColor(out_stream, .White);
if (line_info) |*li| {
- try out_stream.print("{}:{}:{}", .{ li.file_name, li.line, li.column });
+ try noasync out_stream.print("{}:{}:{}", .{ li.file_name, li.line, li.column });
} else {
- try out_stream.print("???:?:?", .{});
+ try noasync out_stream.write("???:?:?");
}
tty_config.setColor(out_stream, .Reset);
- try out_stream.write(": ");
+ try noasync out_stream.write(": ");
tty_config.setColor(out_stream, .Dim);
- try out_stream.print("0x{x} in {} ({})", .{ address, symbol_name, compile_unit_name });
+ try noasync out_stream.print("0x{x} in {} ({})", .{ address, symbol_name, compile_unit_name });
tty_config.setColor(out_stream, .Reset);
- try out_stream.write("\n");
+ try noasync out_stream.write("\n");
// Show the matching source code line if possible
if (line_info) |li| {
@@ -734,12 +748,12 @@ fn printLineInfo(
// The caret already takes one char
const space_needed = @intCast(usize, li.column - 1);
- try out_stream.writeByteNTimes(' ', space_needed);
+ try noasync out_stream.writeByteNTimes(' ', space_needed);
tty_config.setColor(out_stream, .Green);
- try out_stream.write("^");
+ try noasync out_stream.write("^");
tty_config.setColor(out_stream, .Reset);
}
- try out_stream.write("\n");
+ try noasync out_stream.write("\n");
} else |err| switch (err) {
error.EndOfFile, error.FileNotFound => {},
error.BadPathName => {},
@@ -755,6 +769,7 @@ pub const OpenSelfDebugInfoError = error{
UnsupportedOperatingSystem,
};
+/// TODO resources https://github.com/ziglang/zig/issues/4353
/// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented,
/// make this `noasync fn` and remove the individual noasync calls.
pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
@@ -963,6 +978,7 @@ pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
try di.scanAllCompileUnits();
}
+/// TODO resources https://github.com/ziglang/zig/issues/4353
pub fn openElfDebugInfo(
allocator: *mem.Allocator,
data: []u8,
@@ -997,12 +1013,11 @@ pub fn openElfDebugInfo(
null,
};
- efile.close();
-
try openDwarfDebugInfo(&di, allocator);
return di;
}
+/// TODO resources https://github.com/ziglang/zig/issues/4353
fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo {
var exe_file = try fs.openSelfExe();
errdefer exe_file.close();
@@ -1022,6 +1037,7 @@ fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo {
return openElfDebugInfo(allocator, exe_mmap);
}
+/// TODO resources https://github.com/ziglang/zig/issues/4353
fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
const hdr = &std.c._mh_execute_header;
assert(hdr.magic == std.macho.MH_MAGIC_64);
@@ -2074,6 +2090,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
return null;
}
+/// TODO resources https://github.com/ziglang/zig/issues/4353
fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, address: usize) !LineInfo {
const ofile = symbol.ofile orelse return error.MissingDebugInfo;
const gop = try di.ofiles.getOrPut(ofile);
@@ -2239,6 +2256,7 @@ pub fn attachSegfaultHandler() void {
os.sigaction(os.SIGSEGV, &act, null);
os.sigaction(os.SIGILL, &act, null);
+ os.sigaction(os.SIGBUS, &act, null);
}
fn resetSegfaultHandler() void {
@@ -2256,6 +2274,7 @@ fn resetSegfaultHandler() void {
};
os.sigaction(os.SIGSEGV, &act, null);
os.sigaction(os.SIGILL, &act, null);
+ os.sigaction(os.SIGBUS, &act, null);
}
fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) callconv(.C) noreturn {
@@ -2268,6 +2287,7 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_vo
switch (sig) {
os.SIGSEGV => std.debug.warn("Segmentation fault at address 0x{x}\n", .{addr}),
os.SIGILL => std.debug.warn("Illegal instruction at address 0x{x}\n", .{addr}),
+ os.SIGBUS => std.debug.warn("Bus error at address 0x{x}\n", .{addr}),
else => unreachable,
}
switch (builtin.arch) {