| author | |
| committer | |
| log | 9c908ea814b6b5ae67622c0a9cce4704c6734590 |
| tree | 2809339ba3d469c31898c0659371ac22dc79a2c2 |
| parent | 23d9b59b868e7f256668535adf9803facf75e538 |
4 files changed, 105 insertions(+), 0 deletions(-)
test/standalone.zig+4| ... | ... | @@ -230,6 +230,10 @@ pub const build_cases = [_]BuildCase{ |
| 230 | 230 | .build_root = "test/standalone/zerolength_check", |
| 231 | 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 | }; |
| 234 | 238 | |
| 235 | 239 | const std = @import("std"); |
test/standalone/dwarf_unwinding/build.zig created+37| ... | ... | @@ -0,0 +1,37 @@ |
| 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 (!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 @@ |
| 1 | const std = @import("std"); | |
| 2 | const debug = std.debug; | |
| 3 | const testing = std.testing; | |
| 4 | ||
| 5 | noinline 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 | ||
| 20 | noinline fn frame3(expected: *[4]usize, unwound: *[4]usize) void { | |
| 21 | expected[1] = @returnAddress(); | |
| 22 | frame4(expected, unwound); | |
| 23 | } | |
| 24 | ||
| 25 | fn frame2(expected: *[4]usize, unwound: *[4]usize) callconv(.C) void { | |
| 26 | frame3(expected, unwound); | |
| 27 | } | |
| 28 | ||
| 29 | extern 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 | ||
| 35 | pub 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 | ||
| 16 | LIB_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 |