@@ -175,7 +175,6 @@ pub fn next(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheEn
175175
176176fn nextInner (unwinder : * SelfUnwinder , gpa : Allocator , cache_entry : * const CacheEntry ) ! usize {
177177 const format = cache_entry .cie .format ;
178- const return_address_register = cache_entry .cie .return_address_register ;
179178
180179 const cfa = switch (cache_entry .cfa_rule ) {
181180 .none = > return error .InvalidDebugInfo ,
@@ -202,23 +201,15 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
202201 },
203202 };
204203
205- // If unspecified, we'll use the default rule for the return address register, which is
206- // typically equivalent to `.undefined` (meaning there is no return address), but may be
207- // overriden by ABIs.
208- var has_return_address : bool = switch (builtin .cpu .arch ) {
209- // DWARF for the Arm 64-bit Architecture (AArch64) §4.3, p1
210- .aarch64 , .aarch64_be = > return_address_register >= 19 and return_address_register <= 28 ,
211- // ELF ABI s390x Supplement §1.6.4
212- .s390x = > return_address_register >= 6 and return_address_register <= 15 ,
213- else = > false ,
214- };
215-
216204 // Create a copy of the CPU state, to which we will apply the new rules.
217205 var new_cpu_state = unwinder .cpu_state ;
218206
219207 // On all implemented architectures, the CFA is defined to be the previous frame's SP
220208 (try regNative (& new_cpu_state , sp_reg_num )).* = cfa ;
221209
210+ const return_address_register = cache_entry .cie .return_address_register ;
211+ var has_return_address = true ;
212+
222213 const rules_len = cache_entry .num_rules ;
223214 for (cache_entry .rules_regs [0.. rules_len ], cache_entry .rules [0.. rules_len ]) | register , rule | {
224215 const new_val : union (enum ) {
@@ -228,13 +219,14 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
228219 bytes : []const u8 ,
229220 } = switch (rule ) {
230221 .default = > val : {
231- // The default rule is typically equivalent to `.undefined`, but ABIs may override it.
232- switch (builtin .target .cpu .arch ) {
233- .aarch64 , .aarch64_be = > if (register >= 19 and register <= 28 ) break :val .same ,
234- .s390x = > if (register >= 6 and register <= 15 ) break :val .same ,
235- else = > {},
236- }
237- break :val .undefined ;
222+ // The way things are supposed to work is that `.undefined` is the default rule
223+ // unless an ABI says otherwise (e.g. aarch64, s390x).
224+ //
225+ // Unfortunately, at some point, a decision was made to have libgcc's unwinder
226+ // assume `.same` as the default for all registers. Compilers then started depending
227+ // on this, and the practice was carried forward to LLVM's libunwind and some of its
228+ // backends.
229+ break :val .same ;
238230 },
239231 .undefined = > .undefined ,
240232 .same_value = > .same ,
@@ -273,6 +265,12 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
273265 .undefined = > {
274266 const dest = try new_cpu_state .dwarfRegisterBytes (@intCast (register ));
275267 @memset (dest , undefined );
268+
269+ // If the return address register is explicitly set to `.undefined`, it means that
270+ // there are no more frames to unwind.
271+ if (register == return_address_register ) {
272+ has_return_address = false ;
273+ }
276274 },
277275 .val = > | val | {
278276 const dest = try new_cpu_state .dwarfRegisterBytes (@intCast (register ));
@@ -286,15 +284,12 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
286284 @memcpy (dest , src );
287285 },
288286 }
289- if (register == return_address_register ) {
290- has_return_address = new_val != .undefined ;
291- }
292287 }
293288
294- const return_address : usize = if (has_return_address ) pc : {
295- const raw_ptr = try regNative (& new_cpu_state , return_address_register );
296- break : pc stripInstructionPtrAuthCode ( raw_ptr .* );
297- } else 0 ;
289+ const return_address = if (has_return_address )
290+ stripInstructionPtrAuthCode (( try regNative (& new_cpu_state , return_address_register )) .* )
291+ else
292+ 0 ;
298293
299294 (try regNative (& new_cpu_state , ip_reg_num )).* = return_address ;
300295
0 commit comments