authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-18 20:14:42-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:16-04:00
log253e6971ad77a9665348fd6a2085b2ffd8c84219
treeaf68ece38de03bc42a96a0c98ea3176530deecf5
parent4421b14878eb722da8a57069b2152f7b43ba7ffc

dwarf: implement aarch64 default register rules


3 files changed, 38 insertions(+), 38 deletions(-)

lib/std/dwarf.zig+14-29
...@@ -1740,21 +1740,7 @@ pub const DwarfInfo = struct {...@@ -1740,21 +1740,7 @@ pub const DwarfInfo = struct {
1740 context.reg_context.eh_frame = cie.version != 4;1740 context.reg_context.eh_frame = cie.version != 4;
1741 context.reg_context.is_macho = di.is_macho;1741 context.reg_context.is_macho = di.is_macho;
17421742
1743 if (comptime builtin.target.isDarwin()) {
1744 std.debug.print(" state before:\n", .{});
1745 std.debug.print(" cfa {?x}:\n", .{context.cfa});
1746 for (context.thread_context.mcontext.ss.regs, 0..) |reg, i| {
1747 std.debug.print(" {}:0x{x}\n", .{i, reg});
1748 }
1749 std.debug.print(" fp:0x{x}\n", .{context.thread_context.mcontext.ss.fp});
1750 std.debug.print(" lr:0x{x}\n", .{context.thread_context.mcontext.ss.lr});
1751 std.debug.print(" sp:0x{x}\n", .{context.thread_context.mcontext.ss.sp});
1752 std.debug.print(" pc:0x{x}\n", .{context.thread_context.mcontext.ss.pc});
1753 }
1754
1755 const row = try context.vm.runToNative(context.allocator, context.pc, cie, fde);1743 const row = try context.vm.runToNative(context.allocator, context.pc, cie, fde);
1756 std.debug.print(" ran to 0x{x}\n", .{row.offset + fde.pc_begin});
1757
1758 context.cfa = switch (row.cfa.rule) {1744 context.cfa = switch (row.cfa.rule) {
1759 .val_offset => |offset| blk: {1745 .val_offset => |offset| blk: {
1760 const register = row.cfa.register orelse return error.InvalidCFARule;1746 const register = row.cfa.register orelse return error.InvalidCFARule;
...@@ -1789,47 +1775,48 @@ pub const DwarfInfo = struct {...@@ -1789,47 +1775,48 @@ pub const DwarfInfo = struct {
17891775
1790 const RegisterUpdate = struct {1776 const RegisterUpdate = struct {
1791 // Backed by thread_context1777 // Backed by thread_context
1792 old_value: []u8,1778 dest: []u8,
1793 // Backed by arena1779 // Backed by arena
1794 new_value: []const u8,1780 src: []const u8,
1795 prev: ?*@This(),1781 prev: ?*@This(),
1796 };1782 };
17971783
1798 var update_tail: ?*RegisterUpdate = null;1784 var update_tail: ?*RegisterUpdate = null;
1799 var has_next_ip = true;1785 var has_return_address= true;
1800 for (context.vm.rowColumns(row)) |column| {1786 for (context.vm.rowColumns(row)) |column| {
1801 if (column.register) |register| {1787 if (column.register) |register| {
1802 if (register == cie.return_address_register) {1788 if (register == cie.return_address_register) {
1803 has_next_ip = column.rule != .undefined;1789 has_return_address = column.rule != .undefined;
1804 }1790 }
1805 std.debug.print(" updated {}\n", .{register});
18061791
1807 const old_value = try abi.regBytes(context.thread_context, register, context.reg_context);1792 const dest = try abi.regBytes(context.thread_context, register, context.reg_context);
1808 const new_value = try update_allocator.alloc(u8, old_value.len);1793 const src = try update_allocator.alloc(u8, dest.len);
18091794
1810 const prev = update_tail;1795 const prev = update_tail;
1811 update_tail = try update_allocator.create(RegisterUpdate);1796 update_tail = try update_allocator.create(RegisterUpdate);
1812 update_tail.?.* = .{1797 update_tail.?.* = .{
1813 .old_value = old_value,1798 .dest = dest,
1814 .new_value = new_value,1799 .src = src,
1815 .prev = prev,1800 .prev = prev,
1816 };1801 };
18171802
1818 try column.resolveValue(1803 try column.resolveValue(
1819 context,1804 context,
1820 expression_context,1805 expression_context,
1821 new_value,1806 src,
1822 );1807 );
1823 }1808 }
1824 }1809 }
18251810
1811 // On all implemented architectures, the CFA is defined as being the previous frame's SP
1826 (try abi.regValueNative(usize, context.thread_context, abi.spRegNum(context.reg_context), context.reg_context)).* = context.cfa.?;1812 (try abi.regValueNative(usize, context.thread_context, abi.spRegNum(context.reg_context), context.reg_context)).* = context.cfa.?;
1813
1827 while (update_tail) |tail| {1814 while (update_tail) |tail| {
1828 @memcpy(tail.old_value, tail.new_value);1815 @memcpy(tail.dest, tail.src);
1829 update_tail = tail.prev;1816 update_tail = tail.prev;
1830 }1817 }
18311818
1832 if (has_next_ip) {1819 if (has_return_address) {
1833 context.pc = abi.stripInstructionPtrAuthCode(mem.readIntSliceNative(usize, try abi.regBytes(1820 context.pc = abi.stripInstructionPtrAuthCode(mem.readIntSliceNative(usize, try abi.regBytes(
1834 context.thread_context,1821 context.thread_context,
1835 cie.return_address_register,1822 cie.return_address_register,
...@@ -1838,10 +1825,8 @@ pub const DwarfInfo = struct {...@@ -1838,10 +1825,8 @@ pub const DwarfInfo = struct {
1838 } else {1825 } else {
1839 context.pc = 0;1826 context.pc = 0;
1840 }1827 }
1841 (try abi.regValueNative(usize, context.thread_context, abi.ipRegNum(), context.reg_context)).* = context.pc;
1842 std.debug.print(" new context.pc: 0x{x}\n", .{context.pc});
18431828
1844 (try abi.regValueNative(usize, context.thread_context, abi.spRegNum(context.reg_context), context.reg_context)).* = context.cfa.?;1829 (try abi.regValueNative(usize, context.thread_context, abi.ipRegNum(), context.reg_context)).* = context.pc;
18451830
1846 // The call instruction will have pushed the address of the instruction that follows the call as the return address1831 // The call instruction will have pushed the address of the instruction that follows the call as the return address
1847 // However, this return address may be past the end of the function if the caller was `noreturn`. By subtracting one,1832 // However, this return address may be past the end of the function if the caller was `noreturn`. By subtracting one,
lib/std/dwarf/abi.zig+15-6
...@@ -367,12 +367,21 @@ pub fn regBytes(...@@ -367,12 +367,21 @@ pub fn regBytes(
367}367}
368368
369/// Returns the ABI-defined default value this register has in the unwinding table369/// Returns the ABI-defined default value this register has in the unwinding table
370/// before running any of the CIE instructions. The DWARF spec defines these values370/// before running any of the CIE instructions. The DWARF spec defines these as having
371/// to be undefined, but allows ABI authors to override that default.371/// the .undefined rule by default, but allows ABI authors to override that.
372pub fn getRegDefaultValue(reg_number: u8, out: []u8) void {372pub fn getRegDefaultValue(reg_number: u8, context: *std.dwarf.UnwindContext, out: []u8) !void {
373373 switch (builtin.cpu.arch) {
374 // Implement any ABI-specific rules here374 .aarch64 => {
375 // Callee-saved registers are initialized as if they had the .same_value rule
376 if (reg_number >= 19 and reg_number <= 28) {
377 const src = try regBytes(context.thread_context, reg_number, context.reg_context);
378 if (src.len != out.len) return error.RegisterSizeMismatch;
379 @memcpy(out, src);
380 return;
381 }
382 },
383 else => {},
384 }
375385
376 _ = reg_number;
377 @memset(out, undefined);386 @memset(out, undefined);
378}387}
lib/std/dwarf/call_frame.zig+9-3
...@@ -295,12 +295,18 @@ pub const VirtualMachine = struct {...@@ -295,12 +295,18 @@ pub const VirtualMachine = struct {
295 switch (self.rule) {295 switch (self.rule) {
296 .default => {296 .default => {
297 const register = self.register orelse return error.InvalidRegister;297 const register = self.register orelse return error.InvalidRegister;
298 abi.getRegDefaultValue(register, out);298 try abi.getRegDefaultValue(register, context, out);
299 },299 },
300 .undefined => {300 .undefined => {
301 @memset(out, undefined);301 @memset(out, undefined);
302 },302 },
303 .same_value => {},303 .same_value => {
304 // TODO: This copy could be eliminated if callers always copy the state then call this function to update it
305 const register = self.register orelse return error.InvalidRegister;
306 const src = try abi.regBytes(context.thread_context, register, context.reg_context);
307 if (src.len != out.len) return error.RegisterSizeMismatch;
308 @memcpy(out, src);
309 },
304 .offset => |offset| {310 .offset => |offset| {
305 if (context.cfa) |cfa| {311 if (context.cfa) |cfa| {
306 const addr = try applyOffset(cfa, offset);312 const addr = try applyOffset(cfa, offset);
...@@ -316,7 +322,7 @@ pub const VirtualMachine = struct {...@@ -316,7 +322,7 @@ pub const VirtualMachine = struct {
316 },322 },
317 .register => |register| {323 .register => |register| {
318 const src = try abi.regBytes(context.thread_context, register, context.reg_context);324 const src = try abi.regBytes(context.thread_context, register, context.reg_context);
319 if (src.len != out.len) return error.RegisterTypeMismatch;325 if (src.len != out.len) return error.RegisterSizeMismatch;
320 @memcpy(out, try abi.regBytes(context.thread_context, register, context.reg_context));326 @memcpy(out, try abi.regBytes(context.thread_context, register, context.reg_context));
321 },327 },
322 .expression => |expression| {328 .expression => |expression| {