mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 00:08:56 +00:00
std.debug.Dwarf.SelfUnwinder: assume same-value rule by default for all columns
This fixes leaf function unwinding, presumably among other things.
This commit is contained in:
parent
f010a31319
commit
9aeabad519
@ -175,7 +175,6 @@ pub fn next(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheEn
|
||||
|
||||
fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheEntry) !usize {
|
||||
const format = cache_entry.cie.format;
|
||||
const return_address_register = cache_entry.cie.return_address_register;
|
||||
|
||||
const cfa = switch (cache_entry.cfa_rule) {
|
||||
.none => return error.InvalidDebugInfo,
|
||||
@ -202,23 +201,15 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
|
||||
},
|
||||
};
|
||||
|
||||
// If unspecified, we'll use the default rule for the return address register, which is
|
||||
// typically equivalent to `.undefined` (meaning there is no return address), but may be
|
||||
// overriden by ABIs.
|
||||
var has_return_address: bool = switch (builtin.cpu.arch) {
|
||||
// DWARF for the Arm 64-bit Architecture (AArch64) §4.3, p1
|
||||
.aarch64, .aarch64_be => return_address_register >= 19 and return_address_register <= 28,
|
||||
// ELF ABI s390x Supplement §1.6.4
|
||||
.s390x => return_address_register >= 6 and return_address_register <= 15,
|
||||
else => false,
|
||||
};
|
||||
|
||||
// Create a copy of the CPU state, to which we will apply the new rules.
|
||||
var new_cpu_state = unwinder.cpu_state;
|
||||
|
||||
// On all implemented architectures, the CFA is defined to be the previous frame's SP
|
||||
(try regNative(&new_cpu_state, sp_reg_num)).* = cfa;
|
||||
|
||||
const return_address_register = cache_entry.cie.return_address_register;
|
||||
var has_return_address = true;
|
||||
|
||||
const rules_len = cache_entry.num_rules;
|
||||
for (cache_entry.rules_regs[0..rules_len], cache_entry.rules[0..rules_len]) |register, rule| {
|
||||
const new_val: union(enum) {
|
||||
@ -228,13 +219,14 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
|
||||
bytes: []const u8,
|
||||
} = switch (rule) {
|
||||
.default => val: {
|
||||
// The default rule is typically equivalent to `.undefined`, but ABIs may override it.
|
||||
switch (builtin.target.cpu.arch) {
|
||||
.aarch64, .aarch64_be => if (register >= 19 and register <= 28) break :val .same,
|
||||
.s390x => if (register >= 6 and register <= 15) break :val .same,
|
||||
else => {},
|
||||
}
|
||||
break :val .undefined;
|
||||
// The way things are supposed to work is that `.undefined` is the default rule
|
||||
// unless an ABI says otherwise (e.g. aarch64, s390x).
|
||||
//
|
||||
// Unfortunately, at some point, a decision was made to have libgcc's unwinder
|
||||
// assume `.same` as the default for all registers. Compilers then started depending
|
||||
// on this, and the practice was carried forward to LLVM's libunwind and some of its
|
||||
// backends.
|
||||
break :val .same;
|
||||
},
|
||||
.undefined => .undefined,
|
||||
.same_value => .same,
|
||||
@ -273,6 +265,12 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
|
||||
.undefined => {
|
||||
const dest = try new_cpu_state.dwarfRegisterBytes(@intCast(register));
|
||||
@memset(dest, undefined);
|
||||
|
||||
// If the return address register is explicitly set to `.undefined`, it means that
|
||||
// there are no more frames to unwind.
|
||||
if (register == return_address_register) {
|
||||
has_return_address = false;
|
||||
}
|
||||
},
|
||||
.val => |val| {
|
||||
const dest = try new_cpu_state.dwarfRegisterBytes(@intCast(register));
|
||||
@ -286,15 +284,12 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE
|
||||
@memcpy(dest, src);
|
||||
},
|
||||
}
|
||||
if (register == return_address_register) {
|
||||
has_return_address = new_val != .undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const return_address: usize = if (has_return_address) pc: {
|
||||
const raw_ptr = try regNative(&new_cpu_state, return_address_register);
|
||||
break :pc stripInstructionPtrAuthCode(raw_ptr.*);
|
||||
} else 0;
|
||||
const return_address = if (has_return_address)
|
||||
stripInstructionPtrAuthCode((try regNative(&new_cpu_state, return_address_register)).*)
|
||||
else
|
||||
0;
|
||||
|
||||
(try regNative(&new_cpu_state, ip_reg_num)).* = return_address;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user