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 {...@@ -478,8 +478,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
478 },478 },
479 .not_present => {479 .not_present => {
480 while (it.next()) |line| {480 while (it.next()) |line| {
481 if (act.notPresent(b, step, line)) break;481 if (act.notPresent(b, step, line)) continue;
482 } else {
483 return step.fail(482 return step.fail(
484 \\483 \\
485 \\========= expected not to find: ===================484 \\========= expected not to find: ===================
lib/std/debug.zig+17-8
...@@ -242,8 +242,7 @@ pub fn dumpStackTraceFromBase(context: *const ThreadContext) void {...@@ -242,8 +242,7 @@ pub fn dumpStackTraceFromBase(context: *const ThreadContext) void {
242 printSourceAtAddress(debug_info, stderr, it.unwind_state.?.dwarf_context.pc, tty_config) catch return;242 printSourceAtAddress(debug_info, stderr, it.unwind_state.?.dwarf_context.pc, tty_config) catch return;
243243
244 while (it.next()) |return_address| {244 while (it.next()) |return_address| {
245 if (it.getLastError()) |unwind_error|245 printLastUnwindError(&it, debug_info, stderr, tty_config);
246 printUnwindError(debug_info, stderr, unwind_error.address, unwind_error.err, tty_config) catch {};
247246
248 // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS,247 // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS,
249 // therefore, we do a check for `return_address == 0` before subtracting 1 from it to avoid248 // 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,7 +251,7 @@ pub fn dumpStackTraceFromBase(context: *const ThreadContext) void {
252 // same behaviour for x86-windows-msvc251 // same behaviour for x86-windows-msvc
253 const address = if (return_address == 0) return_address else return_address - 1;252 const address = if (return_address == 0) return_address else return_address - 1;
254 printSourceAtAddress(debug_info, stderr, address, tty_config) catch return;253 printSourceAtAddress(debug_info, stderr, address, tty_config) catch return;
255 }254 } else printLastUnwindError(&it, debug_info, stderr, tty_config);
256 }255 }
257}256}
258257
...@@ -731,8 +730,7 @@ pub fn writeCurrentStackTrace(...@@ -731,8 +730,7 @@ pub fn writeCurrentStackTrace(
731 defer it.deinit();730 defer it.deinit();
732731
733 while (it.next()) |return_address| {732 while (it.next()) |return_address| {
734 if (it.getLastError()) |unwind_error|733 printLastUnwindError(&it, debug_info, out_stream, tty_config);
735 try printUnwindError(debug_info, out_stream, unwind_error.address, unwind_error.err, tty_config);
736734
737 // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS,735 // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS,
738 // therefore, we do a check for `return_address == 0` before subtracting 1 from it to avoid736 // therefore, we do a check for `return_address == 0` before subtracting 1 from it to avoid
...@@ -741,7 +739,7 @@ pub fn writeCurrentStackTrace(...@@ -741,7 +739,7 @@ pub fn writeCurrentStackTrace(
741 // same behaviour for x86-windows-msvc739 // same behaviour for x86-windows-msvc
742 const address = if (return_address == 0) return_address else return_address - 1;740 const address = if (return_address == 0) return_address else return_address - 1;
743 try printSourceAtAddress(debug_info, out_stream, address, tty_config);741 try printSourceAtAddress(debug_info, out_stream, address, tty_config);
744 }742 } else printLastUnwindError(&it, debug_info, out_stream, tty_config);
745}743}
746744
747pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const windows.CONTEXT) usize {745pub 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,10 +877,21 @@ fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usiz
879 );877 );
880}878}
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 {
883 const module_name = debug_info.getModuleNameForAddress(address) orelse "???";888 const module_name = debug_info.getModuleNameForAddress(address) orelse "???";
884 try tty_config.setColor(out_stream, .dim);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 try tty_config.setColor(out_stream, .reset);895 try tty_config.setColor(out_stream, .reset);
887}896}
888897
lib/std/dwarf.zig+1-1
...@@ -1656,7 +1656,7 @@ pub const DwarfInfo = struct {...@@ -1656,7 +1656,7 @@ pub const DwarfInfo = struct {
1656 /// `explicit_fde_offset` is for cases where the FDE offset is known, such as when __unwind_info1656 /// `explicit_fde_offset` is for cases where the FDE offset is known, such as when __unwind_info
1657 /// defers unwinding to DWARF. This is an offset into the `.eh_frame` section.1657 /// defers unwinding to DWARF. This is an offset into the `.eh_frame` section.
1658 pub fn unwindFrame(di: *const DwarfInfo, context: *UnwindContext, explicit_fde_offset: ?usize) !usize {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 if (context.pc == 0) return 0;1660 if (context.pc == 0) return 0;
16611661
1662 // Find the FDE and CIE1662 // Find the FDE and CIE
lib/std/dwarf/abi.zig+18-7
...@@ -3,13 +3,24 @@ const std = @import("../std.zig");...@@ -3,13 +3,24 @@ const std = @import("../std.zig");
3const os = std.os;3const os = std.os;
4const mem = std.mem;4const mem = std.mem;
55
6pub fn isSupportedArch(arch: std.Target.Cpu.Arch) bool {6pub fn supportsUnwinding(target: std.Target) bool {
7 return switch (arch) {7 return switch (target.cpu.arch) {
8 .x86,8 .x86 => switch (target.os.tag) {
9 .x86_64,9 .linux, .netbsd, .solaris => true,
10 .arm,10 else => false,
11 .aarch64,11 },
12 => true,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 else => false,24 else => false,
14 };25 };
15}26}
src/Compilation.zig+2-5
...@@ -5491,6 +5491,7 @@ fn buildOutputFromZig(...@@ -5491,6 +5491,7 @@ fn buildOutputFromZig(
5491 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,5491 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
5492 .want_valgrind = false,5492 .want_valgrind = false,
5493 .want_tsan = false,5493 .want_tsan = false,
5494 .want_unwind_tables = comp.bin_file.options.eh_frame_hdr,
5494 .want_pic = comp.bin_file.options.pic,5495 .want_pic = comp.bin_file.options.pic,
5495 .want_pie = comp.bin_file.options.pie,5496 .want_pie = comp.bin_file.options.pie,
5496 .emit_h = null,5497 .emit_h = null,
...@@ -5639,9 +5640,5 @@ pub fn compilerRtOptMode(comp: Compilation) std.builtin.Mode {...@@ -5639,9 +5640,5 @@ pub fn compilerRtOptMode(comp: Compilation) std.builtin.Mode {
5639/// This decides whether to strip debug info for all zig-provided libraries, including5640/// This decides whether to strip debug info for all zig-provided libraries, including
5640/// compiler-rt, libcxx, libc, libunwind, etc.5641/// compiler-rt, libcxx, libc, libunwind, etc.
5641pub fn compilerRtStrip(comp: Compilation) bool {5642pub fn compilerRtStrip(comp: Compilation) bool {
5642 if (comp.debug_compiler_runtime_libs) {5643 return comp.bin_file.options.strip;
5643 return comp.bin_file.options.strip;
5644 } else {
5645 return true;
5646 }
5647}5644}
src/target.zig+1-1
...@@ -510,7 +510,7 @@ pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool {...@@ -510,7 +510,7 @@ pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool {
510}510}
511511
512pub fn needUnwindTables(target: std.Target) bool {512pub 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}
515515
516pub fn defaultAddressSpace(516pub fn defaultAddressSpace(
test/standalone.zig+4
...@@ -241,6 +241,10 @@ pub const build_cases = [_]BuildCase{...@@ -241,6 +241,10 @@ pub const build_cases = [_]BuildCase{
241 .build_root = "test/standalone/coff_dwarf",241 .build_root = "test/standalone/coff_dwarf",
242 .import = @import("standalone/coff_dwarf/build.zig"),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};
245249
246const std = @import("std");250const 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