authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-10-08 03:00:48+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-10-08 03:00:48+02:00
logb19ba7df3b59755a2808b2c2854ef4a029309ce4
tree49eaddec505406a2c5e70a698aeddb5c299dc15c
parentb824ca8494f24b92fb5f84eea64807678315eae3
parenta06db282c75dba5fa0a2859088840a24d04c7c7f
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #25496 from alexrp/std-debug-reg-access

`std.debug`: be more resilient in the face of unsupported registers

2 files changed, 21 insertions(+), 23 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
lib/std/debug/SelfInfo/MachO.zig+5-15
...@@ -401,21 +401,11 @@ fn unwindFrameInner(si: *SelfInfo, gpa: Allocator, context: *UnwindContext) !usi...@@ -401,21 +401,11 @@ fn unwindFrameInner(si: *SelfInfo, gpa: Allocator, context: *UnwindContext) !usi
401 }401 }
402 }402 }
403403
404 inline for (@typeInfo(@TypeOf(frame.d_reg_pairs)).@"struct".fields, 0..) |field, i| {404 // We intentionally skip restoring `frame.d_reg_pairs`; we know we don't support
405 if (@field(frame.d_reg_pairs, field.name) != 0) {405 // vector registers in the AArch64 `cpu_context` anyway, so there's no reason to
406 // Only the lower half of the 128-bit V registers are restored during unwinding406 // fail a legitimate unwind just because we're asked to restore the registers here.
407 {407 // If some weird/broken unwind info tells us to read them later, we will fail then.
408 const dest: *align(1) usize = @ptrCast(try context.cpu_state.dwarfRegisterBytes(64 + 8 + i));408 reg_addr += 16 * @as(usize, @popCount(@as(u4, @bitCast(frame.d_reg_pairs))));
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 }
419409
420 const new_ip = @as(*const usize, @ptrFromInt(ip_ptr)).*;410 const new_ip = @as(*const usize, @ptrFromInt(ip_ptr)).*;
421 const new_fp = @as(*const usize, @ptrFromInt(fp)).*;411 const new_fp = @as(*const usize, @ptrFromInt(fp)).*;