authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-01 01:40:34-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:14-04:00
log9c908ea814b6b5ae67622c0a9cce4704c6734590
tree2809339ba3d469c31898c0659371ac22dc79a2c2
parent23d9b59b868e7f256668535adf9803facf75e538

test: add standalone test for DWARF unwinding with -fomit-frame-pointer


4 files changed, 105 insertions(+), 0 deletions(-)

test/standalone.zig+4
...@@ -230,6 +230,10 @@ pub const build_cases = [_]BuildCase{...@@ -230,6 +230,10 @@ pub const build_cases = [_]BuildCase{
230 .build_root = "test/standalone/zerolength_check",230 .build_root = "test/standalone/zerolength_check",
231 .import = @import("standalone/zerolength_check/build.zig"),231 .import = @import("standalone/zerolength_check/build.zig"),
232 },232 },
233 .{
234 .build_root = "test/standalone/dwarf_unwinding",
235 .import = @import("standalone/dwarf_unwinding/build.zig"),
236 },
233};237};
234238
235const std = @import("std");239const std = @import("std");
test/standalone/dwarf_unwinding/build.zig created+37
...@@ -0,0 +1,37 @@
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 (!std.debug.StackIterator.supports_context) return;
11
12 const c_shared_lib = b.addSharedLibrary(.{
13 .name = "c_shared_lib",
14 .target = target,
15 .optimize = optimize,
16 });
17
18 if (target.isWindows()) c_shared_lib.defineCMacro("LIB_API", "__declspec(dllexport)");
19
20 c_shared_lib.strip = false;
21 c_shared_lib.addCSourceFile("shared_lib.c", &.{"-fomit-frame-pointer"});
22 c_shared_lib.linkLibC();
23
24 const exe = b.addExecutable(.{
25 .name = "main",
26 .root_source_file = .{ .path = "main.zig" },
27 .target = target,
28 .optimize = optimize,
29 });
30
31 exe.omit_frame_pointer = true;
32 exe.linkLibrary(c_shared_lib);
33 b.installArtifact(exe);
34
35 const run_cmd = b.addRunArtifact(exe);
36 test_step.dependOn(&run_cmd.step);
37}
test/standalone/dwarf_unwinding/main.zig created+40
...@@ -0,0 +1,40 @@
1const std = @import("std");
2const debug = std.debug;
3const testing = std.testing;
4
5noinline fn frame4(expected: *[4]usize, unwound: *[4]usize) void {
6 expected[0] = @returnAddress();
7
8 var context: debug.StackTraceContext = undefined;
9 testing.expect(debug.getContext(&context)) catch @panic("failed to getContext");
10
11 var debug_info = debug.getSelfDebugInfo() catch @panic("failed to openSelfDebugInfo");
12 var it = debug.StackIterator.initWithContext(null, debug_info, &context) catch @panic("failed to initWithContext");
13 defer it.deinit();
14
15 for (unwound) |*addr| {
16 if (it.next()) |return_address| addr.* = return_address;
17 }
18}
19
20noinline fn frame3(expected: *[4]usize, unwound: *[4]usize) void {
21 expected[1] = @returnAddress();
22 frame4(expected, unwound);
23}
24
25fn frame2(expected: *[4]usize, unwound: *[4]usize) callconv(.C) void {
26 frame3(expected, unwound);
27}
28
29extern fn frame0(
30 expected: *[4]usize,
31 unwound: *[4]usize,
32 frame_2: *const fn (expected: *[4]usize, unwound: *[4]usize) callconv(.C) void,
33) void;
34
35pub fn main() !void {
36 var expected: [4]usize = undefined;
37 var unwound: [4]usize = undefined;
38 frame0(&expected, &unwound, &frame2);
39 try testing.expectEqual(expected, unwound);
40}
test/standalone/dwarf_unwinding/shared_lib.c created+24
...@@ -0,0 +1,24 @@
1#include <stdint.h>
2
3#ifndef LIB_API
4#define LIB_API
5#endif
6
7__attribute__((noinline)) void frame1(
8 void** expected,
9 void** unwound,
10 void (*frame2)(void** expected, void** unwound)) {
11 expected[2] = &&frame_2_ret;
12 frame2(expected, unwound);
13 frame_2_ret:
14}
15
16LIB_API void frame0(
17 void** expected,
18 void** unwound,
19 void (*frame2)(void** expected, void** unwound)) {
20 expected[3] = &&frame_1_ret;
21 frame1(expected, unwound, frame2);
22 frame_1_ret:
23}
24