mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
debug: add relocateContext
dwarf: fixup tests that used a ThreadContext
This commit is contained in:
parent
94354aa6aa
commit
203d96ae97
@ -133,6 +133,12 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
|
||||||
/// Platform-specific thread state. This contains register state, and on some platforms
|
/// Platform-specific thread state. This contains register state, and on some platforms
|
||||||
/// information about the stack. This is not safe to trivially copy, because some platforms
|
/// information about the stack. This is not safe to trivially copy, because some platforms
|
||||||
/// use internal pointers within this structure. To make a copy, use `copyContext`.
|
/// use internal pointers within this structure. To make a copy, use `copyContext`.
|
||||||
@ -146,6 +152,47 @@ pub const ThreadContext = blk: {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Copies one context to another, updating any internal pointers
|
||||||
|
pub fn copyContext(source: *const ThreadContext, dest: *ThreadContext) void {
|
||||||
|
if (!have_ucontext) return {};
|
||||||
|
dest.* = source.*;
|
||||||
|
relocateContext(dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates any internal points in the context to reflect its current location
|
||||||
|
pub fn relocateContext(context: *ThreadContext) void {
|
||||||
|
return switch (native_os) {
|
||||||
|
.macos => {
|
||||||
|
context.mcontext = &context.__mcontext_data;
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const have_getcontext = @hasDecl(os.system, "getcontext") and
|
||||||
|
(builtin.os.tag != .linux or switch (builtin.cpu.arch) {
|
||||||
|
.x86, .x86_64 => true,
|
||||||
|
else => false,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Capture the current context. The register values in the context will reflect the
|
||||||
|
/// state after the platform `getcontext` function returned.
|
||||||
|
///
|
||||||
|
/// It is valid to call this if the platform doesn't have context capturing support,
|
||||||
|
/// in that case false will be returned.
|
||||||
|
pub inline fn getContext(context: *ThreadContext) bool {
|
||||||
|
if (native_os == .windows) {
|
||||||
|
context.* = std.mem.zeroes(windows.CONTEXT);
|
||||||
|
windows.ntdll.RtlCaptureContext(context);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = have_getcontext and os.system.getcontext(context) == 0;
|
||||||
|
if (native_os == .macos) assert(context.mcsize == @sizeOf(std.c.mcontext_t));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/// Tries to print the stack trace starting from the supplied base pointer to stderr,
|
/// Tries to print the stack trace starting from the supplied base pointer to stderr,
|
||||||
/// unbuffered, and ignores any error returned.
|
/// unbuffered, and ignores any error returned.
|
||||||
/// TODO multithreaded awareness
|
/// TODO multithreaded awareness
|
||||||
@ -428,51 +475,6 @@ 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: *ThreadContext) bool {
|
|
||||||
if (native_os == .windows) {
|
|
||||||
context.* = std.mem.zeroes(windows.CONTEXT);
|
|
||||||
windows.ntdll.RtlCaptureContext(context);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = have_getcontext and os.system.getcontext(context) == 0;
|
|
||||||
if (native_os == .macos) {
|
|
||||||
// TODO: Temp, to discover this size via aarch64 CI
|
|
||||||
if (context.mcsize != @sizeOf(std.c.mcontext_t)) {
|
|
||||||
print("context.mcsize does not match! {} vs {}\n", .{ context.mcsize, @sizeOf(std.c.mcontext_t) });
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(context.mcsize == @sizeOf(std.c.mcontext_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn copyContext(source: *const ThreadContext, dest: *ThreadContext) void {
|
|
||||||
if (native_os == .windows) dest.* = source.*;
|
|
||||||
if (!have_ucontext) return {};
|
|
||||||
|
|
||||||
return switch (native_os) {
|
|
||||||
.macos => {
|
|
||||||
dest.* = source.*;
|
|
||||||
dest.mcontext = &dest.__mcontext_data;
|
|
||||||
},
|
|
||||||
else => dest.* = source.*,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const UnwindError = if (have_ucontext)
|
pub const UnwindError = if (have_ucontext)
|
||||||
@typeInfo(@typeInfo(@TypeOf(StackIterator.next_unwind)).Fn.return_type.?).ErrorUnion.error_set
|
@typeInfo(@typeInfo(@TypeOf(StackIterator.next_unwind)).Fn.return_type.?).ErrorUnion.error_set
|
||||||
else
|
else
|
||||||
@ -855,7 +857,7 @@ fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usiz
|
|||||||
pub fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void {
|
pub fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void {
|
||||||
const module_name = debug_info.getModuleNameForAddress(address) orelse "???";
|
const module_name = debug_info.getModuleNameForAddress(address) orelse "???";
|
||||||
try tty_config.setColor(out_stream, .dim);
|
try tty_config.setColor(out_stream, .dim);
|
||||||
try out_stream.print("Unwind information for {s} was not available ({}), trace may be incomplete\n\n", .{ module_name, err });
|
try out_stream.print("Unwind information for `{s}` was not available ({}), trace may be incomplete\n\n", .{ module_name, err });
|
||||||
try tty_config.setColor(out_stream, .reset);
|
try tty_config.setColor(out_stream, .reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1641,7 +1643,7 @@ pub const DebugInfo = struct {
|
|||||||
const seg_start = segment_cmd.vmaddr;
|
const seg_start = segment_cmd.vmaddr;
|
||||||
const seg_end = seg_start + segment_cmd.vmsize;
|
const seg_end = seg_start + segment_cmd.vmsize;
|
||||||
if (original_address >= seg_start and original_address < seg_end) {
|
if (original_address >= seg_start and original_address < seg_end) {
|
||||||
return mem.sliceTo(std.c._dyld_get_image_name(i), 0);
|
return fs.path.basename(mem.sliceTo(std.c._dyld_get_image_name(i), 0));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
|
|||||||
@ -48,6 +48,7 @@ pub const ExpressionOptions = struct {
|
|||||||
call_frame_context: bool = false,
|
call_frame_context: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Explcitly defined to support executing sub-expressions
|
||||||
pub const ExpressionError = error{
|
pub const ExpressionError = error{
|
||||||
UnimplementedExpressionCall,
|
UnimplementedExpressionCall,
|
||||||
UnimplementedOpcode,
|
UnimplementedOpcode,
|
||||||
@ -1178,20 +1179,21 @@ test "DWARF expressions" {
|
|||||||
.is_macho = builtin.os.tag == .macos,
|
.is_macho = builtin.os.tag == .macos,
|
||||||
};
|
};
|
||||||
var thread_context: std.debug.ThreadContext = undefined;
|
var thread_context: std.debug.ThreadContext = undefined;
|
||||||
|
std.debug.relocateContext(&thread_context);
|
||||||
const context = ExpressionContext{
|
const context = ExpressionContext{
|
||||||
.thread_context = &thread_context,
|
.thread_context = &thread_context,
|
||||||
.reg_context = reg_context,
|
.reg_context = reg_context,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only test register operations on arch / os that have them implemented
|
// Only test register operations on arch / os that have them implemented
|
||||||
if (abi.regBytes(&thread_context, 0, reg_context)) |_| {
|
if (abi.regBytes(&thread_context, 0, reg_context)) |reg_bytes| {
|
||||||
|
|
||||||
// TODO: Test fbreg (once implemented): mock a DIE and point compile_unit.frame_base at it
|
// TODO: Test fbreg (once implemented): mock a DIE and point compile_unit.frame_base at it
|
||||||
|
|
||||||
mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, 0, reg_context), 0xee);
|
mem.writeIntSliceNative(usize, reg_bytes, 0xee);
|
||||||
mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, abi.fpRegNum(reg_context), reg_context), 1);
|
(try abi.regValueNative(usize, &thread_context, abi.fpRegNum(reg_context), reg_context)).* = 1;
|
||||||
mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, abi.spRegNum(reg_context), reg_context), 2);
|
(try abi.regValueNative(usize, &thread_context, abi.spRegNum(reg_context), reg_context)).* = 2;
|
||||||
mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, abi.ipRegNum(), reg_context), 3);
|
(try abi.regValueNative(usize, &thread_context, abi.ipRegNum(), reg_context)).* = 3;
|
||||||
|
|
||||||
try b.writeBreg(writer, abi.fpRegNum(reg_context), @as(usize, 100));
|
try b.writeBreg(writer, abi.fpRegNum(reg_context), @as(usize, 100));
|
||||||
try b.writeBreg(writer, abi.spRegNum(reg_context), @as(usize, 200));
|
try b.writeBreg(writer, abi.spRegNum(reg_context), @as(usize, 200));
|
||||||
@ -1609,6 +1611,7 @@ test "DWARF expressions" {
|
|||||||
.is_macho = builtin.os.tag == .macos,
|
.is_macho = builtin.os.tag == .macos,
|
||||||
};
|
};
|
||||||
var thread_context: std.debug.ThreadContext = undefined;
|
var thread_context: std.debug.ThreadContext = undefined;
|
||||||
|
std.debug.relocateContext(&thread_context);
|
||||||
context = ExpressionContext{
|
context = ExpressionContext{
|
||||||
.thread_context = &thread_context,
|
.thread_context = &thread_context,
|
||||||
.reg_context = reg_context,
|
.reg_context = reg_context,
|
||||||
|
|||||||
@ -19,9 +19,19 @@ noinline fn frame3(expected: *[4]usize, unwound: *[4]usize) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
noinline fn frame2(expected: *[4]usize, unwound: *[4]usize) void {
|
noinline fn frame2(expected: *[4]usize, unwound: *[4]usize) void {
|
||||||
if (builtin.os.tag == .macos) {
|
// Excercise different __unwind_info / DWARF CFI encodings by forcing some registers to be restored
|
||||||
// Excercise different __unwind_info encodings by forcing some registers to be restored
|
if (builtin.target.ofmt != .c) {
|
||||||
switch (builtin.cpu.arch) {
|
switch (builtin.cpu.arch) {
|
||||||
|
.x86 => {
|
||||||
|
asm volatile (
|
||||||
|
\\movl $3, %%ebx
|
||||||
|
\\movl $1, %%ecx
|
||||||
|
\\movl $2, %%edx
|
||||||
|
\\movl $7, %%edi
|
||||||
|
\\movl $6, %%esi
|
||||||
|
\\movl $5, %%ebp
|
||||||
|
::: "ebx", "ecx", "edx", "edi", "esi", "ebp");
|
||||||
|
},
|
||||||
.x86_64 => {
|
.x86_64 => {
|
||||||
asm volatile (
|
asm volatile (
|
||||||
\\movq $3, %%rbx
|
\\movq $3, %%rbx
|
||||||
@ -32,7 +42,6 @@ noinline fn frame2(expected: *[4]usize, unwound: *[4]usize) void {
|
|||||||
\\movq $6, %%rbp
|
\\movq $6, %%rbp
|
||||||
::: "rbx", "r12", "r13", "r14", "r15", "rbp");
|
::: "rbx", "r12", "r13", "r14", "r15", "rbp");
|
||||||
},
|
},
|
||||||
.aarch64 => {},
|
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user