| author | |
| committer | |
| log | 282cb5ee5d75b4de2f215479b0c5531750908608 |
| tree | a547a460bce58f0203980658875f6a91f6bf0f70 |
| parent | 8f2af35eaaf94493b4e459e14a1eda7ef00b7f64 |
| parent | 8b9627f01d44b94fad744f6d515dc32438130628 |
| signature |
Unwinding follow up: Don't strip compiler_rt symbols, enable unwind tables on supported platforms9 files changed, 81 insertions(+), 24 deletions(-)
lib/std/Build/Step/CheckObject.zig+1-2| ... | ... | @@ -478,8 +478,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 478 | 478 | }, |
| 479 | 479 | .not_present => { |
| 480 | 480 | while (it.next()) |line| { |
| 481 | if (act.notPresent(b, step, line)) break; | |
| 482 | } else { | |
| 481 | if (act.notPresent(b, step, line)) continue; | |
| 483 | 482 | return step.fail( |
| 484 | 483 | \\ |
| 485 | 484 | \\========= expected not to find: =================== |
lib/std/debug.zig+17-8| ... | ... | @@ -242,8 +242,7 @@ pub fn dumpStackTraceFromBase(context: *const ThreadContext) void { |
| 242 | 242 | printSourceAtAddress(debug_info, stderr, it.unwind_state.?.dwarf_context.pc, tty_config) catch return; |
| 243 | 243 | |
| 244 | 244 | while (it.next()) |return_address| { |
| 245 | if (it.getLastError()) |unwind_error| | |
| 246 | printUnwindError(debug_info, stderr, unwind_error.address, unwind_error.err, tty_config) catch {}; | |
| 245 | printLastUnwindError(&it, debug_info, stderr, tty_config); | |
| 247 | 246 | |
| 248 | 247 | // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS, |
| 249 | 248 | // therefore, we do a check for `return_address == 0` before subtracting 1 from it to avoid |
| ... | ... | @@ -252,7 +251,7 @@ pub fn dumpStackTraceFromBase(context: *const ThreadContext) void { |
| 252 | 251 | // same behaviour for x86-windows-msvc |
| 253 | 252 | const address = if (return_address == 0) return_address else return_address - 1; |
| 254 | 253 | printSourceAtAddress(debug_info, stderr, address, tty_config) catch return; |
| 255 | } | |
| 254 | } else printLastUnwindError(&it, debug_info, stderr, tty_config); | |
| 256 | 255 | } |
| 257 | 256 | } |
| 258 | 257 | |
| ... | ... | @@ -731,8 +730,7 @@ pub fn writeCurrentStackTrace( |
| 731 | 730 | defer it.deinit(); |
| 732 | 731 | |
| 733 | 732 | while (it.next()) |return_address| { |
| 734 | if (it.getLastError()) |unwind_error| | |
| 735 | try printUnwindError(debug_info, out_stream, unwind_error.address, unwind_error.err, tty_config); | |
| 733 | printLastUnwindError(&it, debug_info, out_stream, tty_config); | |
| 736 | 734 | |
| 737 | 735 | // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS, |
| 738 | 736 | // therefore, we do a check for `return_address == 0` before subtracting 1 from it to avoid |
| ... | ... | @@ -741,7 +739,7 @@ pub fn writeCurrentStackTrace( |
| 741 | 739 | // same behaviour for x86-windows-msvc |
| 742 | 740 | const address = if (return_address == 0) return_address else return_address - 1; |
| 743 | 741 | try printSourceAtAddress(debug_info, out_stream, address, tty_config); |
| 744 | } | |
| 742 | } else printLastUnwindError(&it, debug_info, out_stream, tty_config); | |
| 745 | 743 | } |
| 746 | 744 | |
| 747 | 745 | pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const windows.CONTEXT) usize { |
| ... | ... | @@ -879,10 +877,21 @@ fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usiz |
| 879 | 877 | ); |
| 880 | 878 | } |
| 881 | 879 | |
| 882 | pub fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void { | |
| 880 | fn printLastUnwindError(it: *StackIterator, debug_info: *DebugInfo, out_stream: anytype, tty_config: io.tty.Config) void { | |
| 881 | if (!have_ucontext) return; | |
| 882 | if (it.getLastError()) |unwind_error| { | |
| 883 | printUnwindError(debug_info, out_stream, unwind_error.address, unwind_error.err, tty_config) catch {}; | |
| 884 | } | |
| 885 | } | |
| 886 | ||
| 887 | fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void { | |
| 883 | 888 | const module_name = debug_info.getModuleNameForAddress(address) orelse "???"; |
| 884 | 889 | try tty_config.setColor(out_stream, .dim); |
| 885 | try out_stream.print("Unwind information for `{s}:0x{x}` was not available ({}), trace may be incomplete\n\n", .{ module_name, address, err }); | |
| 890 | if (err == error.MissingDebugInfo) { | |
| 891 | try out_stream.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address }); | |
| 892 | } else { | |
| 893 | try out_stream.print("Unwind error at address `{s}:0x{x}` ({}), trace may be incomplete\n\n", .{ module_name, address, err }); | |
| 894 | } | |
| 886 | 895 | try tty_config.setColor(out_stream, .reset); |
| 887 | 896 | } |
| 888 | 897 |
lib/std/dwarf.zig+1-1| ... | ... | @@ -1656,7 +1656,7 @@ pub const DwarfInfo = struct { |
| 1656 | 1656 | /// `explicit_fde_offset` is for cases where the FDE offset is known, such as when __unwind_info |
| 1657 | 1657 | /// defers unwinding to DWARF. This is an offset into the `.eh_frame` section. |
| 1658 | 1658 | pub fn unwindFrame(di: *const DwarfInfo, context: *UnwindContext, explicit_fde_offset: ?usize) !usize { |
| 1659 | if (!comptime abi.isSupportedArch(builtin.target.cpu.arch)) return error.UnsupportedCpuArchitecture; | |
| 1659 | if (!comptime abi.supportsUnwinding(builtin.target)) return error.UnsupportedCpuArchitecture; | |
| 1660 | 1660 | if (context.pc == 0) return 0; |
| 1661 | 1661 | |
| 1662 | 1662 | // Find the FDE and CIE |
lib/std/dwarf/abi.zig+18-7| ... | ... | @@ -3,13 +3,24 @@ const std = @import("../std.zig"); |
| 3 | 3 | const os = std.os; |
| 4 | 4 | const mem = std.mem; |
| 5 | 5 | |
| 6 | pub fn isSupportedArch(arch: std.Target.Cpu.Arch) bool { | |
| 7 | return switch (arch) { | |
| 8 | .x86, | |
| 9 | .x86_64, | |
| 10 | .arm, | |
| 11 | .aarch64, | |
| 12 | => true, | |
| 6 | pub fn supportsUnwinding(target: std.Target) bool { | |
| 7 | return switch (target.cpu.arch) { | |
| 8 | .x86 => switch (target.os.tag) { | |
| 9 | .linux, .netbsd, .solaris => true, | |
| 10 | else => false, | |
| 11 | }, | |
| 12 | .x86_64 => switch (target.os.tag) { | |
| 13 | .linux, .netbsd, .freebsd, .openbsd, .macos, .solaris => true, | |
| 14 | else => false, | |
| 15 | }, | |
| 16 | .arm => switch (target.os.tag) { | |
| 17 | .linux => true, | |
| 18 | else => false, | |
| 19 | }, | |
| 20 | .aarch64 => switch (target.os.tag) { | |
| 21 | .linux, .netbsd, .freebsd, .macos => true, | |
| 22 | else => false, | |
| 23 | }, | |
| 13 | 24 | else => false, |
| 14 | 25 | }; |
| 15 | 26 | } |
src/Compilation.zig+2-5| ... | ... | @@ -5491,6 +5491,7 @@ fn buildOutputFromZig( |
| 5491 | 5491 | .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, |
| 5492 | 5492 | .want_valgrind = false, |
| 5493 | 5493 | .want_tsan = false, |
| 5494 | .want_unwind_tables = comp.bin_file.options.eh_frame_hdr, | |
| 5494 | 5495 | .want_pic = comp.bin_file.options.pic, |
| 5495 | 5496 | .want_pie = comp.bin_file.options.pie, |
| 5496 | 5497 | .emit_h = null, |
| ... | ... | @@ -5639,9 +5640,5 @@ pub fn compilerRtOptMode(comp: Compilation) std.builtin.Mode { |
| 5639 | 5640 | /// This decides whether to strip debug info for all zig-provided libraries, including |
| 5640 | 5641 | /// compiler-rt, libcxx, libc, libunwind, etc. |
| 5641 | 5642 | pub fn compilerRtStrip(comp: Compilation) bool { |
| 5642 | if (comp.debug_compiler_runtime_libs) { | |
| 5643 | return comp.bin_file.options.strip; | |
| 5644 | } else { | |
| 5645 | return true; | |
| 5646 | } | |
| 5643 | return comp.bin_file.options.strip; | |
| 5647 | 5644 | } |
src/target.zig+1-1| ... | ... | @@ -510,7 +510,7 @@ pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool { |
| 510 | 510 | } |
| 511 | 511 | |
| 512 | 512 | pub fn needUnwindTables(target: std.Target) bool { |
| 513 | return target.os.tag == .windows or target.isDarwin(); | |
| 513 | return target.os.tag == .windows or target.isDarwin() or std.dwarf.abi.supportsUnwinding(target); | |
| 514 | 514 | } |
| 515 | 515 | |
| 516 | 516 | pub fn defaultAddressSpace( |
test/standalone.zig+4| ... | ... | @@ -241,6 +241,10 @@ pub const build_cases = [_]BuildCase{ |
| 241 | 241 | .build_root = "test/standalone/coff_dwarf", |
| 242 | 242 | .import = @import("standalone/coff_dwarf/build.zig"), |
| 243 | 243 | }, |
| 244 | .{ | |
| 245 | .build_root = "test/standalone/compiler_rt_panic", | |
| 246 | .import = @import("standalone/compiler_rt_panic/build.zig"), | |
| 247 | }, | |
| 244 | 248 | }; |
| 245 | 249 | |
| 246 | 250 | const std = @import("std"); |
test/standalone/compiler_rt_panic/build.zig created+26| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub fn build(b: *std.Build) void { | |
| 4 | const test_step = b.step("test", "Test it"); | |
| 5 | b.default_step = test_step; | |
| 6 | ||
| 7 | const target = b.standardTargetOptions(.{}); | |
| 8 | const optimize = b.standardOptimizeOption(.{}); | |
| 9 | ||
| 10 | if (target.getObjectFormat() != .elf) return; | |
| 11 | ||
| 12 | const exe = b.addExecutable(.{ | |
| 13 | .name = "main", | |
| 14 | .optimize = optimize, | |
| 15 | .target = target, | |
| 16 | }); | |
| 17 | exe.addCSourceFile("main.c", &.{}); | |
| 18 | exe.link_gc_sections = false; | |
| 19 | exe.bundle_compiler_rt = true; | |
| 20 | ||
| 21 | // Verify compiler_rt hasn't pulled in any debug handlers | |
| 22 | const check_exe = exe.checkObject(); | |
| 23 | check_exe.checkInSymtab(); | |
| 24 | check_exe.checkNotPresent("debug.readElfDebugInfo"); | |
| 25 | test_step.dependOn(&check_exe.step); | |
| 26 | } |
test/standalone/compiler_rt_panic/main.c created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | #include <stddef.h> | |
| 2 | ||
| 3 | void* __memset(void* dest, char c, size_t n, size_t dest_n); | |
| 4 | ||
| 5 | char foo[128]; | |
| 6 | ||
| 7 | int main() { | |
| 8 | __memset(&foo[0], 0xff, 128, 128); | |
| 9 | return foo[64]; | |
| 10 | } | |
| 11 |