authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-05-22 14:45:24-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:13-04:00
log9145ff7da073966ace27151f7a0921b20c7860f4
treee033aa47d0a73180f7f7bcdb220f2e91d2897db0
parentb449d98a935a20429874d8eb379d9cc0e49c5fcd

dwarf: implement more register number mappings

- add dwarf.abi.RegisterContext to handle register numbers changing based on DWARF format

4 files changed, 226 insertions(+), 81 deletions(-)

lib/std/debug.zig+12
......@@ -521,6 +521,8 @@ pub const StackIterator = struct {
521521 fn next_dwarf(self: *StackIterator) !void {
522522 const module = try self.debug_info.?.getModuleForAddress(self.dwarf_context.pc);
523523 if (module.getDwarfInfo()) |di| {
524 self.dwarf_context.reg_ctx.eh_frame = true;
525 self.dwarf_context.reg_ctx.is_macho = di.is_macho;
524526 try di.unwindFrame(self.debug_info.?.allocator, &self.dwarf_context, module.base_address);
525527 } else return error.MissingDebugInfo;
526528 }
......@@ -532,6 +534,10 @@ pub const StackIterator = struct {
532534 } else |err| {
533535 // Fall back to fp unwinding on the first failure,
534536 // as the register context won't be updated
537
538 // TODO: Could still attempt dwarf unwinding after this, maybe marking non-updated registers as
539 // invalid, so the unwind only fails if it requires out of date registers?
540
535541 self.fp = self.dwarf_context.getFp() catch 0;
536542 self.debug_info = null;
537543
......@@ -854,6 +860,7 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_bytes: []const u8) !ModuleDe
854860 var dwarf = DW.DwarfInfo{
855861 .endian = native_endian,
856862 .sections = sections,
863 .is_macho = false,
857864 };
858865
859866 try DW.openDwarfDebugInfo(&dwarf, allocator, coff_bytes);
......@@ -1079,6 +1086,7 @@ pub fn readElfDebugInfo(
10791086 var di = DW.DwarfInfo{
10801087 .endian = endian,
10811088 .sections = sections,
1089 .is_macho = false,
10821090 };
10831091
10841092 try DW.openDwarfDebugInfo(&di, allocator, parent_mapped_mem orelse mapped_mem);
......@@ -1682,6 +1690,10 @@ pub const ModuleDebugInfo = switch (native_os) {
16821690
16831691 var di = DW.DwarfInfo{
16841692 .endian = .Little,
1693 .is_macho = true,
1694
1695 // TODO: Get this compiling
1696
16851697 .debug_info = try chopSlice(mapped_mem, debug_info.offset, debug_info.size),
16861698 .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size),
16871699 .debug_str = try chopSlice(mapped_mem, debug_str.offset, debug_str.size),
lib/std/dwarf.zig+15-9
......@@ -686,6 +686,8 @@ pub const DwarfInfo = struct {
686686 // Sorted by start_pc
687687 fde_list: std.ArrayListUnmanaged(FrameDescriptionEntry) = .{},
688688
689 is_macho: bool,
690
689691 pub fn section(di: DwarfInfo, dwarf_section: DwarfSection) ?[]const u8 {
690692 return if (di.sections[@enumToInt(dwarf_section)]) |s| s.data else null;
691693 }
......@@ -712,6 +714,7 @@ pub const DwarfInfo = struct {
712714 }
713715
714716 pub fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 {
717 // TODO: Can this be binary searched?
715718 for (di.func_list.items) |*func| {
716719 if (func.pc_range) |range| {
717720 if (address >= range.start and address < range.end) {
......@@ -853,6 +856,9 @@ pub const DwarfInfo = struct {
853856 }
854857 };
855858
859 // TODO: Debug issue where `puts` in Ubuntu's libc was not found
860 //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});
861
856862 try di.func_list.append(allocator, Func{
857863 .name = fn_name,
858864 .pc_range = pc_range,
......@@ -1587,7 +1593,7 @@ pub const DwarfInfo = struct {
15871593 context.cfa = switch (row.cfa.rule) {
15881594 .val_offset => |offset| blk: {
15891595 const register = row.cfa.register orelse return error.InvalidCFARule;
1590 const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, register));
1596 const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, register, context.reg_ctx));
15911597
15921598 // TODO: Check isValidMemory?
15931599 break :blk try call_frame.applyOffset(value, offset);
......@@ -1602,15 +1608,13 @@ pub const DwarfInfo = struct {
16021608 else => return error.InvalidCFARule,
16031609 };
16041610
1605 // Update the context with the unwound values
1606 // TODO: Need old cfa and pc?
1607
1611 // Update the context with the previous frame's values
16081612 var next_ucontext = context.ucontext;
16091613
16101614 var has_next_ip = false;
16111615 for (vm.rowColumns(row)) |column| {
16121616 if (column.register) |register| {
1613 const dest = try abi.regBytes(&next_ucontext, register);
1617 const dest = try abi.regBytes(&next_ucontext, register, context.reg_ctx);
16141618 if (register == cie.return_address_register) {
16151619 has_next_ip = column.rule != .undefined;
16161620 }
......@@ -1622,12 +1626,12 @@ pub const DwarfInfo = struct {
16221626 context.ucontext = next_ucontext;
16231627
16241628 if (has_next_ip) {
1625 context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, @enumToInt(abi.Register.ip)));
1629 context.pc = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, abi.ipRegNum(), context.reg_ctx));
16261630 } else {
16271631 context.pc = 0;
16281632 }
16291633
1630 mem.writeIntSliceNative(usize, try abi.regBytes(&context.ucontext, @enumToInt(abi.Register.sp)), context.cfa.?);
1634 mem.writeIntSliceNative(usize, try abi.regBytes(&context.ucontext, abi.spRegNum(context.reg_ctx), context.reg_ctx), context.cfa.?);
16311635 }
16321636};
16331637
......@@ -1635,18 +1639,20 @@ pub const UnwindContext = struct {
16351639 cfa: ?usize,
16361640 pc: usize,
16371641 ucontext: os.ucontext_t,
1642 reg_ctx: abi.RegisterContext,
16381643
16391644 pub fn init(ucontext: *const os.ucontext_t) !UnwindContext {
1640 const pc = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, @enumToInt(abi.Register.ip)));
1645 const pc = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, abi.ipRegNum(), null));
16411646 return .{
16421647 .cfa = null,
16431648 .pc = pc,
16441649 .ucontext = ucontext.*,
1650 .reg_ctx = undefined,
16451651 };
16461652 }
16471653
16481654 pub fn getFp(self: *const UnwindContext) !usize {
1649 return mem.readIntSliceNative(usize, try abi.regBytes(&self.ucontext, @enumToInt(abi.Register.fp)));
1655 return mem.readIntSliceNative(usize, try abi.regBytes(&self.ucontext, abi.fpRegNum(self.reg_ctx), self.reg_ctx));
16501656 }
16511657};
16521658
lib/std/dwarf/abi.zig+197-70
......@@ -3,56 +3,87 @@ const std = @import("../std.zig");
33const os = std.os;
44const mem = std.mem;
55
6/// Maps register names to their DWARF register number.
7/// `bp`, `ip`, and `sp` are provided as aliases.
8pub const Register = switch (builtin.cpu.arch) {
9 .x86 => {
10
11 //pub const ip = Register.eip;
12 //pub const sp = Register.
13 },
14 .x86_64 => enum(u8) {
15 rax,
16 rdx,
17 rcx,
18 rbx,
19 rsi,
20 rdi,
21 rbp,
22 rsp,
23 r8,
24 r9,
25 r10,
26 r11,
27 r12,
28 r13,
29 r14,
30 r15,
31 rip,
32 xmm0,
33 xmm1,
34 xmm2,
35 xmm3,
36 xmm4,
37 xmm5,
38 xmm6,
39 xmm7,
40 xmm8,
41 xmm9,
42 xmm10,
43 xmm11,
44 xmm12,
45 xmm13,
46 xmm14,
47 xmm15,
48
49 pub const fp = Register.rbp;
50 pub const ip = Register.rip;
51 pub const sp = Register.rsp;
52 },
53 else => enum {},
6pub const RegisterContext = struct {
7 eh_frame: bool,
8 is_macho: bool,
549};
5510
11pub fn ipRegNum() u8 {
12 return switch (builtin.cpu.arch) {
13 .x86 => 8,
14 .x86_64 => 16,
15 .arm => error.InvalidRegister, // TODO
16 .aarch64 => error.InvalidRegister, // TODO
17
18 // const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
19 // const ip = switch (native_os) {
20 // .macos => @intCast(usize, ctx.mcontext.ss.pc),
21 // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]),
22 // .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr),
23 // else => @intCast(usize, ctx.mcontext.pc),
24 // };
25 // // x29 is the ABI-designated frame pointer
26 // const bp = switch (native_os) {
27 // .macos => @intCast(usize, ctx.mcontext.ss.fp),
28 // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]),
29 // .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]),
30 // else => @intCast(usize, ctx.mcontext.regs[29]),
31 // };
32 else => unreachable,
33 };
34}
35
36pub fn fpRegNum(reg_ctx: RegisterContext) u8 {
37 return switch (builtin.cpu.arch) {
38 // GCC on OS X did the opposite of ELF for these registers (only in .eh_frame), and that is now the convention for MachO
39 .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 4 else 5,
40 .x86_64 => 6,
41 .arm => error.InvalidRegister, // TODO
42 .aarch64 => error.InvalidRegister, // TODO
43
44 // const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
45 // const ip = switch (native_os) {
46 // .macos => @intCast(usize, ctx.mcontext.ss.pc),
47 // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]),
48 // .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr),
49 // else => @intCast(usize, ctx.mcontext.pc),
50 // };
51 // // x29 is the ABI-designated frame pointer
52 // const bp = switch (native_os) {
53 // .macos => @intCast(usize, ctx.mcontext.ss.fp),
54 // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]),
55 // .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]),
56 // else => @intCast(usize, ctx.mcontext.regs[29]),
57 // };
58 else => unreachable,
59 };
60}
61
62pub fn spRegNum(reg_ctx: RegisterContext) u8 {
63 return switch (builtin.cpu.arch) {
64 .x86 => if (reg_ctx.eh_frame and reg_ctx.is_macho) 5 else 4,
65 .x86_64 => 7,
66 .arm => error.InvalidRegister, // TODO
67 .aarch64 => error.InvalidRegister, // TODO
68
69 // const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
70 // const ip = switch (native_os) {
71 // .macos => @intCast(usize, ctx.mcontext.ss.pc),
72 // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.PC]),
73 // .freebsd => @intCast(usize, ctx.mcontext.gpregs.elr),
74 // else => @intCast(usize, ctx.mcontext.pc),
75 // };
76 // // x29 is the ABI-designated frame pointer
77 // const bp = switch (native_os) {
78 // .macos => @intCast(usize, ctx.mcontext.ss.fp),
79 // .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.FP]),
80 // .freebsd => @intCast(usize, ctx.mcontext.gpregs.x[os.REG.FP]),
81 // else => @intCast(usize, ctx.mcontext.regs[29]),
82 // };
83 else => unreachable,
84 };
85}
86
5687fn RegBytesReturnType(comptime ContextPtrType: type) type {
5788 const info = @typeInfo(ContextPtrType);
5889 if (info != .Pointer or info.Pointer.child != os.ucontext_t) {
......@@ -62,36 +93,132 @@ fn RegBytesReturnType(comptime ContextPtrType: type) type {
6293 return if (info.Pointer.is_const) return []const u8 else []u8;
6394}
6495
65/// Returns a slice containing the backing storage for `reg_number`
66pub fn regBytes(ucontext_ptr: anytype, reg_number: u8) !RegBytesReturnType(@TypeOf(ucontext_ptr)) {
96/// Returns a slice containing the backing storage for `reg_number`.
97///
98/// `reg_ctx` describes in what context the register number is used, as it can have different
99/// meanings depending on the DWARF container. It is only required when getting the stack or
100/// frame pointer register on some architectures.
101pub fn regBytes(ucontext_ptr: anytype, reg_number: u8, reg_ctx: ?RegisterContext) !RegBytesReturnType(@TypeOf(ucontext_ptr)) {
67102 var m = &ucontext_ptr.mcontext;
68103
69104 return switch (builtin.cpu.arch) {
105 .x86 => switch (reg_number) {
106 0 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EAX]),
107 1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ECX]),
108 2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDX]),
109 3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBX]),
110 4...5 => if (reg_ctx) |r| bytes: {
111 if (reg_number == 4) {
112 break :bytes if (r.eh_frame and r.is_macho)
113 mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBP])
114 else
115 mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESP]);
116 } else {
117 break :bytes if (r.eh_frame and r.is_macho)
118 mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESP])
119 else
120 mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBP]);
121 }
122 } else error.RegisterContextRequired,
123 6 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESI]),
124 7 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDI]),
125 8 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EIP]),
126 9 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EFL]),
127 10 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.CS]),
128 11 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.SS]),
129 12 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.DS]),
130 13 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ES]),
131 14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.FS]),
132 15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.GS]),
133 16...23 => error.InvalidRegister, // TODO: Support loading ST0-ST7 from mcontext.fpregs
134 // TODO: Map TRAPNO, ERR, UESP
135 32...39 => error.InvalidRegister, // TODO: Support loading XMM0-XMM7 from mcontext.fpregs
136 else => error.InvalidRegister,
137 },
70138 .x86_64 => switch (builtin.os.tag) {
71139 .linux, .netbsd, .solaris => switch (reg_number) {
72 0 => mem.asBytes(&m.gregs[os.REG.RAX]),
73 1 => mem.asBytes(&m.gregs[os.REG.RDX]),
74 2 => mem.asBytes(&m.gregs[os.REG.RCX]),
75 3 => mem.asBytes(&m.gregs[os.REG.RBX]),
76 4 => mem.asBytes(&m.gregs[os.REG.RSI]),
77 5 => mem.asBytes(&m.gregs[os.REG.RDI]),
78 6 => mem.asBytes(&m.gregs[os.REG.RBP]),
79 7 => mem.asBytes(&m.gregs[os.REG.RSP]),
80 8 => mem.asBytes(&m.gregs[os.REG.R8]),
81 9 => mem.asBytes(&m.gregs[os.REG.R9]),
82 10 => mem.asBytes(&m.gregs[os.REG.R10]),
83 11 => mem.asBytes(&m.gregs[os.REG.R11]),
84 12 => mem.asBytes(&m.gregs[os.REG.R12]),
85 13 => mem.asBytes(&m.gregs[os.REG.R13]),
86 14 => mem.asBytes(&m.gregs[os.REG.R14]),
87 15 => mem.asBytes(&m.gregs[os.REG.R15]),
88 16 => mem.asBytes(&m.gregs[os.REG.RIP]),
140 0 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RAX]),
141 1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RDX]),
142 2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RCX]),
143 3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RBX]),
144 4 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RSI]),
145 5 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RDI]),
146 6 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RBP]),
147 7 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RSP]),
148 8 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R8]),
149 9 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R9]),
150 10 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R10]),
151 11 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R11]),
152 12 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R12]),
153 13 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R13]),
154 14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R14]),
155 15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R15]),
156 16 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RIP]),
89157 17...32 => |i| mem.asBytes(&m.fpregs.xmm[i - 17]),
90158 else => error.InvalidRegister,
91159 },
92 //.freebsd => @intCast(usize, ctx.mcontext.rip),
93 //.openbsd => @intCast(usize, ctx.sc_rip),
94 //.macos => @intCast(usize, ctx.mcontext.ss.rip),
160 .freebsd => switch (reg_number) {
161 0 => mem.asBytes(&ucontext_ptr.mcontext.rax),
162 1 => mem.asBytes(&ucontext_ptr.mcontext.rdx),
163 2 => mem.asBytes(&ucontext_ptr.mcontext.rcx),
164 3 => mem.asBytes(&ucontext_ptr.mcontext.rbx),
165 4 => mem.asBytes(&ucontext_ptr.mcontext.rsi),
166 5 => mem.asBytes(&ucontext_ptr.mcontext.rdi),
167 6 => mem.asBytes(&ucontext_ptr.mcontext.rbp),
168 7 => mem.asBytes(&ucontext_ptr.mcontext.rsp),
169 8 => mem.asBytes(&ucontext_ptr.mcontext.r8),
170 9 => mem.asBytes(&ucontext_ptr.mcontext.r9),
171 10 => mem.asBytes(&ucontext_ptr.mcontext.r10),
172 11 => mem.asBytes(&ucontext_ptr.mcontext.r11),
173 12 => mem.asBytes(&ucontext_ptr.mcontext.r12),
174 13 => mem.asBytes(&ucontext_ptr.mcontext.r13),
175 14 => mem.asBytes(&ucontext_ptr.mcontext.r14),
176 15 => mem.asBytes(&ucontext_ptr.mcontext.r15),
177 16 => mem.asBytes(&ucontext_ptr.mcontext.rip),
178 // TODO: Extract xmm state from mcontext.fpstate?
179 else => error.InvalidRegister,
180 },
181 .openbsd => switch (reg_number) {
182 0 => mem.asBytes(&ucontext_ptr.sc_rax),
183 1 => mem.asBytes(&ucontext_ptr.sc_rdx),
184 2 => mem.asBytes(&ucontext_ptr.sc_rcx),
185 3 => mem.asBytes(&ucontext_ptr.sc_rbx),
186 4 => mem.asBytes(&ucontext_ptr.sc_rsi),
187 5 => mem.asBytes(&ucontext_ptr.sc_rdi),
188 6 => mem.asBytes(&ucontext_ptr.sc_rbp),
189 7 => mem.asBytes(&ucontext_ptr.sc_rsp),
190 8 => mem.asBytes(&ucontext_ptr.sc_r8),
191 9 => mem.asBytes(&ucontext_ptr.sc_r9),
192 10 => mem.asBytes(&ucontext_ptr.sc_r10),
193 11 => mem.asBytes(&ucontext_ptr.sc_r11),
194 12 => mem.asBytes(&ucontext_ptr.sc_r12),
195 13 => mem.asBytes(&ucontext_ptr.sc_r13),
196 14 => mem.asBytes(&ucontext_ptr.sc_r14),
197 15 => mem.asBytes(&ucontext_ptr.sc_r15),
198 16 => mem.asBytes(&ucontext_ptr.sc_rip),
199 // TODO: Extract xmm state from sc_fpstate?
200 else => error.InvalidRegister,
201 },
202 .macos => switch (reg_number) {
203 0 => mem.asBytes(&ucontext_ptr.mcontext.ss.rax),
204 1 => mem.asBytes(&ucontext_ptr.mcontext.ss.rdx),
205 2 => mem.asBytes(&ucontext_ptr.mcontext.ss.rcx),
206 3 => mem.asBytes(&ucontext_ptr.mcontext.ss.rbx),
207 4 => mem.asBytes(&ucontext_ptr.mcontext.ss.rsi),
208 5 => mem.asBytes(&ucontext_ptr.mcontext.ss.rdi),
209 6 => mem.asBytes(&ucontext_ptr.mcontext.ss.rbp),
210 7 => mem.asBytes(&ucontext_ptr.mcontext.ss.rsp),
211 8 => mem.asBytes(&ucontext_ptr.mcontext.ss.r8),
212 9 => mem.asBytes(&ucontext_ptr.mcontext.ss.r9),
213 10 => mem.asBytes(&ucontext_ptr.mcontext.ss.r10),
214 11 => mem.asBytes(&ucontext_ptr.mcontext.ss.r11),
215 12 => mem.asBytes(&ucontext_ptr.mcontext.ss.r12),
216 13 => mem.asBytes(&ucontext_ptr.mcontext.ss.r13),
217 14 => mem.asBytes(&ucontext_ptr.mcontext.ss.r14),
218 15 => mem.asBytes(&ucontext_ptr.mcontext.ss.r15),
219 16 => mem.asBytes(&ucontext_ptr.mcontext.ss.rip),
220 else => error.InvalidRegister,
221 },
95222 else => error.UnimplementedOs,
96223 },
97224 else => error.UnimplementedArch,
lib/std/dwarf/call_frame.zig+2-2
......@@ -304,9 +304,9 @@ pub const VirtualMachine = struct {
304304 } else return error.InvalidCFA;
305305 },
306306 .register => |register| {
307 const src = try abi.regBytes(&context.ucontext, register);
307 const src = try abi.regBytes(&context.ucontext, register, context.reg_ctx);
308308 if (src.len != out.len) return error.RegisterTypeMismatch;
309 @memcpy(out, try abi.regBytes(&context.ucontext, register));
309 @memcpy(out, try abi.regBytes(&context.ucontext, register, context.reg_ctx));
310310 },
311311 .expression => |expression| {
312312 // TODO