authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-27 11:07:10-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-27 11:07:10-07:00
log282cb5ee5d75b4de2f215479b0c5531750908608
treea547a460bce58f0203980658875f6a91f6bf0f70
parent8f2af35eaaf94493b4e459e14a1eda7ef00b7f64
parent8b9627f01d44b94fad744f6d515dc32438130628
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

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

9 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 {
478478 },
479479 .not_present => {
480480 while (it.next()) |line| {
481 if (act.notPresent(b, step, line)) break;
482 } else {
481 if (act.notPresent(b, step, line)) continue;
483482 return step.fail(
484483 \\
485484 \\========= expected not to find: ===================
lib/std/debug.zig+17-8
......@@ -242,8 +242,7 @@ pub fn dumpStackTraceFromBase(context: *const ThreadContext) void {
242242 printSourceAtAddress(debug_info, stderr, it.unwind_state.?.dwarf_context.pc, tty_config) catch return;
243243
244244 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);
247246
248247 // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS,
249248 // 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 {
252251 // same behaviour for x86-windows-msvc
253252 const address = if (return_address == 0) return_address else return_address - 1;
254253 printSourceAtAddress(debug_info, stderr, address, tty_config) catch return;
255 }
254 } else printLastUnwindError(&it, debug_info, stderr, tty_config);
256255 }
257256}
258257
......@@ -731,8 +730,7 @@ pub fn writeCurrentStackTrace(
731730 defer it.deinit();
732731
733732 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);
736734
737735 // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS,
738736 // therefore, we do a check for `return_address == 0` before subtracting 1 from it to avoid
......@@ -741,7 +739,7 @@ pub fn writeCurrentStackTrace(
741739 // same behaviour for x86-windows-msvc
742740 const address = if (return_address == 0) return_address else return_address - 1;
743741 try printSourceAtAddress(debug_info, out_stream, address, tty_config);
744 }
742 } else printLastUnwindError(&it, debug_info, out_stream, tty_config);
745743}
746744
747745pub 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
879877 );
880878}
881879
882pub fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void {
880fn 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
887fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void {
883888 const module_name = debug_info.getModuleNameForAddress(address) orelse "???";
884889 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 }
886895 try tty_config.setColor(out_stream, .reset);
887896}
888897
lib/std/dwarf.zig+1-1
......@@ -1656,7 +1656,7 @@ pub const DwarfInfo = struct {
16561656 /// `explicit_fde_offset` is for cases where the FDE offset is known, such as when __unwind_info
16571657 /// defers unwinding to DWARF. This is an offset into the `.eh_frame` section.
16581658 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;
16601660 if (context.pc == 0) return 0;
16611661
16621662 // Find the FDE and CIE
lib/std/dwarf/abi.zig+18-7
......@@ -3,13 +3,24 @@ const std = @import("../std.zig");
33const os = std.os;
44const mem = std.mem;
55
6pub fn isSupportedArch(arch: std.Target.Cpu.Arch) bool {
7 return switch (arch) {
8 .x86,
9 .x86_64,
10 .arm,
11 .aarch64,
12 => true,
6pub 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 },
1324 else => false,
1425 };
1526}
src/Compilation.zig+2-5
......@@ -5491,6 +5491,7 @@ fn buildOutputFromZig(
54915491 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
54925492 .want_valgrind = false,
54935493 .want_tsan = false,
5494 .want_unwind_tables = comp.bin_file.options.eh_frame_hdr,
54945495 .want_pic = comp.bin_file.options.pic,
54955496 .want_pie = comp.bin_file.options.pie,
54965497 .emit_h = null,
......@@ -5639,9 +5640,5 @@ pub fn compilerRtOptMode(comp: Compilation) std.builtin.Mode {
56395640/// This decides whether to strip debug info for all zig-provided libraries, including
56405641/// compiler-rt, libcxx, libc, libunwind, etc.
56415642pub 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;
56475644}
src/target.zig+1-1
......@@ -510,7 +510,7 @@ pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool {
510510}
511511
512512pub 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);
514514}
515515
516516pub fn defaultAddressSpace(
test/standalone.zig+4
......@@ -241,6 +241,10 @@ pub const build_cases = [_]BuildCase{
241241 .build_root = "test/standalone/coff_dwarf",
242242 .import = @import("standalone/coff_dwarf/build.zig"),
243243 },
244 .{
245 .build_root = "test/standalone/compiler_rt_panic",
246 .import = @import("standalone/compiler_rt_panic/build.zig"),
247 },
244248};
245249
246250const std = @import("std");
test/standalone/compiler_rt_panic/build.zig created+26
......@@ -0,0 +1,26 @@
1const std = @import("std");
2
3pub 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
3void* __memset(void* dest, char c, size_t n, size_t dest_n);
4
5char foo[128];
6
7int main() {
8 __memset(&foo[0], 0xff, 128, 128);
9 return foo[64];
10}
11