mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
dwarf: implement aarch64 default register rules
This commit is contained in:
parent
4421b14878
commit
253e6971ad
3 changed files with 38 additions and 38 deletions
|
|
@ -1740,21 +1740,7 @@ pub const DwarfInfo = struct {
|
||||||
context.reg_context.eh_frame = cie.version != 4;
|
context.reg_context.eh_frame = cie.version != 4;
|
||||||
context.reg_context.is_macho = di.is_macho;
|
context.reg_context.is_macho = di.is_macho;
|
||||||
|
|
||||||
if (comptime builtin.target.isDarwin()) {
|
|
||||||
std.debug.print(" state before:\n", .{});
|
|
||||||
std.debug.print(" cfa {?x}:\n", .{context.cfa});
|
|
||||||
for (context.thread_context.mcontext.ss.regs, 0..) |reg, i| {
|
|
||||||
std.debug.print(" {}:0x{x}\n", .{i, reg});
|
|
||||||
}
|
|
||||||
std.debug.print(" fp:0x{x}\n", .{context.thread_context.mcontext.ss.fp});
|
|
||||||
std.debug.print(" lr:0x{x}\n", .{context.thread_context.mcontext.ss.lr});
|
|
||||||
std.debug.print(" sp:0x{x}\n", .{context.thread_context.mcontext.ss.sp});
|
|
||||||
std.debug.print(" pc:0x{x}\n", .{context.thread_context.mcontext.ss.pc});
|
|
||||||
}
|
|
||||||
|
|
||||||
const row = try context.vm.runToNative(context.allocator, context.pc, cie, fde);
|
const row = try context.vm.runToNative(context.allocator, context.pc, cie, fde);
|
||||||
std.debug.print(" ran to 0x{x}\n", .{row.offset + fde.pc_begin});
|
|
||||||
|
|
||||||
context.cfa = switch (row.cfa.rule) {
|
context.cfa = switch (row.cfa.rule) {
|
||||||
.val_offset => |offset| blk: {
|
.val_offset => |offset| blk: {
|
||||||
const register = row.cfa.register orelse return error.InvalidCFARule;
|
const register = row.cfa.register orelse return error.InvalidCFARule;
|
||||||
|
|
@ -1789,47 +1775,48 @@ pub const DwarfInfo = struct {
|
||||||
|
|
||||||
const RegisterUpdate = struct {
|
const RegisterUpdate = struct {
|
||||||
// Backed by thread_context
|
// Backed by thread_context
|
||||||
old_value: []u8,
|
dest: []u8,
|
||||||
// Backed by arena
|
// Backed by arena
|
||||||
new_value: []const u8,
|
src: []const u8,
|
||||||
prev: ?*@This(),
|
prev: ?*@This(),
|
||||||
};
|
};
|
||||||
|
|
||||||
var update_tail: ?*RegisterUpdate = null;
|
var update_tail: ?*RegisterUpdate = null;
|
||||||
var has_next_ip = true;
|
var has_return_address= true;
|
||||||
for (context.vm.rowColumns(row)) |column| {
|
for (context.vm.rowColumns(row)) |column| {
|
||||||
if (column.register) |register| {
|
if (column.register) |register| {
|
||||||
if (register == cie.return_address_register) {
|
if (register == cie.return_address_register) {
|
||||||
has_next_ip = column.rule != .undefined;
|
has_return_address = column.rule != .undefined;
|
||||||
}
|
}
|
||||||
std.debug.print(" updated {}\n", .{register});
|
|
||||||
|
|
||||||
const old_value = try abi.regBytes(context.thread_context, register, context.reg_context);
|
const dest = try abi.regBytes(context.thread_context, register, context.reg_context);
|
||||||
const new_value = try update_allocator.alloc(u8, old_value.len);
|
const src = try update_allocator.alloc(u8, dest.len);
|
||||||
|
|
||||||
const prev = update_tail;
|
const prev = update_tail;
|
||||||
update_tail = try update_allocator.create(RegisterUpdate);
|
update_tail = try update_allocator.create(RegisterUpdate);
|
||||||
update_tail.?.* = .{
|
update_tail.?.* = .{
|
||||||
.old_value = old_value,
|
.dest = dest,
|
||||||
.new_value = new_value,
|
.src = src,
|
||||||
.prev = prev,
|
.prev = prev,
|
||||||
};
|
};
|
||||||
|
|
||||||
try column.resolveValue(
|
try column.resolveValue(
|
||||||
context,
|
context,
|
||||||
expression_context,
|
expression_context,
|
||||||
new_value,
|
src,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On all implemented architectures, the CFA is defined as being the previous frame's SP
|
||||||
(try abi.regValueNative(usize, context.thread_context, abi.spRegNum(context.reg_context), context.reg_context)).* = context.cfa.?;
|
(try abi.regValueNative(usize, context.thread_context, abi.spRegNum(context.reg_context), context.reg_context)).* = context.cfa.?;
|
||||||
|
|
||||||
while (update_tail) |tail| {
|
while (update_tail) |tail| {
|
||||||
@memcpy(tail.old_value, tail.new_value);
|
@memcpy(tail.dest, tail.src);
|
||||||
update_tail = tail.prev;
|
update_tail = tail.prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_next_ip) {
|
if (has_return_address) {
|
||||||
context.pc = abi.stripInstructionPtrAuthCode(mem.readIntSliceNative(usize, try abi.regBytes(
|
context.pc = abi.stripInstructionPtrAuthCode(mem.readIntSliceNative(usize, try abi.regBytes(
|
||||||
context.thread_context,
|
context.thread_context,
|
||||||
cie.return_address_register,
|
cie.return_address_register,
|
||||||
|
|
@ -1838,10 +1825,8 @@ pub const DwarfInfo = struct {
|
||||||
} else {
|
} else {
|
||||||
context.pc = 0;
|
context.pc = 0;
|
||||||
}
|
}
|
||||||
(try abi.regValueNative(usize, context.thread_context, abi.ipRegNum(), context.reg_context)).* = context.pc;
|
|
||||||
std.debug.print(" new context.pc: 0x{x}\n", .{context.pc});
|
|
||||||
|
|
||||||
(try abi.regValueNative(usize, context.thread_context, abi.spRegNum(context.reg_context), context.reg_context)).* = context.cfa.?;
|
(try abi.regValueNative(usize, context.thread_context, abi.ipRegNum(), context.reg_context)).* = context.pc;
|
||||||
|
|
||||||
// The call instruction will have pushed the address of the instruction that follows the call as the return address
|
// 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`. By subtracting one,
|
// However, this return address may be past the end of the function if the caller was `noreturn`. By subtracting one,
|
||||||
|
|
|
||||||
|
|
@ -367,12 +367,21 @@ pub fn regBytes(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the ABI-defined default value this register has in the unwinding table
|
/// Returns the ABI-defined default value this register has in the unwinding table
|
||||||
/// before running any of the CIE instructions. The DWARF spec defines these values
|
/// before running any of the CIE instructions. The DWARF spec defines these as having
|
||||||
/// to be undefined, but allows ABI authors to override that default.
|
/// the .undefined rule by default, but allows ABI authors to override that.
|
||||||
pub fn getRegDefaultValue(reg_number: u8, out: []u8) void {
|
pub fn getRegDefaultValue(reg_number: u8, context: *std.dwarf.UnwindContext, out: []u8) !void {
|
||||||
|
switch (builtin.cpu.arch) {
|
||||||
|
.aarch64 => {
|
||||||
|
// Callee-saved registers are initialized as if they had the .same_value rule
|
||||||
|
if (reg_number >= 19 and reg_number <= 28) {
|
||||||
|
const src = try regBytes(context.thread_context, reg_number, context.reg_context);
|
||||||
|
if (src.len != out.len) return error.RegisterSizeMismatch;
|
||||||
|
@memcpy(out, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
// Implement any ABI-specific rules here
|
|
||||||
|
|
||||||
_ = reg_number;
|
|
||||||
@memset(out, undefined);
|
@memset(out, undefined);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -295,12 +295,18 @@ pub const VirtualMachine = struct {
|
||||||
switch (self.rule) {
|
switch (self.rule) {
|
||||||
.default => {
|
.default => {
|
||||||
const register = self.register orelse return error.InvalidRegister;
|
const register = self.register orelse return error.InvalidRegister;
|
||||||
abi.getRegDefaultValue(register, out);
|
try abi.getRegDefaultValue(register, context, out);
|
||||||
},
|
},
|
||||||
.undefined => {
|
.undefined => {
|
||||||
@memset(out, undefined);
|
@memset(out, undefined);
|
||||||
},
|
},
|
||||||
.same_value => {},
|
.same_value => {
|
||||||
|
// TODO: This copy could be eliminated if callers always copy the state then call this function to update it
|
||||||
|
const register = self.register orelse return error.InvalidRegister;
|
||||||
|
const src = try abi.regBytes(context.thread_context, register, context.reg_context);
|
||||||
|
if (src.len != out.len) return error.RegisterSizeMismatch;
|
||||||
|
@memcpy(out, src);
|
||||||
|
},
|
||||||
.offset => |offset| {
|
.offset => |offset| {
|
||||||
if (context.cfa) |cfa| {
|
if (context.cfa) |cfa| {
|
||||||
const addr = try applyOffset(cfa, offset);
|
const addr = try applyOffset(cfa, offset);
|
||||||
|
|
@ -316,7 +322,7 @@ pub const VirtualMachine = struct {
|
||||||
},
|
},
|
||||||
.register => |register| {
|
.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;
|
if (src.len != out.len) return error.RegisterSizeMismatch;
|
||||||
@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| {
|
.expression => |expression| {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue