Skip to content

Commit 282cb5e

Browse files
authored
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
2 parents 8f2af35 + 8b9627f commit 282cb5e

File tree

9 files changed

+81
-24
lines changed

9 files changed

+81
-24
lines changed

lib/std/Build/Step/CheckObject.zig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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

747745
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
879877
);
880878
}
881879

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 {
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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,24 @@ const std = @import("../std.zig");
33
const os = std.os;
44
const mem = std.mem;
55

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+
},
1324
else => false,
1425
};
1526
}

src/Compilation.zig

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
56415642
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;
56475644
}

src/target.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool {
510510
}
511511

512512
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);
514514
}
515515

516516
pub fn defaultAddressSpace(

test/standalone.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

246250
const std = @import("std");
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+

0 commit comments

Comments
 (0)