diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-02-10 00:26:33 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-02-10 00:26:33 -0500 |
| commit | cdc5070f216a924d24588b8d0fe06400e036e6bf (patch) | |
| tree | c1943e1831725e41810ea4db4eb1785a130e18e1 /lib/std/debug.zig | |
| parent | 9e5b2489913f72764ded2089bccd7e612a3cc347 (diff) | |
| parent | 014f66e6de4aaf81f32c796b12f981326a479397 (diff) | |
| download | zig-cdc5070f216a924d24588b8d0fe06400e036e6bf.tar.gz zig-cdc5070f216a924d24588b8d0fe06400e036e6bf.zip | |
Merge remote-tracking branch 'origin/master' into llvm10
Diffstat (limited to 'lib/std/debug.zig')
| -rw-r--r-- | lib/std/debug.zig | 128 |
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) { |
