Skip to content

Commit b19ba7d

Browse files
authored
Merge pull request #25496 from alexrp/std-debug-reg-access
`std.debug`: be more resilient in the face of unsupported registers
2 parents b824ca8 + a06db28 commit b19ba7d

File tree

2 files changed

+21
-23
lines changed

2 files changed

+21
-23
lines changed

lib/std/debug/Dwarf/SelfUnwinder.zig

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ cfi_vm: Dwarf.Unwind.VirtualMachine,
1515
expr_vm: Dwarf.expression.StackMachine(.{ .call_frame_context = true }),
1616

1717
pub const CacheEntry = struct {
18-
const max_regs = 32;
18+
const max_rules = 32;
1919

2020
pc: usize,
2121
cie: *const Dwarf.Unwind.CommonInformationEntry,
2222
cfa_rule: Dwarf.Unwind.VirtualMachine.CfaRule,
2323
num_rules: u8,
24-
rules_regs: [max_regs]u16,
25-
rules: [max_regs]Dwarf.Unwind.VirtualMachine.RegisterRule,
24+
rules_regs: [max_rules]u16,
25+
rules: [max_rules]Dwarf.Unwind.VirtualMachine.RegisterRule,
2626

2727
pub fn find(entries: []const CacheEntry, pc: usize) ?*const CacheEntry {
2828
assert(pc != 0);
@@ -108,22 +108,30 @@ pub fn computeRules(
108108

109109
unwinder.cfi_vm.reset();
110110
const row = try unwinder.cfi_vm.runTo(gpa, pc_vaddr, cie, &fde, @sizeOf(usize), native_endian);
111-
const cols = unwinder.cfi_vm.rowColumns(&row);
112-
113-
if (cols.len > CacheEntry.max_regs) return error.UnsupportedDebugInfo;
114111

115112
var entry: CacheEntry = .{
116113
.pc = unwinder.pc,
117114
.cie = cie,
118115
.cfa_rule = row.cfa,
119-
.num_rules = @intCast(cols.len),
116+
.num_rules = undefined,
120117
.rules_regs = undefined,
121118
.rules = undefined,
122119
};
123-
for (cols, 0..) |col, i| {
120+
var i: usize = 0;
121+
for (unwinder.cfi_vm.rowColumns(&row)) |col| {
122+
if (i == CacheEntry.max_rules) return error.UnsupportedDebugInfo;
123+
124+
_ = unwinder.cpu_state.dwarfRegisterBytes(col.register) catch |err| switch (err) {
125+
// Reading an unsupported register during unwinding will result in an error, so there is
126+
// no point wasting a rule slot in the cache entry for it.
127+
error.UnsupportedRegister => continue,
128+
error.InvalidRegister => return error.InvalidDebugInfo,
129+
};
124130
entry.rules_regs[i] = col.register;
125131
entry.rules[i] = col.rule;
132+
i += 1;
126133
}
134+
entry.num_rules = @intCast(i);
127135
return entry;
128136
}
129137

lib/std/debug/SelfInfo/MachO.zig

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -401,21 +401,11 @@ fn unwindFrameInner(si: *SelfInfo, gpa: Allocator, context: *UnwindContext) !usi
401401
}
402402
}
403403

404-
inline for (@typeInfo(@TypeOf(frame.d_reg_pairs)).@"struct".fields, 0..) |field, i| {
405-
if (@field(frame.d_reg_pairs, field.name) != 0) {
406-
// Only the lower half of the 128-bit V registers are restored during unwinding
407-
{
408-
const dest: *align(1) usize = @ptrCast(try context.cpu_state.dwarfRegisterBytes(64 + 8 + i));
409-
dest.* = @as(*const usize, @ptrFromInt(reg_addr)).*;
410-
}
411-
reg_addr += @sizeOf(usize);
412-
{
413-
const dest: *align(1) usize = @ptrCast(try context.cpu_state.dwarfRegisterBytes(64 + 9 + i));
414-
dest.* = @as(*const usize, @ptrFromInt(reg_addr)).*;
415-
}
416-
reg_addr += @sizeOf(usize);
417-
}
418-
}
404+
// We intentionally skip restoring `frame.d_reg_pairs`; we know we don't support
405+
// vector registers in the AArch64 `cpu_context` anyway, so there's no reason to
406+
// fail a legitimate unwind just because we're asked to restore the registers here.
407+
// If some weird/broken unwind info tells us to read them later, we will fail then.
408+
reg_addr += 16 * @as(usize, @popCount(@as(u4, @bitCast(frame.d_reg_pairs))));
419409

420410
const new_ip = @as(*const usize, @ptrFromInt(ip_ptr)).*;
421411
const new_fp = @as(*const usize, @ptrFromInt(fp)).*;

0 commit comments

Comments
 (0)