mirror of
https://github.com/ziglang/zig.git
synced 2026-02-15 22:09:49 +00:00
Merge pull request #25496 from alexrp/std-debug-reg-access
`std.debug`: be more resilient in the face of unsupported registers
This commit is contained in:
commit
b19ba7df3b
@ -15,14 +15,14 @@ cfi_vm: Dwarf.Unwind.VirtualMachine,
|
||||
expr_vm: Dwarf.expression.StackMachine(.{ .call_frame_context = true }),
|
||||
|
||||
pub const CacheEntry = struct {
|
||||
const max_regs = 32;
|
||||
const max_rules = 32;
|
||||
|
||||
pc: usize,
|
||||
cie: *const Dwarf.Unwind.CommonInformationEntry,
|
||||
cfa_rule: Dwarf.Unwind.VirtualMachine.CfaRule,
|
||||
num_rules: u8,
|
||||
rules_regs: [max_regs]u16,
|
||||
rules: [max_regs]Dwarf.Unwind.VirtualMachine.RegisterRule,
|
||||
rules_regs: [max_rules]u16,
|
||||
rules: [max_rules]Dwarf.Unwind.VirtualMachine.RegisterRule,
|
||||
|
||||
pub fn find(entries: []const CacheEntry, pc: usize) ?*const CacheEntry {
|
||||
assert(pc != 0);
|
||||
@ -108,22 +108,30 @@ pub fn computeRules(
|
||||
|
||||
unwinder.cfi_vm.reset();
|
||||
const row = try unwinder.cfi_vm.runTo(gpa, pc_vaddr, cie, &fde, @sizeOf(usize), native_endian);
|
||||
const cols = unwinder.cfi_vm.rowColumns(&row);
|
||||
|
||||
if (cols.len > CacheEntry.max_regs) return error.UnsupportedDebugInfo;
|
||||
|
||||
var entry: CacheEntry = .{
|
||||
.pc = unwinder.pc,
|
||||
.cie = cie,
|
||||
.cfa_rule = row.cfa,
|
||||
.num_rules = @intCast(cols.len),
|
||||
.num_rules = undefined,
|
||||
.rules_regs = undefined,
|
||||
.rules = undefined,
|
||||
};
|
||||
for (cols, 0..) |col, i| {
|
||||
var i: usize = 0;
|
||||
for (unwinder.cfi_vm.rowColumns(&row)) |col| {
|
||||
if (i == CacheEntry.max_rules) return error.UnsupportedDebugInfo;
|
||||
|
||||
_ = unwinder.cpu_state.dwarfRegisterBytes(col.register) catch |err| switch (err) {
|
||||
// Reading an unsupported register during unwinding will result in an error, so there is
|
||||
// no point wasting a rule slot in the cache entry for it.
|
||||
error.UnsupportedRegister => continue,
|
||||
error.InvalidRegister => return error.InvalidDebugInfo,
|
||||
};
|
||||
entry.rules_regs[i] = col.register;
|
||||
entry.rules[i] = col.rule;
|
||||
i += 1;
|
||||
}
|
||||
entry.num_rules = @intCast(i);
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
@ -401,21 +401,11 @@ fn unwindFrameInner(si: *SelfInfo, gpa: Allocator, context: *UnwindContext) !usi
|
||||
}
|
||||
}
|
||||
|
||||
inline for (@typeInfo(@TypeOf(frame.d_reg_pairs)).@"struct".fields, 0..) |field, i| {
|
||||
if (@field(frame.d_reg_pairs, field.name) != 0) {
|
||||
// Only the lower half of the 128-bit V registers are restored during unwinding
|
||||
{
|
||||
const dest: *align(1) usize = @ptrCast(try context.cpu_state.dwarfRegisterBytes(64 + 8 + i));
|
||||
dest.* = @as(*const usize, @ptrFromInt(reg_addr)).*;
|
||||
}
|
||||
reg_addr += @sizeOf(usize);
|
||||
{
|
||||
const dest: *align(1) usize = @ptrCast(try context.cpu_state.dwarfRegisterBytes(64 + 9 + i));
|
||||
dest.* = @as(*const usize, @ptrFromInt(reg_addr)).*;
|
||||
}
|
||||
reg_addr += @sizeOf(usize);
|
||||
}
|
||||
}
|
||||
// We intentionally skip restoring `frame.d_reg_pairs`; we know we don't support
|
||||
// vector registers in the AArch64 `cpu_context` anyway, so there's no reason to
|
||||
// fail a legitimate unwind just because we're asked to restore the registers here.
|
||||
// If some weird/broken unwind info tells us to read them later, we will fail then.
|
||||
reg_addr += 16 * @as(usize, @popCount(@as(u4, @bitCast(frame.d_reg_pairs))));
|
||||
|
||||
const new_ip = @as(*const usize, @ptrFromInt(ip_ptr)).*;
|
||||
const new_fp = @as(*const usize, @ptrFromInt(fp)).*;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user