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,...@@ -15,14 +15,14 @@ cfi_vm: Dwarf.Unwind.VirtualMachine,
15expr_vm: Dwarf.expression.StackMachine(.{ .call_frame_context = true }),15expr_vm: Dwarf.expression.StackMachine(.{ .call_frame_context = true }),
1616
17pub const CacheEntry = struct {17pub const CacheEntry = struct {
18 const max_regs = 32;18 const max_rules = 32;
1919
20 pc: usize,20 pc: usize,
21 cie: *const Dwarf.Unwind.CommonInformationEntry,21 cie: *const Dwarf.Unwind.CommonInformationEntry,
22 cfa_rule: Dwarf.Unwind.VirtualMachine.CfaRule,22 cfa_rule: Dwarf.Unwind.VirtualMachine.CfaRule,
23 num_rules: u8,23 num_rules: u8,
24 rules_regs: [max_regs]u16,24 rules_regs: [max_rules]u16,
25 rules: [max_regs]Dwarf.Unwind.VirtualMachine.RegisterRule,25 rules: [max_rules]Dwarf.Unwind.VirtualMachine.RegisterRule,
2626
27 pub fn find(entries: []const CacheEntry, pc: usize) ?*const CacheEntry {27 pub fn find(entries: []const CacheEntry, pc: usize) ?*const CacheEntry {
28 assert(pc != 0);28 assert(pc != 0);
...@@ -108,22 +108,30 @@ pub fn computeRules(...@@ -108,22 +108,30 @@ pub fn computeRules(
108108
109 unwinder.cfi_vm.reset();109 unwinder.cfi_vm.reset();
110 const row = try unwinder.cfi_vm.runTo(gpa, pc_vaddr, cie, &fde, @sizeOf(usize), native_endian);110 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
115 var entry: CacheEntry = .{112 var entry: CacheEntry = .{
116 .pc = unwinder.pc,113 .pc = unwinder.pc,
117 .cie = cie,114 .cie = cie,
118 .cfa_rule = row.cfa,115 .cfa_rule = row.cfa,
119 .num_rules = @intCast(cols.len),116 .num_rules = undefined,
120 .rules_regs = undefined,117 .rules_regs = undefined,
121 .rules = undefined,118 .rules = undefined,
122 };119 };
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 };
124 entry.rules_regs[i] = col.register;130 entry.rules_regs[i] = col.register;
125 entry.rules[i] = col.rule;131 entry.rules[i] = col.rule;
132 i += 1;
126 }133 }
134 entry.num_rules = @intCast(i);
127 return entry;135 return entry;
128}136}
129137