zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 282cb5ee5d75b4de2f215479b0c5531750908608 (tree)
parent 8f2af35eaaf94493b4e459e14a1eda7ef00b7f64
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Thu, 27 Jul 2023 11:07:10 -0700

Merge pull request #16559 from kcbanner/improve_compiler_rt_stack_trace

Unwinding follow up: Don't strip compiler_rt symbols, enable unwind tables on supported platforms
Diffstat:
Mlib/std/Build/Step/CheckObject.zig | 3+--
Mlib/std/debug.zig | 25+++++++++++++++++--------
Mlib/std/dwarf.zig | 2+-
Mlib/std/dwarf/abi.zig | 25++++++++++++++++++-------
Msrc/Compilation.zig | 7++-----
Msrc/target.zig | 2+-
Mtest/standalone.zig | 4++++
Atest/standalone/compiler_rt_panic/build.zig | 26++++++++++++++++++++++++++
Atest/standalone/compiler_rt_panic/main.c | 11+++++++++++
9 files changed, 81 insertions(+), 24 deletions(-)

diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig @@ -478,8 +478,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { }, .not_present => { while (it.next()) |line| { - if (act.notPresent(b, step, line)) break; - } else { + if (act.notPresent(b, step, line)) continue; return step.fail( \\ \\========= expected not to find: =================== diff --git a/lib/std/debug.zig b/lib/std/debug.zig @@ -242,8 +242,7 @@ pub fn dumpStackTraceFromBase(context: *const ThreadContext) void { printSourceAtAddress(debug_info, stderr, it.unwind_state.?.dwarf_context.pc, tty_config) catch return; while (it.next()) |return_address| { - if (it.getLastError()) |unwind_error| - printUnwindError(debug_info, stderr, unwind_error.address, unwind_error.err, tty_config) catch {}; + printLastUnwindError(&it, debug_info, stderr, tty_config); // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS, // 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 { // same behaviour for x86-windows-msvc const address = if (return_address == 0) return_address else return_address - 1; printSourceAtAddress(debug_info, stderr, address, tty_config) catch return; - } + } else printLastUnwindError(&it, debug_info, stderr, tty_config); } } @@ -731,8 +730,7 @@ pub fn writeCurrentStackTrace( defer it.deinit(); while (it.next()) |return_address| { - if (it.getLastError()) |unwind_error| - try printUnwindError(debug_info, out_stream, unwind_error.address, unwind_error.err, tty_config); + printLastUnwindError(&it, debug_info, out_stream, tty_config); // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS, // therefore, we do a check for `return_address == 0` before subtracting 1 from it to avoid @@ -741,7 +739,7 @@ pub fn writeCurrentStackTrace( // same behaviour for x86-windows-msvc const address = if (return_address == 0) return_address else return_address - 1; try printSourceAtAddress(debug_info, out_stream, address, tty_config); - } + } else printLastUnwindError(&it, debug_info, out_stream, tty_config); } 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 ); } -pub fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void { +fn printLastUnwindError(it: *StackIterator, debug_info: *DebugInfo, out_stream: anytype, tty_config: io.tty.Config) void { + if (!have_ucontext) return; + if (it.getLastError()) |unwind_error| { + printUnwindError(debug_info, out_stream, unwind_error.address, unwind_error.err, tty_config) catch {}; + } +} + +fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void { const module_name = debug_info.getModuleNameForAddress(address) orelse "???"; try tty_config.setColor(out_stream, .dim); - try out_stream.print("Unwind information for `{s}:0x{x}` was not available ({}), trace may be incomplete\n\n", .{ module_name, address, err }); + if (err == error.MissingDebugInfo) { + try out_stream.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address }); + } else { + try out_stream.print("Unwind error at address `{s}:0x{x}` ({}), trace may be incomplete\n\n", .{ module_name, address, err }); + } try tty_config.setColor(out_stream, .reset); } diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig @@ -1656,7 +1656,7 @@ pub const DwarfInfo = struct { /// `explicit_fde_offset` is for cases where the FDE offset is known, such as when __unwind_info /// defers unwinding to DWARF. This is an offset into the `.eh_frame` section. pub fn unwindFrame(di: *const DwarfInfo, context: *UnwindContext, explicit_fde_offset: ?usize) !usize { - if (!comptime abi.isSupportedArch(builtin.target.cpu.arch)) return error.UnsupportedCpuArchitecture; + if (!comptime abi.supportsUnwinding(builtin.target)) return error.UnsupportedCpuArchitecture; if (context.pc == 0) return 0; // Find the FDE and CIE diff --git a/lib/std/dwarf/abi.zig b/lib/std/dwarf/abi.zig @@ -3,13 +3,24 @@ const std = @import("../std.zig"); const os = std.os; const mem = std.mem; -pub fn isSupportedArch(arch: std.Target.Cpu.Arch) bool { - return switch (arch) { - .x86, - .x86_64, - .arm, - .aarch64, - => true, +pub fn supportsUnwinding(target: std.Target) bool { + return switch (target.cpu.arch) { + .x86 => switch (target.os.tag) { + .linux, .netbsd, .solaris => true, + else => false, + }, + .x86_64 => switch (target.os.tag) { + .linux, .netbsd, .freebsd, .openbsd, .macos, .solaris => true, + else => false, + }, + .arm => switch (target.os.tag) { + .linux => true, + else => false, + }, + .aarch64 => switch (target.os.tag) { + .linux, .netbsd, .freebsd, .macos => true, + else => false, + }, else => false, }; } diff --git a/src/Compilation.zig b/src/Compilation.zig @@ -5491,6 +5491,7 @@ fn buildOutputFromZig( .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, .want_valgrind = false, .want_tsan = false, + .want_unwind_tables = comp.bin_file.options.eh_frame_hdr, .want_pic = comp.bin_file.options.pic, .want_pie = comp.bin_file.options.pie, .emit_h = null, @@ -5639,9 +5640,5 @@ pub fn compilerRtOptMode(comp: Compilation) std.builtin.Mode { /// This decides whether to strip debug info for all zig-provided libraries, including /// compiler-rt, libcxx, libc, libunwind, etc. pub fn compilerRtStrip(comp: Compilation) bool { - if (comp.debug_compiler_runtime_libs) { - return comp.bin_file.options.strip; - } else { - return true; - } + return comp.bin_file.options.strip; } diff --git a/src/target.zig b/src/target.zig @@ -510,7 +510,7 @@ pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool { } pub fn needUnwindTables(target: std.Target) bool { - return target.os.tag == .windows or target.isDarwin(); + return target.os.tag == .windows or target.isDarwin() or std.dwarf.abi.supportsUnwinding(target); } pub fn defaultAddressSpace( diff --git a/test/standalone.zig b/test/standalone.zig @@ -241,6 +241,10 @@ pub const build_cases = [_]BuildCase{ .build_root = "test/standalone/coff_dwarf", .import = @import("standalone/coff_dwarf/build.zig"), }, + .{ + .build_root = "test/standalone/compiler_rt_panic", + .import = @import("standalone/compiler_rt_panic/build.zig"), + }, }; const std = @import("std"); diff --git a/test/standalone/compiler_rt_panic/build.zig b/test/standalone/compiler_rt_panic/build.zig @@ -0,0 +1,26 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const test_step = b.step("test", "Test it"); + b.default_step = test_step; + + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + if (target.getObjectFormat() != .elf) return; + + const exe = b.addExecutable(.{ + .name = "main", + .optimize = optimize, + .target = target, + }); + exe.addCSourceFile("main.c", &.{}); + exe.link_gc_sections = false; + exe.bundle_compiler_rt = true; + + // Verify compiler_rt hasn't pulled in any debug handlers + const check_exe = exe.checkObject(); + check_exe.checkInSymtab(); + check_exe.checkNotPresent("debug.readElfDebugInfo"); + test_step.dependOn(&check_exe.step); +} diff --git a/test/standalone/compiler_rt_panic/main.c b/test/standalone/compiler_rt_panic/main.c @@ -0,0 +1,11 @@ +#include <stddef.h> + +void* __memset(void* dest, char c, size_t n, size_t dest_n); + +char foo[128]; + +int main() { + __memset(&foo[0], 0xff, 128, 128); + return foo[64]; +} +