mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 06:15:21 +00:00
dwarf: implement more register number mappings
- add dwarf.abi.RegisterContext to handle register numbers changing based on DWARF format
This commit is contained in:
parent
b449d98a93
commit
9145ff7da0
@ -521,6 +521,8 @@ pub const StackIterator = struct {
|
||||
fn next_dwarf(self: *StackIterator) !void {
|
||||
const module = try self.debug_info.?.getModuleForAddress(self.dwarf_context.pc);
|
||||
if (module.getDwarfInfo()) |di| {
|
||||
self.dwarf_context.reg_ctx.eh_frame = true;
|
||||
self.dwarf_context.reg_ctx.is_macho = di.is_macho;
|
||||
try di.unwindFrame(self.debug_info.?.allocator, &self.dwarf_context, module.base_address);
|
||||
} else return error.MissingDebugInfo;
|
||||
}
|
||||
@ -532,6 +534,10 @@ pub const StackIterator = struct {
|
||||
} else |err| {
|
||||
// Fall back to fp unwinding on the first failure,
|
||||
// as the register context won't be updated
|
||||
|
||||
// TODO: Could still attempt dwarf unwinding after this, maybe marking non-updated registers as
|
||||
// invalid, so the unwind only fails if it requires out of date registers?
|
||||
|
||||
self.fp = self.dwarf_context.getFp() catch 0;
|
||||
self.debug_info = null;
|
||||
|
||||
@ -854,6 +860,7 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_bytes: []const u8) !ModuleDe
|
||||
var dwarf = DW.DwarfInfo{
|
||||
.endian = native_endian,
|
||||
.sections = sections,
|
||||
.is_macho = false,
|
||||
};
|
||||
|
||||
try DW.openDwarfDebugInfo(&dwarf, allocator, coff_bytes);
|
||||
@ -1079,6 +1086,7 @@ pub fn readElfDebugInfo(
|
||||
var di = DW.DwarfInfo{
|
||||
.endian = endian,
|
||||
.sections = sections,
|
||||
.is_macho = false,
|
||||
};
|
||||
|
||||
try DW.openDwarfDebugInfo(&di, allocator, parent_mapped_mem orelse mapped_mem);
|
||||
@ -1682,6 +1690,10 @@ pub const ModuleDebugInfo = switch (native_os) {
|
||||
|
||||
var di = DW.DwarfInfo{
|
||||
.endian = .Little,
|
||||
.is_macho = true,
|
||||
|
||||
// TODO: Get this compiling
|
||||
|
||||
.debug_info = try chopSlice(mapped_mem, debug_info.offset, debug_info.size),
|
||||
.debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size),
|
||||
.debug_str = try chopSlice(mapped_mem, debug_str.offset, debug_str.size),
|
||||
|
||||
@ -686,6 +686,8 @@ pub const DwarfInfo = struct {
|
||||
// Sorted by start_pc
|
||||
fde_list: std.ArrayListUnmanaged(FrameDescriptionEntry) = .{},
|
||||
|
||||
is_macho: bool,
|
||||
|
||||
pub fn section(di: DwarfInfo, dwarf_section: DwarfSection) ?[]const u8 {
|
||||
return if (di.sections[@enumToInt(dwarf_section)]) |s| s.data else null;
|
||||
}
|
||||
@ -712,6 +714,7 @@ pub const DwarfInfo = struct {
|
||||
}
|
||||
|
||||
pub fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {
|
||||
// TODO: Can this be binary searched?
|
||||
for (di.func_list.items) |*func| {
|
||||
if (func.pc_range) |range| {
|
||||
if (address >= range.start and address < range.end) {
|
||||
@ -853,6 +856,9 @@ pub const DwarfInfo = struct {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Debug issue where `puts` in Ubuntu's libc was not found
|
||||
//if (fn_name != null and pc_range != null) debug.print("func_list: {s} -> 0x{x}-0x{x}\n", .{fn_name.?, pc_range.?.start, pc_range.?.end});
|
||||
|
||||
try di.func_list.append(allocator, Func{
|
||||
.name = fn_name,
|
||||
.pc_range = pc_range,
|
||||
@ -1587,7 +1593,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.ucontext, register));
|
||||
const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, register, context.reg_ctx));
|
||||
|
||||
// TODO: Check isValidMemory?
|
||||
break :blk try call_frame.applyOffset(value, offset);
|
||||
@ -1602,15 +1608,13 @@ pub const DwarfInfo = struct {
|
||||
else => return error.InvalidCFARule,
|
||||
};
|
||||
|
||||
// Update the context with the unwound values
|
||||
// TODO: Need old cfa and pc?
|
||||
|
||||
// Update the context with the previous frame's values
|
||||
var next_ucontext = context.ucontext;
|
||||
|
||||
var has_next_ip = false;
|
||||
for (vm.rowColumns(row)) |column| {
|
||||
if (column.register) |register| {
|
||||
const dest = try abi.regBytes(&next_ucontext, register);
|
||||
const dest = try abi.regBytes(&next_ucontext, register, context.reg_ctx);
|
||||
if (register == cie.return_address_register) {
|
||||
has_next_ip = column.rule != .undefined;
|
||||
}
|
||||
@ -1622,12 +1626,12 @@ pub const DwarfInfo = struct {
|
||||
context.ucontext = next_ucontext;
|
||||
|
||||
if (has_next_ip) {
|
||||
context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, @enumToInt(abi.Register.ip)));
|
||||
context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, abi.ipRegNum(), context.reg_ctx));
|
||||
} else {
|
||||
context.pc = 0;
|
||||
}
|
||||
|
||||
mem.writeIntSliceNative(usize, try abi.regBytes(&context.ucontext, @enumToInt(abi.Register.sp)), context.cfa.?);
|
||||
mem.writeIntSliceNative(usize, try abi.regBytes(&context.ucontext, abi.spRegNum(context.reg_ctx), context.reg_ctx), context.cfa.?);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1635,18 +1639,20 @@ pub const UnwindContext = struct {
|
||||
cfa: ?usize,
|
||||
pc: usize,
|
||||
ucontext: os.ucontext_t,
|
||||
reg_ctx: abi.RegisterContext,
|
||||
|
||||
pub fn init(ucontext: *const os.ucontext_t) !UnwindContext {
|
||||
const pc = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, @enumToInt(abi.Register.ip)));
|
||||
const pc = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, abi.ipRegNum(), null));
|
||||
return .{
|
||||
.cfa = null,
|
||||
.pc = pc,
|
||||
.ucontext = ucontext.*,
|
||||
.reg_ctx = undefined,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getFp(self: *const UnwindContext) !usize {
|
||||
return mem.readIntSliceNative(usize, try abi.regBytes(&self.ucontext, @enumToInt(abi.Register.fp)));
|
||||
return mem.readIntSliceNative(usize, try abi.regBytes(&self.ucontext, abi.fpRegNum(self.reg_ctx), self.reg_ctx));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -3,56 +3,87 @@ const std = @import("../std.zig");
|
||||
const os = std.os;
|
||||
const mem = std.mem;
|
||||
|
||||
/// Maps register names to their DWARF register number.
|
||||
/// `bp`, `ip`, and `sp` are provided as aliases.
|
||||
pub const Register = switch (builtin.cpu.arch) {
|
||||
.x86 => {
|
||||
|
||||
//pub const ip = Register.eip;
|
||||
//pub const sp = Register.
|
||||
},
|
||||
.x86_64 => enum(u8) {
|
||||
rax,
|
||||
rdx,
|
||||
rcx,
|
||||
rbx,
|
||||
rsi,
|
||||
rdi,
|
||||
rbp,
|
||||
rsp,
|
||||
r8,
|
||||
r9,
|
||||
r10,
|
||||
r11,
|
||||
r12,
|
||||
r13,
|
||||
r14,
|
||||
r15,
|
||||
rip,
|
||||
xmm0,
|
||||
xmm1,
|
||||
xmm2,
|
||||
xmm3,
|
||||
xmm4,
|
||||
xmm5,
|
||||
xmm6,
|
||||
xmm7,
|
||||
xmm8,
|
||||
xmm9,
|
||||
xmm10,
|
||||
xmm11,
|
||||
xmm12,
|
||||
xmm13,
|
||||
xmm14,
|
||||
xmm15,
|
||||
|
||||
pub const fp = Register.rbp;
|
||||
pub const ip = Register.rip;
|
||||
pub const sp = Register.rsp;
|
||||
},
|
||||
else => enum {},
|
||||
pub const RegisterContext = struct {
|
||||
eh_frame: bool,
|
||||
is_macho: bool,
|
||||
};
|
||||
|
||||
pub fn ipRegNum() u8 {
|
||||
return switch (builtin.cpu.arch) {
|
||||
.x86 => 8,
|
||||
.x86_64 => 16,
|
||||
.arm => error.InvalidRegister, // TODO
|
||||
.aarch64 => error.InvalidRegister, // TODO
|
||||
|
||||
// const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
|
||||
// const ip = switch (native_os) {
|
||||
// .macos => @intCast(usize, ctx.mcontext.ss.pc),
|
||||
// .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]),
|
||||
// .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr),
|
||||
// else => @intCast(usize, ctx.mcontext.pc),
|
||||
// };
|
||||
// // x29 is the ABI-designated frame pointer
|
||||
// const bp = switch (native_os) {
|
||||
// .macos => @intCast(usize, ctx.mcontext.ss.fp),
|
||||
// .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]),
|
||||
// .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]),
|
||||
// else => @intCast(usize, ctx.mcontext.regs[29]),
|
||||
// };
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fpRegNum(reg_ctx: RegisterContext) u8 {
|
||||
return switch (builtin.cpu.arch) {
|
||||
// GCC on OS X did the opposite of ELF for these registers (only in .eh_frame), and that is now the convention for MachO
|
||||
.x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 4 else 5,
|
||||
.x86_64 => 6,
|
||||
.arm => error.InvalidRegister, // TODO
|
||||
.aarch64 => error.InvalidRegister, // TODO
|
||||
|
||||
// const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
|
||||
// const ip = switch (native_os) {
|
||||
// .macos => @intCast(usize, ctx.mcontext.ss.pc),
|
||||
// .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]),
|
||||
// .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr),
|
||||
// else => @intCast(usize, ctx.mcontext.pc),
|
||||
// };
|
||||
// // x29 is the ABI-designated frame pointer
|
||||
// const bp = switch (native_os) {
|
||||
// .macos => @intCast(usize, ctx.mcontext.ss.fp),
|
||||
// .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]),
|
||||
// .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]),
|
||||
// else => @intCast(usize, ctx.mcontext.regs[29]),
|
||||
// };
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn spRegNum(reg_ctx: RegisterContext) u8 {
|
||||
return switch (builtin.cpu.arch) {
|
||||
.x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 5 else 4,
|
||||
.x86_64 => 7,
|
||||
.arm => error.InvalidRegister, // TODO
|
||||
.aarch64 => error.InvalidRegister, // TODO
|
||||
|
||||
// const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
|
||||
// const ip = switch (native_os) {
|
||||
// .macos => @intCast(usize, ctx.mcontext.ss.pc),
|
||||
// .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]),
|
||||
// .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr),
|
||||
// else => @intCast(usize, ctx.mcontext.pc),
|
||||
// };
|
||||
// // x29 is the ABI-designated frame pointer
|
||||
// const bp = switch (native_os) {
|
||||
// .macos => @intCast(usize, ctx.mcontext.ss.fp),
|
||||
// .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]),
|
||||
// .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]),
|
||||
// else => @intCast(usize, ctx.mcontext.regs[29]),
|
||||
// };
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
fn RegBytesReturnType(comptime ContextPtrType: type) type {
|
||||
const info = @typeInfo(ContextPtrType);
|
||||
if (info != .Pointer or info.Pointer.child != os.ucontext_t) {
|
||||
@ -62,36 +93,132 @@ fn RegBytesReturnType(comptime ContextPtrType: type) type {
|
||||
return if (info.Pointer.is_const) return []const u8 else []u8;
|
||||
}
|
||||
|
||||
/// Returns a slice containing the backing storage for `reg_number`
|
||||
pub fn regBytes(ucontext_ptr: anytype, reg_number: u8) !RegBytesReturnType(@TypeOf(ucontext_ptr)) {
|
||||
/// Returns a slice containing the backing storage for `reg_number`.
|
||||
///
|
||||
/// `reg_ctx` describes in what context the register number is used, as it can have different
|
||||
/// meanings depending on the DWARF container. It is only required when getting the stack or
|
||||
/// frame pointer register on some architectures.
|
||||
pub fn regBytes(ucontext_ptr: anytype, reg_number: u8, reg_ctx: ?RegisterContext) !RegBytesReturnType(@TypeOf(ucontext_ptr)) {
|
||||
var m = &ucontext_ptr.mcontext;
|
||||
|
||||
return switch (builtin.cpu.arch) {
|
||||
.x86 => switch (reg_number) {
|
||||
0 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EAX]),
|
||||
1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ECX]),
|
||||
2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDX]),
|
||||
3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBX]),
|
||||
4...5 => if (reg_ctx) |r| bytes: {
|
||||
if (reg_number == 4) {
|
||||
break :bytes if (r.eh_frame and r.is_macho)
|
||||
mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBP])
|
||||
else
|
||||
mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESP]);
|
||||
} else {
|
||||
break :bytes if (r.eh_frame and r.is_macho)
|
||||
mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESP])
|
||||
else
|
||||
mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBP]);
|
||||
}
|
||||
} else error.RegisterContextRequired,
|
||||
6 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESI]),
|
||||
7 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDI]),
|
||||
8 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EIP]),
|
||||
9 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EFL]),
|
||||
10 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.CS]),
|
||||
11 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.SS]),
|
||||
12 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.DS]),
|
||||
13 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ES]),
|
||||
14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.FS]),
|
||||
15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.GS]),
|
||||
16...23 => error.InvalidRegister, // TODO: Support loading ST0-ST7 from mcontext.fpregs
|
||||
// TODO: Map TRAPNO, ERR, UESP
|
||||
32...39 => error.InvalidRegister, // TODO: Support loading XMM0-XMM7 from mcontext.fpregs
|
||||
else => error.InvalidRegister,
|
||||
},
|
||||
.x86_64 => switch (builtin.os.tag) {
|
||||
.linux, .netbsd, .solaris => switch (reg_number) {
|
||||
0 => mem.asBytes(&m.gregs[os.REG.RAX]),
|
||||
1 => mem.asBytes(&m.gregs[os.REG.RDX]),
|
||||
2 => mem.asBytes(&m.gregs[os.REG.RCX]),
|
||||
3 => mem.asBytes(&m.gregs[os.REG.RBX]),
|
||||
4 => mem.asBytes(&m.gregs[os.REG.RSI]),
|
||||
5 => mem.asBytes(&m.gregs[os.REG.RDI]),
|
||||
6 => mem.asBytes(&m.gregs[os.REG.RBP]),
|
||||
7 => mem.asBytes(&m.gregs[os.REG.RSP]),
|
||||
8 => mem.asBytes(&m.gregs[os.REG.R8]),
|
||||
9 => mem.asBytes(&m.gregs[os.REG.R9]),
|
||||
10 => mem.asBytes(&m.gregs[os.REG.R10]),
|
||||
11 => mem.asBytes(&m.gregs[os.REG.R11]),
|
||||
12 => mem.asBytes(&m.gregs[os.REG.R12]),
|
||||
13 => mem.asBytes(&m.gregs[os.REG.R13]),
|
||||
14 => mem.asBytes(&m.gregs[os.REG.R14]),
|
||||
15 => mem.asBytes(&m.gregs[os.REG.R15]),
|
||||
16 => mem.asBytes(&m.gregs[os.REG.RIP]),
|
||||
0 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RAX]),
|
||||
1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RDX]),
|
||||
2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RCX]),
|
||||
3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RBX]),
|
||||
4 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RSI]),
|
||||
5 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RDI]),
|
||||
6 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RBP]),
|
||||
7 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RSP]),
|
||||
8 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R8]),
|
||||
9 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R9]),
|
||||
10 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R10]),
|
||||
11 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R11]),
|
||||
12 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R12]),
|
||||
13 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R13]),
|
||||
14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R14]),
|
||||
15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R15]),
|
||||
16 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RIP]),
|
||||
17...32 => |i| mem.asBytes(&m.fpregs.xmm[i - 17]),
|
||||
else => error.InvalidRegister,
|
||||
},
|
||||
//.freebsd => @intCast(usize, ctx.mcontext.rip),
|
||||
//.openbsd => @intCast(usize, ctx.sc_rip),
|
||||
//.macos => @intCast(usize, ctx.mcontext.ss.rip),
|
||||
.freebsd => switch (reg_number) {
|
||||
0 => mem.asBytes(&ucontext_ptr.mcontext.rax),
|
||||
1 => mem.asBytes(&ucontext_ptr.mcontext.rdx),
|
||||
2 => mem.asBytes(&ucontext_ptr.mcontext.rcx),
|
||||
3 => mem.asBytes(&ucontext_ptr.mcontext.rbx),
|
||||
4 => mem.asBytes(&ucontext_ptr.mcontext.rsi),
|
||||
5 => mem.asBytes(&ucontext_ptr.mcontext.rdi),
|
||||
6 => mem.asBytes(&ucontext_ptr.mcontext.rbp),
|
||||
7 => mem.asBytes(&ucontext_ptr.mcontext.rsp),
|
||||
8 => mem.asBytes(&ucontext_ptr.mcontext.r8),
|
||||
9 => mem.asBytes(&ucontext_ptr.mcontext.r9),
|
||||
10 => mem.asBytes(&ucontext_ptr.mcontext.r10),
|
||||
11 => mem.asBytes(&ucontext_ptr.mcontext.r11),
|
||||
12 => mem.asBytes(&ucontext_ptr.mcontext.r12),
|
||||
13 => mem.asBytes(&ucontext_ptr.mcontext.r13),
|
||||
14 => mem.asBytes(&ucontext_ptr.mcontext.r14),
|
||||
15 => mem.asBytes(&ucontext_ptr.mcontext.r15),
|
||||
16 => mem.asBytes(&ucontext_ptr.mcontext.rip),
|
||||
// TODO: Extract xmm state from mcontext.fpstate?
|
||||
else => error.InvalidRegister,
|
||||
},
|
||||
.openbsd => switch (reg_number) {
|
||||
0 => mem.asBytes(&ucontext_ptr.sc_rax),
|
||||
1 => mem.asBytes(&ucontext_ptr.sc_rdx),
|
||||
2 => mem.asBytes(&ucontext_ptr.sc_rcx),
|
||||
3 => mem.asBytes(&ucontext_ptr.sc_rbx),
|
||||
4 => mem.asBytes(&ucontext_ptr.sc_rsi),
|
||||
5 => mem.asBytes(&ucontext_ptr.sc_rdi),
|
||||
6 => mem.asBytes(&ucontext_ptr.sc_rbp),
|
||||
7 => mem.asBytes(&ucontext_ptr.sc_rsp),
|
||||
8 => mem.asBytes(&ucontext_ptr.sc_r8),
|
||||
9 => mem.asBytes(&ucontext_ptr.sc_r9),
|
||||
10 => mem.asBytes(&ucontext_ptr.sc_r10),
|
||||
11 => mem.asBytes(&ucontext_ptr.sc_r11),
|
||||
12 => mem.asBytes(&ucontext_ptr.sc_r12),
|
||||
13 => mem.asBytes(&ucontext_ptr.sc_r13),
|
||||
14 => mem.asBytes(&ucontext_ptr.sc_r14),
|
||||
15 => mem.asBytes(&ucontext_ptr.sc_r15),
|
||||
16 => mem.asBytes(&ucontext_ptr.sc_rip),
|
||||
// TODO: Extract xmm state from sc_fpstate?
|
||||
else => error.InvalidRegister,
|
||||
},
|
||||
.macos => switch (reg_number) {
|
||||
0 => mem.asBytes(&ucontext_ptr.mcontext.ss.rax),
|
||||
1 => mem.asBytes(&ucontext_ptr.mcontext.ss.rdx),
|
||||
2 => mem.asBytes(&ucontext_ptr.mcontext.ss.rcx),
|
||||
3 => mem.asBytes(&ucontext_ptr.mcontext.ss.rbx),
|
||||
4 => mem.asBytes(&ucontext_ptr.mcontext.ss.rsi),
|
||||
5 => mem.asBytes(&ucontext_ptr.mcontext.ss.rdi),
|
||||
6 => mem.asBytes(&ucontext_ptr.mcontext.ss.rbp),
|
||||
7 => mem.asBytes(&ucontext_ptr.mcontext.ss.rsp),
|
||||
8 => mem.asBytes(&ucontext_ptr.mcontext.ss.r8),
|
||||
9 => mem.asBytes(&ucontext_ptr.mcontext.ss.r9),
|
||||
10 => mem.asBytes(&ucontext_ptr.mcontext.ss.r10),
|
||||
11 => mem.asBytes(&ucontext_ptr.mcontext.ss.r11),
|
||||
12 => mem.asBytes(&ucontext_ptr.mcontext.ss.r12),
|
||||
13 => mem.asBytes(&ucontext_ptr.mcontext.ss.r13),
|
||||
14 => mem.asBytes(&ucontext_ptr.mcontext.ss.r14),
|
||||
15 => mem.asBytes(&ucontext_ptr.mcontext.ss.r15),
|
||||
16 => mem.asBytes(&ucontext_ptr.mcontext.ss.rip),
|
||||
else => error.InvalidRegister,
|
||||
},
|
||||
else => error.UnimplementedOs,
|
||||
},
|
||||
else => error.UnimplementedArch,
|
||||
|
||||
@ -304,9 +304,9 @@ pub const VirtualMachine = struct {
|
||||
} else return error.InvalidCFA;
|
||||
},
|
||||
.register => |register| {
|
||||
const src = try abi.regBytes(&context.ucontext, register);
|
||||
const src = try abi.regBytes(&context.ucontext, register, context.reg_ctx);
|
||||
if (src.len != out.len) return error.RegisterTypeMismatch;
|
||||
@memcpy(out, try abi.regBytes(&context.ucontext, register));
|
||||
@memcpy(out, try abi.regBytes(&context.ucontext, register, context.reg_ctx));
|
||||
},
|
||||
.expression => |expression| {
|
||||
// TODO
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user