mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
debug: add dupeContext, store a pointer to a copy of ThreadContext on UnwindContext
This commit is contained in:
parent
463bbe7807
commit
5c0d4cef1a
@ -133,6 +133,9 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// use internal pointers within this structure. To make a copy, use `dupeContext`.
|
||||
pub const ThreadContext = blk: {
|
||||
if (native_os == .windows) {
|
||||
break :blk std.os.windows.CONTEXT;
|
||||
@ -457,6 +460,19 @@ pub inline fn getContext(context: *ThreadContext) bool {
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn dupeContext(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)
|
||||
@typeInfo(@typeInfo(@TypeOf(StackIterator.next_dwarf)).Fn.return_type.?).ErrorUnion.error_set
|
||||
else
|
||||
|
||||
@ -1676,7 +1676,7 @@ pub const DwarfInfo = struct {
|
||||
var expression_context = .{
|
||||
.isValidMemory = context.isValidMemory,
|
||||
.compile_unit = di.findCompileUnit(fde.pc_begin) catch null,
|
||||
.thread_context = &context.thread_context,
|
||||
.thread_context = context.thread_context,
|
||||
.reg_context = context.reg_context,
|
||||
.cfa = context.cfa,
|
||||
};
|
||||
@ -1690,7 +1690,7 @@ pub const DwarfInfo = struct {
|
||||
context.cfa = switch (row.cfa.rule) {
|
||||
.val_offset => |offset| blk: {
|
||||
const register = row.cfa.register orelse return error.InvalidCFARule;
|
||||
const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.thread_context, register, context.reg_context));
|
||||
const value = mem.readIntSliceNative(usize, try abi.regBytes(context.thread_context, register, context.reg_context));
|
||||
break :blk try call_frame.applyOffset(value, offset);
|
||||
},
|
||||
.expression => |expression| blk: {
|
||||
@ -1733,7 +1733,7 @@ pub const DwarfInfo = struct {
|
||||
has_next_ip = column.rule != .undefined;
|
||||
}
|
||||
|
||||
const old_value = try abi.regBytes(&context.thread_context, register, context.reg_context);
|
||||
const old_value = try abi.regBytes(context.thread_context, register, context.reg_context);
|
||||
const new_value = try update_allocator.alloc(u8, old_value.len);
|
||||
|
||||
const prev = update_tail;
|
||||
@ -1758,12 +1758,12 @@ pub const DwarfInfo = struct {
|
||||
}
|
||||
|
||||
if (has_next_ip) {
|
||||
context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.thread_context, comptime abi.ipRegNum(), context.reg_context));
|
||||
context.pc = mem.readIntSliceNative(usize, try abi.regBytes(context.thread_context, comptime abi.ipRegNum(), context.reg_context));
|
||||
} else {
|
||||
context.pc = 0;
|
||||
}
|
||||
|
||||
mem.writeIntSliceNative(usize, try abi.regBytes(&context.thread_context, abi.spRegNum(context.reg_context), context.reg_context), context.cfa.?);
|
||||
mem.writeIntSliceNative(usize, try abi.regBytes(context.thread_context, abi.spRegNum(context.reg_context), context.reg_context), context.cfa.?);
|
||||
|
||||
// The call instruction will have pushed the address of the instruction that follows the call as the return address
|
||||
// However, this return address may be past the end of the function if the caller was `noreturn`.
|
||||
@ -1779,7 +1779,7 @@ pub const UnwindContext = struct {
|
||||
allocator: mem.Allocator,
|
||||
cfa: ?usize,
|
||||
pc: usize,
|
||||
thread_context: debug.ThreadContext,
|
||||
thread_context: *debug.ThreadContext,
|
||||
reg_context: abi.RegisterContext,
|
||||
isValidMemory: *const fn (address: usize) bool,
|
||||
vm: call_frame.VirtualMachine = .{},
|
||||
@ -1788,14 +1788,14 @@ pub const UnwindContext = struct {
|
||||
pub fn init(allocator: mem.Allocator, thread_context: *const debug.ThreadContext, isValidMemory: *const fn (address: usize) bool) !UnwindContext {
|
||||
const pc = mem.readIntSliceNative(usize, try abi.regBytes(thread_context, abi.ipRegNum(), null));
|
||||
|
||||
if (builtin.os.tag == .macos) @compileError("Fix below TODO");
|
||||
const context_copy = try allocator.create(debug.ThreadContext);
|
||||
debug.dupeContext(thread_context, context_copy);
|
||||
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.cfa = null,
|
||||
.pc = pc,
|
||||
// TODO: This is broken on macos, need a function that knows how to copy the OSs mcontext properly
|
||||
.thread_context = thread_context.*,
|
||||
.thread_context = context_copy,
|
||||
.reg_context = undefined,
|
||||
.isValidMemory = isValidMemory,
|
||||
};
|
||||
@ -1804,10 +1804,11 @@ pub const UnwindContext = struct {
|
||||
pub fn deinit(self: *UnwindContext) void {
|
||||
self.vm.deinit(self.allocator);
|
||||
self.stack_machine.deinit(self.allocator);
|
||||
self.allocator.destroy(self.thread_context);
|
||||
}
|
||||
|
||||
pub fn getFp(self: *const UnwindContext) !usize {
|
||||
return mem.readIntSliceNative(usize, try abi.regBytes(&self.thread_context, abi.fpRegNum(self.reg_context), self.reg_context));
|
||||
return mem.readIntSliceNative(usize, try abi.regBytes(self.thread_context, abi.fpRegNum(self.reg_context), self.reg_context));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -315,9 +315,9 @@ pub const VirtualMachine = struct {
|
||||
} else return error.InvalidCFA;
|
||||
},
|
||||
.register => |register| {
|
||||
const src = try abi.regBytes(&context.thread_context, register, context.reg_context);
|
||||
const src = try abi.regBytes(context.thread_context, register, context.reg_context);
|
||||
if (src.len != out.len) return error.RegisterTypeMismatch;
|
||||
@memcpy(out, try abi.regBytes(&context.thread_context, register, context.reg_context));
|
||||
@memcpy(out, try abi.regBytes(context.thread_context, register, context.reg_context));
|
||||
},
|
||||
.expression => |expression| {
|
||||
context.stack_machine.reset();
|
||||
|
||||
@ -1070,8 +1070,10 @@ test "DWARF expressions" {
|
||||
}
|
||||
|
||||
// Register values
|
||||
var thread_context: std.debug.ThreadContext = undefined;
|
||||
if (std.debug.getContext(&thread_context)) {
|
||||
if (@TypeOf(std.debug.ThreadContext) != void) {
|
||||
var thread_context: std.debug.ThreadContext = undefined;
|
||||
_ = thread_context;
|
||||
|
||||
// TODO: Test fbreg, breg0..31, bregx, regval_type
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user