aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorkcbanner <kcbanner@gmail.com>2023-05-22 14:45:24 -0400
committerkcbanner <kcbanner@gmail.com>2023-07-20 22:58:13 -0400
commit9145ff7da073966ace27151f7a0921b20c7860f4 (patch)
treee033aa47d0a73180f7f7bcdb220f2e91d2897db0 /lib/std
parentb449d98a935a20429874d8eb379d9cc0e49c5fcd (diff)
downloadzig-9145ff7da073966ace27151f7a0921b20c7860f4.tar.gz
zig-9145ff7da073966ace27151f7a0921b20c7860f4.zip
dwarf: implement more register number mappings
- add dwarf.abi.RegisterContext to handle register numbers changing based on DWARF format
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/debug.zig12
-rw-r--r--lib/std/dwarf.zig24
-rw-r--r--lib/std/dwarf/abi.zig267
-rw-r--r--lib/std/dwarf/call_frame.zig4
4 files changed, 226 insertions, 81 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 5e63bd9704..66dfdc1838 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -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),
diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig
index d36aceee93..99c26051c8 100644
--- a/lib/std/dwarf.zig
+++ b/lib/std/dwarf.zig
@@ -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));
}
};
diff --git a/lib/std/dwarf/abi.zig b/lib/std/dwarf/abi.zig
index 913743f0f8..35f805bbf4 100644
--- a/lib/std/dwarf/abi.zig
+++ b/lib/std/dwarf/abi.zig
@@ -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,
diff --git a/lib/std/dwarf/call_frame.zig b/lib/std/dwarf/call_frame.zig
index e9761206ed..8a8d083031 100644
--- a/lib/std/dwarf/call_frame.zig
+++ b/lib/std/dwarf/call_frame.zig
@@ -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