aboutsummaryrefslogtreecommitdiff
path: root/test/standalone/stack_iterator/unwind_freestanding.zig
blob: ec4bb5d00eff1cf2df61ed4d6b37032be69e6ad7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/// Test StackIterator on 'freestanding' target.  Based on unwind.zig.
const std = @import("std");
const builtin = @import("builtin");
const debug = std.debug;

noinline fn frame3(expected: *[4]usize, unwound: *[4]usize) void {
    expected[0] = @returnAddress();

    var it = debug.StackIterator.init(@returnAddress(), @frameAddress());
    defer it.deinit();

    // Save StackIterator's frame addresses into `unwound`:
    for (unwound) |*addr| {
        if (it.next()) |return_address| addr.* = return_address;
    }
}

noinline fn frame2(expected: *[4]usize, unwound: *[4]usize) void {
    expected[1] = @returnAddress();
    frame3(expected, unwound);
}

noinline fn frame1(expected: *[4]usize, unwound: *[4]usize) void {
    expected[2] = @returnAddress();

    // Use a stack frame that is too big to encode in __unwind_info's stack-immediate encoding
    // to exercise the stack-indirect encoding path
    var pad: [std.math.maxInt(u8) * @sizeOf(usize) + 1]u8 = undefined;
    _ = std.mem.doNotOptimizeAway(&pad);

    frame2(expected, unwound);
}

noinline fn frame0(expected: *[4]usize, unwound: *[4]usize) void {
    expected[3] = @returnAddress();
    frame1(expected, unwound);
}

// No-OS entrypoint
export fn _start() callconv(.c) noreturn {
    var expected: [4]usize = undefined;
    var unwound: [4]usize = undefined;
    frame0(&expected, &unwound);

    // Verify result (no std.testing in freestanding)
    var missed: c_int = 0;
    for (expected, unwound) |expectFA, actualFA| {
        if (expectFA != actualFA) {
            missed += 1;
        }
    }

    // Need to compile with the target OS as "freestanding" or "other" to
    // exercise the StackIterator code, but when run as a regression test
    // need to actually exit.  So assume we're running on x86_64-linux ...
    asm volatile (
        \\movl $60, %%eax
        \\syscall
        :
        : [missed] "{edi}" (missed),
        : .{ .edi = true, .eax = true });

    while (true) {} // unreached
}