authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-10-07 09:28:43+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-10-07 09:28:43+02:00
logc23a5ccd19f08d485820a1d5deea04a6e10fe7bb
treea474edb89937dc46cb5639b3ed8619409f831369
parent6893e7feeed8b528d0a03d3491f4254bbcf5c7ce
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

std.debug.Dwarf.SelfUnwinder: skip caching rules for unsupported registers

For unwinding purposes, we don't care about unsupported registers. Yet because we added these rules to the cache entry, we'd later try to evaluate them and thus fail the unwind attempt for no good reason. They'd also take up cache rule slots that would be better spent on actually relevant registers. Note that any attempt to read unsupported registers during unwinding will still fail the unwind attempt as expected.

1 files changed, 16 insertions(+), 8 deletions(-)

lib/std/debug/Dwarf/SelfUnwinder.zig+16-8
......@@ -15,14 +15,14 @@ cfi_vm: Dwarf.Unwind.VirtualMachine,
1515expr_vm: Dwarf.expression.StackMachine(.{ .call_frame_context = true }),
1616
1717pub 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