@@ -175,7 +175,6 @@ pub fn next(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheEn
175
175
176
176
fn nextInner (unwinder : * SelfUnwinder , gpa : Allocator , cache_entry : * const CacheEntry ) ! usize {
177
177
const format = cache_entry .cie .format ;
178
- const return_address_register = cache_entry .cie .return_address_register ;
179
178
180
179
const cfa = switch (cache_entry .cfa_rule ) {
181
180
.none = > return error .InvalidDebugInfo ,
@@ -202,23 +201,15 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
202
201
},
203
202
};
204
203
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
-
216
204
// Create a copy of the CPU state, to which we will apply the new rules.
217
205
var new_cpu_state = unwinder .cpu_state ;
218
206
219
207
// On all implemented architectures, the CFA is defined to be the previous frame's SP
220
208
(try regNative (& new_cpu_state , sp_reg_num )).* = cfa ;
221
209
210
+ const return_address_register = cache_entry .cie .return_address_register ;
211
+ var has_return_address = true ;
212
+
222
213
const rules_len = cache_entry .num_rules ;
223
214
for (cache_entry .rules_regs [0.. rules_len ], cache_entry .rules [0.. rules_len ]) | register , rule | {
224
215
const new_val : union (enum ) {
@@ -228,13 +219,14 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
228
219
bytes : []const u8 ,
229
220
} = switch (rule ) {
230
221
.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 ;
238
230
},
239
231
.undefined = > .undefined ,
240
232
.same_value = > .same ,
@@ -273,6 +265,12 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
273
265
.undefined = > {
274
266
const dest = try new_cpu_state .dwarfRegisterBytes (@intCast (register ));
275
267
@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
+ }
276
274
},
277
275
.val = > | val | {
278
276
const dest = try new_cpu_state .dwarfRegisterBytes (@intCast (register ));
@@ -286,15 +284,12 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
286
284
@memcpy (dest , src );
287
285
},
288
286
}
289
- if (register == return_address_register ) {
290
- has_return_address = new_val != .undefined ;
291
- }
292
287
}
293
288
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 ;
298
293
299
294
(try regNative (& new_cpu_state , ip_reg_num )).* = return_address ;
300
295
0 commit comments