mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
test: remove stack_iterator standalone test
Our new stack trace tests cover all the important parts of this.
This commit is contained in:
parent
5a71e15f1f
commit
d97954a8ea
6 changed files with 0 additions and 407 deletions
|
|
@ -163,9 +163,6 @@
|
||||||
.zerolength_check = .{
|
.zerolength_check = .{
|
||||||
.path = "zerolength_check",
|
.path = "zerolength_check",
|
||||||
},
|
},
|
||||||
.stack_iterator = .{
|
|
||||||
.path = "stack_iterator",
|
|
||||||
},
|
|
||||||
.coff_dwarf = .{
|
.coff_dwarf = .{
|
||||||
.path = "coff_dwarf",
|
.path = "coff_dwarf",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,167 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const builtin = @import("builtin");
|
|
||||||
|
|
||||||
pub fn build(b: *std.Build) void {
|
|
||||||
const test_step = b.step("test", "Test it");
|
|
||||||
b.default_step = test_step;
|
|
||||||
|
|
||||||
const target = b.standardTargetOptions(.{});
|
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
|
||||||
|
|
||||||
if (target.result.cpu.arch.isRISCV() and target.result.os.tag == .linux) {
|
|
||||||
// https://github.com/ziglang/zig/issues/24310
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwinding with a frame pointer
|
|
||||||
//
|
|
||||||
// getcontext version: zig std
|
|
||||||
//
|
|
||||||
// Unwind info type:
|
|
||||||
// - ELF: DWARF .debug_frame
|
|
||||||
// - MachO: __unwind_info encodings:
|
|
||||||
// - x86_64: RBP_FRAME
|
|
||||||
// - aarch64: FRAME, DWARF
|
|
||||||
{
|
|
||||||
const exe = b.addExecutable(.{
|
|
||||||
.name = "unwind_fp",
|
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.root_source_file = b.path("unwind.zig"),
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
.unwind_tables = if (target.result.os.tag.isDarwin()) .async else null,
|
|
||||||
.omit_frame_pointer = false,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
|
||||||
test_step.dependOn(&run_cmd.step);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwinding without a frame pointer
|
|
||||||
//
|
|
||||||
// getcontext version: zig std
|
|
||||||
//
|
|
||||||
// Unwind info type:
|
|
||||||
// - ELF: DWARF .eh_frame_hdr + .eh_frame
|
|
||||||
// - MachO: __unwind_info encodings:
|
|
||||||
// - x86_64: STACK_IMMD, STACK_IND
|
|
||||||
// - aarch64: FRAMELESS, DWARF
|
|
||||||
{
|
|
||||||
const exe = b.addExecutable(.{
|
|
||||||
.name = "unwind_nofp",
|
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.root_source_file = b.path("unwind.zig"),
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
.unwind_tables = .async,
|
|
||||||
.omit_frame_pointer = true,
|
|
||||||
}),
|
|
||||||
// self-hosted lacks omit_frame_pointer support
|
|
||||||
.use_llvm = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (builtin.os.tag != .freebsd) {
|
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
|
||||||
test_step.dependOn(&run_cmd.step);
|
|
||||||
} else {
|
|
||||||
test_step.dependOn(&exe.step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/ziglang/zig/issues/24522
|
|
||||||
//// Unwinding through a C shared library without a frame pointer (libc)
|
|
||||||
////
|
|
||||||
//// getcontext version: libc
|
|
||||||
////
|
|
||||||
//// Unwind info type:
|
|
||||||
//// - ELF: DWARF .eh_frame + .debug_frame
|
|
||||||
//// - MachO: __unwind_info encodings:
|
|
||||||
//// - x86_64: STACK_IMMD, STACK_IND
|
|
||||||
//// - aarch64: FRAMELESS, DWARF
|
|
||||||
//{
|
|
||||||
// const c_shared_lib = b.addLibrary(.{
|
|
||||||
// .linkage = .dynamic,
|
|
||||||
// .name = "c_shared_lib",
|
|
||||||
// .root_module = b.createModule(.{
|
|
||||||
// .root_source_file = null,
|
|
||||||
// .target = target,
|
|
||||||
// .optimize = optimize,
|
|
||||||
// .link_libc = true,
|
|
||||||
// .strip = false,
|
|
||||||
// }),
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if (target.result.os.tag == .windows)
|
|
||||||
// c_shared_lib.root_module.addCMacro("LIB_API", "__declspec(dllexport)");
|
|
||||||
|
|
||||||
// c_shared_lib.root_module.addCSourceFile(.{
|
|
||||||
// .file = b.path("shared_lib.c"),
|
|
||||||
// .flags = &.{"-fomit-frame-pointer"},
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const exe = b.addExecutable(.{
|
|
||||||
// .name = "shared_lib_unwind",
|
|
||||||
// .root_module = b.createModule(.{
|
|
||||||
// .root_source_file = b.path("shared_lib_unwind.zig"),
|
|
||||||
// .target = target,
|
|
||||||
// .optimize = optimize,
|
|
||||||
// .unwind_tables = if (target.result.os.tag.isDarwin()) .async else null,
|
|
||||||
// .omit_frame_pointer = true,
|
|
||||||
// }),
|
|
||||||
// // zig objcopy doesn't support incremental binaries
|
|
||||||
// .use_llvm = true,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// exe.root_module.linkLibrary(c_shared_lib);
|
|
||||||
|
|
||||||
// const run_cmd = b.addRunArtifact(exe);
|
|
||||||
// test_step.dependOn(&run_cmd.step);
|
|
||||||
|
|
||||||
// // Separate debug info ELF file
|
|
||||||
// if (target.result.ofmt == .elf) {
|
|
||||||
// const filename = b.fmt("{s}_stripped", .{exe.out_filename});
|
|
||||||
// const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{
|
|
||||||
// .basename = filename, // set the name for the debuglink
|
|
||||||
// .compress_debug = true,
|
|
||||||
// .strip = .debug,
|
|
||||||
// .extract_to_separate_file = true,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename}));
|
|
||||||
// run_stripped.addFileArg(stripped_exe.getOutput());
|
|
||||||
// test_step.dependOn(&run_stripped.step);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Unwinding without libc/posix
|
|
||||||
//
|
|
||||||
// No "getcontext" or "ucontext_t"
|
|
||||||
const no_os_targets = [_]std.Target.Os.Tag{ .freestanding, .other };
|
|
||||||
inline for (no_os_targets) |os_tag| {
|
|
||||||
const exe = b.addExecutable(.{
|
|
||||||
.name = "unwind_freestanding",
|
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.root_source_file = b.path("unwind_freestanding.zig"),
|
|
||||||
.target = b.resolveTargetQuery(.{
|
|
||||||
.cpu_arch = .x86_64,
|
|
||||||
.os_tag = os_tag,
|
|
||||||
}),
|
|
||||||
.optimize = optimize,
|
|
||||||
.unwind_tables = null,
|
|
||||||
.omit_frame_pointer = false,
|
|
||||||
}),
|
|
||||||
// self-hosted lacks omit_frame_pointer support
|
|
||||||
.use_llvm = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
// This "freestanding" binary is runnable because it invokes the
|
|
||||||
// Linux exit syscall directly.
|
|
||||||
if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) {
|
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
|
||||||
test_step.dependOn(&run_cmd.step);
|
|
||||||
} else {
|
|
||||||
test_step.dependOn(&exe.step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifndef LIB_API
|
|
||||||
#define LIB_API
|
|
||||||
#endif
|
|
||||||
|
|
||||||
__attribute__((noinline)) void frame1(
|
|
||||||
void** expected,
|
|
||||||
void** unwound,
|
|
||||||
void (*frame2)(void** expected, void** unwound)) {
|
|
||||||
expected[3] = __builtin_extract_return_addr(__builtin_return_address(0));
|
|
||||||
frame2(expected, unwound);
|
|
||||||
}
|
|
||||||
|
|
||||||
LIB_API void frame0(
|
|
||||||
void** expected,
|
|
||||||
void** unwound,
|
|
||||||
void (*frame2)(void** expected, void** unwound)) {
|
|
||||||
expected[4] = __builtin_extract_return_addr(__builtin_return_address(0));
|
|
||||||
frame1(expected, unwound, frame2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const builtin = @import("builtin");
|
|
||||||
const debug = std.debug;
|
|
||||||
const testing = std.testing;
|
|
||||||
|
|
||||||
noinline fn frame4(expected: *[5]usize, unwound: *[5]usize) void {
|
|
||||||
expected[0] = @returnAddress();
|
|
||||||
|
|
||||||
var context: debug.ThreadContext = undefined;
|
|
||||||
testing.expect(debug.getContext(&context)) catch @panic("failed to getContext");
|
|
||||||
|
|
||||||
const debug_info = debug.getSelfDebugInfo() catch @panic("failed to openSelfDebugInfo");
|
|
||||||
var it = debug.StackIterator.initWithContext(expected[0], debug_info, &context) catch @panic("failed to initWithContext");
|
|
||||||
defer it.deinit();
|
|
||||||
|
|
||||||
for (unwound) |*addr| {
|
|
||||||
if (it.next()) |return_address| addr.* = return_address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn frame3(expected: *[5]usize, unwound: *[5]usize) void {
|
|
||||||
expected[1] = @returnAddress();
|
|
||||||
frame4(expected, unwound);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn frame2(expected: *[5]usize, unwound: *[5]usize) callconv(.c) void {
|
|
||||||
expected[2] = @returnAddress();
|
|
||||||
frame3(expected, unwound);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern fn frame0(
|
|
||||||
expected: *[5]usize,
|
|
||||||
unwound: *[5]usize,
|
|
||||||
frame_2: *const fn (expected: *[5]usize, unwound: *[5]usize) callconv(.c) void,
|
|
||||||
) void;
|
|
||||||
|
|
||||||
pub fn main() !void {
|
|
||||||
// Disabled until the DWARF unwinder bugs on .aarch64 are solved
|
|
||||||
if (builtin.omit_frame_pointer and comptime builtin.target.os.tag.isDarwin() and builtin.cpu.arch == .aarch64) return;
|
|
||||||
if (builtin.target.os.tag.isDarwin() and builtin.cpu.arch == .x86_64) return; // https://github.com/ziglang/zig/issues/21337
|
|
||||||
|
|
||||||
if (!std.debug.have_ucontext or !std.debug.have_getcontext) return;
|
|
||||||
|
|
||||||
var expected: [5]usize = undefined;
|
|
||||||
var unwound: [5]usize = undefined;
|
|
||||||
frame0(&expected, &unwound, &frame2);
|
|
||||||
try testing.expectEqual(expected, unwound);
|
|
||||||
}
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
const std = @import("std");
|
|
||||||
const builtin = @import("builtin");
|
|
||||||
const fatal = std.process.fatal;
|
|
||||||
|
|
||||||
noinline fn frame3(expected: *[4]usize, addr_buf: *[4]usize) std.builtin.StackTrace {
|
|
||||||
expected[0] = @returnAddress();
|
|
||||||
return std.debug.captureCurrentStackTrace(.{
|
|
||||||
.first_address = @returnAddress(),
|
|
||||||
.allow_unsafe_unwind = true,
|
|
||||||
}, addr_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn frame2(expected: *[4]usize, addr_buf: *[4]usize) std.builtin.StackTrace {
|
|
||||||
// Exercise different __unwind_info / DWARF CFI encodings by forcing some registers to be restored
|
|
||||||
if (builtin.target.ofmt != .c) {
|
|
||||||
switch (builtin.target.cpu.arch) {
|
|
||||||
.x86 => {
|
|
||||||
if (builtin.omit_frame_pointer) {
|
|
||||||
asm volatile (
|
|
||||||
\\movl $3, %%ebx
|
|
||||||
\\movl $1, %%ecx
|
|
||||||
\\movl $2, %%edx
|
|
||||||
\\movl $7, %%edi
|
|
||||||
\\movl $6, %%esi
|
|
||||||
\\movl $5, %%ebp
|
|
||||||
::: .{ .ebx = true, .ecx = true, .edx = true, .edi = true, .esi = true, .ebp = true });
|
|
||||||
} else {
|
|
||||||
asm volatile (
|
|
||||||
\\movl $3, %%ebx
|
|
||||||
\\movl $1, %%ecx
|
|
||||||
\\movl $2, %%edx
|
|
||||||
\\movl $7, %%edi
|
|
||||||
\\movl $6, %%esi
|
|
||||||
::: .{ .ebx = true, .ecx = true, .edx = true, .edi = true, .esi = true });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.x86_64 => {
|
|
||||||
if (builtin.omit_frame_pointer) {
|
|
||||||
asm volatile (
|
|
||||||
\\movq $3, %%rbx
|
|
||||||
\\movq $12, %%r12
|
|
||||||
\\movq $13, %%r13
|
|
||||||
\\movq $14, %%r14
|
|
||||||
\\movq $15, %%r15
|
|
||||||
\\movq $6, %%rbp
|
|
||||||
::: .{ .rbx = true, .r12 = true, .r13 = true, .r14 = true, .r15 = true, .rbp = true });
|
|
||||||
} else {
|
|
||||||
asm volatile (
|
|
||||||
\\movq $3, %%rbx
|
|
||||||
\\movq $12, %%r12
|
|
||||||
\\movq $13, %%r13
|
|
||||||
\\movq $14, %%r14
|
|
||||||
\\movq $15, %%r15
|
|
||||||
::: .{ .rbx = true, .r12 = true, .r13 = true, .r14 = true, .r15 = true });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expected[1] = @returnAddress();
|
|
||||||
return frame3(expected, addr_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn frame1(expected: *[4]usize, addr_buf: *[4]usize) std.builtin.StackTrace {
|
|
||||||
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);
|
|
||||||
|
|
||||||
return frame2(expected, addr_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn frame0(expected: *[4]usize, addr_buf: *[4]usize) std.builtin.StackTrace {
|
|
||||||
expected[3] = @returnAddress();
|
|
||||||
return frame1(expected, addr_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main() void {
|
|
||||||
if (std.debug.cpu_context.Native == noreturn and builtin.omit_frame_pointer) {
|
|
||||||
// Stack unwinding is impossible.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var expected: [4]usize = undefined;
|
|
||||||
var addr_buf: [4]usize = undefined;
|
|
||||||
const trace = frame0(&expected, &addr_buf);
|
|
||||||
// There may be *more* than 4 frames (due to the caller of `main`); that's okay.
|
|
||||||
if (trace.index < 4) {
|
|
||||||
fatal("expected at least 4 frames, got '{d}':\n{f}", .{ trace.index, &trace });
|
|
||||||
}
|
|
||||||
if (!std.mem.eql(usize, trace.instruction_addresses, &expected)) {
|
|
||||||
const expected_trace: std.builtin.StackTrace = .{
|
|
||||||
.index = 4,
|
|
||||||
.instruction_addresses = &expected,
|
|
||||||
};
|
|
||||||
fatal("expected trace:\n{f}\nactual trace:\n{f}", .{ &expected_trace, &trace });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
//! Test StackIterator on 'freestanding' target. Based on unwind.zig.
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
noinline fn frame3(expected: *[4]usize, addr_buf: *[4]usize) std.builtin.StackTrace {
|
|
||||||
expected[0] = @returnAddress();
|
|
||||||
return std.debug.captureCurrentStackTrace(.{
|
|
||||||
.first_address = @returnAddress(),
|
|
||||||
.allow_unsafe_unwind = true,
|
|
||||||
}, addr_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn frame2(expected: *[4]usize, addr_buf: *[4]usize) std.builtin.StackTrace {
|
|
||||||
expected[1] = @returnAddress();
|
|
||||||
return frame3(expected, addr_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn frame1(expected: *[4]usize, addr_buf: *[4]usize) std.builtin.StackTrace {
|
|
||||||
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);
|
|
||||||
|
|
||||||
return frame2(expected, addr_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
noinline fn frame0(expected: *[4]usize, addr_buf: *[4]usize) std.builtin.StackTrace {
|
|
||||||
expected[3] = @returnAddress();
|
|
||||||
return frame1(expected, addr_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// No-OS entrypoint
|
|
||||||
export fn _start() callconv(.withStackAlign(.c, 1)) noreturn {
|
|
||||||
var expected: [4]usize = undefined;
|
|
||||||
var addr_buf: [4]usize = undefined;
|
|
||||||
const trace = frame0(&expected, &addr_buf);
|
|
||||||
|
|
||||||
// Since we can't print from this freestanding test, we'll just use the exit
|
|
||||||
// code to communicate error conditions.
|
|
||||||
|
|
||||||
// Unlike `unwind.zig`, we can expect *exactly* 4 frames, as we are the
|
|
||||||
// actual entry point and the frame pointer will be 0 on entry.
|
|
||||||
if (trace.index != 4) exit(1);
|
|
||||||
if (trace.instruction_addresses[0] != expected[0]) exit(2);
|
|
||||||
if (trace.instruction_addresses[1] != expected[1]) exit(3);
|
|
||||||
if (trace.instruction_addresses[2] != expected[2]) exit(4);
|
|
||||||
if (trace.instruction_addresses[3] != expected[3]) exit(5);
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn exit(code: u8) noreturn {
|
|
||||||
// We are intentionally compiling with the target OS being "freestanding" to
|
|
||||||
// exercise std.debug, but we still need to exit the process somehow; so do
|
|
||||||
// the appropriate x86_64-linux syscall.
|
|
||||||
asm volatile (
|
|
||||||
\\movl $60, %%eax
|
|
||||||
\\syscall
|
|
||||||
:
|
|
||||||
: [code] "{edi}" (code),
|
|
||||||
: .{ .edi = true, .eax = true });
|
|
||||||
|
|
||||||
unreachable;
|
|
||||||
}
|
|
||||||
Loading…
Add table
Reference in a new issue