mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
c: fixup getcontext
debug: supports_context -> have_ucontext, supports_getcontext -> have_getcontext test: rework dwarf_unwind test case to also test the non-libc path
This commit is contained in:
parent
7bc1695f15
commit
ccc9f82068
@ -415,9 +415,9 @@ pub extern "c" fn timer_gettime(timerid: c.timer_t, flags: c_int, curr_value: *c
|
|||||||
|
|
||||||
pub usingnamespace if (builtin.os.tag == .linux and builtin.target.isMusl()) struct {
|
pub usingnamespace if (builtin.os.tag == .linux and builtin.target.isMusl()) struct {
|
||||||
// musl does not implement getcontext
|
// musl does not implement getcontext
|
||||||
const getcontext = std.os.linux.getcontext;
|
pub const getcontext = std.os.linux.getcontext;
|
||||||
} else struct {
|
} else struct {
|
||||||
extern "c" fn getcontext(ucp: *std.os.ucontext_t) c_int;
|
pub extern "c" fn getcontext(ucp: *std.os.ucontext_t) c_int;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const max_align_t = if (builtin.abi == .msvc)
|
pub const max_align_t = if (builtin.abi == .msvc)
|
||||||
|
|||||||
@ -136,7 +136,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
|
|||||||
pub const StackTraceContext = blk: {
|
pub const StackTraceContext = blk: {
|
||||||
if (native_os == .windows) {
|
if (native_os == .windows) {
|
||||||
break :blk std.os.windows.CONTEXT;
|
break :blk std.os.windows.CONTEXT;
|
||||||
} else if (StackIterator.supports_context) {
|
} else if (have_ucontext) {
|
||||||
break :blk os.ucontext_t;
|
break :blk os.ucontext_t;
|
||||||
} else {
|
} else {
|
||||||
break :blk void;
|
break :blk void;
|
||||||
@ -420,6 +420,18 @@ pub fn writeStackTrace(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const have_getcontext = @hasDecl(os.system, "getcontext") and
|
||||||
|
(builtin.os.tag != .linux or switch (builtin.cpu.arch) {
|
||||||
|
.x86, .x86_64 => true,
|
||||||
|
else => false,
|
||||||
|
});
|
||||||
|
|
||||||
|
pub const have_ucontext = @hasDecl(os.system, "ucontext_t") and
|
||||||
|
(builtin.os.tag != .linux or switch (builtin.cpu.arch) {
|
||||||
|
.mips, .mipsel, .mips64, .mips64el, .riscv64 => false,
|
||||||
|
else => true,
|
||||||
|
});
|
||||||
|
|
||||||
pub inline fn getContext(context: *StackTraceContext) bool {
|
pub inline fn getContext(context: *StackTraceContext) bool {
|
||||||
if (native_os == .windows) {
|
if (native_os == .windows) {
|
||||||
context.* = std.mem.zeroes(windows.CONTEXT);
|
context.* = std.mem.zeroes(windows.CONTEXT);
|
||||||
@ -427,13 +439,7 @@ pub inline fn getContext(context: *StackTraceContext) bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const supports_getcontext = @hasDecl(os.system, "getcontext") and
|
return have_getcontext and os.system.getcontext(context) == 0;
|
||||||
(builtin.os.tag != .linux or switch (builtin.cpu.arch) {
|
|
||||||
.x86, .x86_64 => true,
|
|
||||||
else => false,
|
|
||||||
});
|
|
||||||
|
|
||||||
return supports_getcontext and os.system.getcontext(context) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const StackIterator = struct {
|
pub const StackIterator = struct {
|
||||||
@ -445,13 +451,7 @@ pub const StackIterator = struct {
|
|||||||
// When DebugInfo and a register context is available, this iterator can unwind
|
// When DebugInfo and a register context is available, this iterator can unwind
|
||||||
// stacks with frames that don't use a frame pointer (ie. -fomit-frame-pointer).
|
// stacks with frames that don't use a frame pointer (ie. -fomit-frame-pointer).
|
||||||
debug_info: ?*DebugInfo,
|
debug_info: ?*DebugInfo,
|
||||||
dwarf_context: if (supports_context) DW.UnwindContext else void = undefined,
|
dwarf_context: if (have_ucontext) DW.UnwindContext else void = undefined,
|
||||||
|
|
||||||
pub const supports_context = @hasDecl(os.system, "ucontext_t") and
|
|
||||||
(builtin.os.tag != .linux or switch (builtin.cpu.arch) {
|
|
||||||
.mips, .mipsel, .mips64, .mips64el, .riscv64 => false,
|
|
||||||
else => true,
|
|
||||||
});
|
|
||||||
|
|
||||||
pub fn init(first_address: ?usize, fp: ?usize) StackIterator {
|
pub fn init(first_address: ?usize, fp: ?usize) StackIterator {
|
||||||
if (native_arch == .sparc64) {
|
if (native_arch == .sparc64) {
|
||||||
@ -476,7 +476,7 @@ pub const StackIterator = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *StackIterator) void {
|
pub fn deinit(self: *StackIterator) void {
|
||||||
if (supports_context) {
|
if (have_ucontext) {
|
||||||
if (self.debug_info) |debug_info| {
|
if (self.debug_info) |debug_info| {
|
||||||
self.dwarf_context.deinit(debug_info.allocator);
|
self.dwarf_context.deinit(debug_info.allocator);
|
||||||
}
|
}
|
||||||
@ -574,7 +574,7 @@ pub const StackIterator = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn next_internal(self: *StackIterator) ?usize {
|
fn next_internal(self: *StackIterator) ?usize {
|
||||||
if (supports_context and self.debug_info != null) {
|
if (have_ucontext and self.debug_info != null) {
|
||||||
if (self.dwarf_context.pc == 0) return null;
|
if (self.dwarf_context.pc == 0) return null;
|
||||||
if (self.next_dwarf()) |return_address| {
|
if (self.next_dwarf()) |return_address| {
|
||||||
return return_address;
|
return return_address;
|
||||||
|
|||||||
@ -7,31 +7,46 @@ pub fn build(b: *std.Build) void {
|
|||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
if (!std.debug.StackIterator.supports_context) return;
|
// Test unwinding pure zig code (no libc)
|
||||||
|
{
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "zig_unwind",
|
||||||
|
.root_source_file = .{ .path = "zig_unwind.zig" },
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
const c_shared_lib = b.addSharedLibrary(.{
|
exe.omit_frame_pointer = true;
|
||||||
.name = "c_shared_lib",
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (target.isWindows()) c_shared_lib.defineCMacro("LIB_API", "__declspec(dllexport)");
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
|
test_step.dependOn(&run_cmd.step);
|
||||||
|
}
|
||||||
|
|
||||||
c_shared_lib.strip = false;
|
// Test unwinding through a C shared library
|
||||||
c_shared_lib.addCSourceFile("shared_lib.c", &.{"-fomit-frame-pointer"});
|
{
|
||||||
c_shared_lib.linkLibC();
|
const c_shared_lib = b.addSharedLibrary(.{
|
||||||
|
.name = "c_shared_lib",
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
const exe = b.addExecutable(.{
|
if (target.isWindows()) c_shared_lib.defineCMacro("LIB_API", "__declspec(dllexport)");
|
||||||
.name = "main",
|
|
||||||
.root_source_file = .{ .path = "main.zig" },
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
|
|
||||||
exe.omit_frame_pointer = true;
|
c_shared_lib.strip = false;
|
||||||
exe.linkLibrary(c_shared_lib);
|
c_shared_lib.addCSourceFile("shared_lib.c", &.{"-fomit-frame-pointer"});
|
||||||
b.installArtifact(exe);
|
c_shared_lib.linkLibC();
|
||||||
|
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
const exe = b.addExecutable(.{
|
||||||
test_step.dependOn(&run_cmd.step);
|
.name = "shared_lib_unwind",
|
||||||
|
.root_source_file = .{ .path = "shared_lib_unwind.zig" },
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
exe.omit_frame_pointer = true;
|
||||||
|
exe.linkLibrary(c_shared_lib);
|
||||||
|
|
||||||
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
|
test_step.dependOn(&run_cmd.step);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ noinline fn frame4(expected: *[4]usize, unwound: *[4]usize) void {
|
|||||||
testing.expect(debug.getContext(&context)) catch @panic("failed to getContext");
|
testing.expect(debug.getContext(&context)) catch @panic("failed to getContext");
|
||||||
|
|
||||||
var debug_info = debug.getSelfDebugInfo() catch @panic("failed to openSelfDebugInfo");
|
var debug_info = debug.getSelfDebugInfo() catch @panic("failed to openSelfDebugInfo");
|
||||||
var it = debug.StackIterator.initWithContext(null, debug_info, &context) catch @panic("failed to initWithContext");
|
var it = debug.StackIterator.initWithContext(expected[0], debug_info, &context) catch @panic("failed to initWithContext");
|
||||||
defer it.deinit();
|
defer it.deinit();
|
||||||
|
|
||||||
for (unwound) |*addr| {
|
for (unwound) |*addr| {
|
||||||
@ -33,6 +33,8 @@ extern fn frame0(
|
|||||||
) void;
|
) void;
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
|
if (!std.debug.have_ucontext or !std.debug.have_getcontext) return;
|
||||||
|
|
||||||
var expected: [4]usize = undefined;
|
var expected: [4]usize = undefined;
|
||||||
var unwound: [4]usize = undefined;
|
var unwound: [4]usize = undefined;
|
||||||
frame0(&expected, &unwound, &frame2);
|
frame0(&expected, &unwound, &frame2);
|
||||||
42
test/standalone/dwarf_unwinding/zig_unwind.zig
Normal file
42
test/standalone/dwarf_unwinding/zig_unwind.zig
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const debug = std.debug;
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
noinline fn frame3(expected: *[4]usize, unwound: *[4]usize) void {
|
||||||
|
expected[0] = @returnAddress();
|
||||||
|
|
||||||
|
var context: debug.StackTraceContext = undefined;
|
||||||
|
testing.expect(debug.getContext(&context)) catch @panic("failed to getContext");
|
||||||
|
|
||||||
|
var 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 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();
|
||||||
|
frame2(expected, unwound);
|
||||||
|
}
|
||||||
|
|
||||||
|
noinline fn frame0(expected: *[4]usize, unwound: *[4]usize) void {
|
||||||
|
expected[3] = @returnAddress();
|
||||||
|
frame1(expected, unwound);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
if (!std.debug.have_ucontext or !std.debug.have_getcontext) return;
|
||||||
|
|
||||||
|
var expected: [4]usize = undefined;
|
||||||
|
var unwound: [4]usize = undefined;
|
||||||
|
frame0(&expected, &unwound);
|
||||||
|
try testing.expectEqual(expected, unwound);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user