summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--absl/debugging/internal/stacktrace_aarch64-inl.inc13
1 files changed, 9 insertions, 4 deletions
diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc
index b66beba2..520e9a84 100644
--- a/absl/debugging/internal/stacktrace_aarch64-inl.inc
+++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc
@@ -94,16 +94,21 @@ static void **NextStackFrame(void **old_frame_pointer, const void *uc) {
void **const pre_signal_frame_pointer =
reinterpret_cast<void **>(ucv->uc_mcontext.regs[29]);
+ // The most recent signal always needs special handling to find the frame
+ // pointer, but a nested signal does not. If pre_signal_frame_pointer is
+ // earlier in the stack than the old_frame_pointer, then use it. If it is
+ // later, then we have already unwound through it and it needs no special
+ // handling.
+ if (pre_signal_frame_pointer >= old_frame_pointer) {
+ new_frame_pointer = pre_signal_frame_pointer;
+ }
// Check that alleged frame pointer is actually readable. This is to
// prevent "double fault" in case we hit the first fault due to e.g.
// stack corruption.
if (!absl::debugging_internal::AddressIsReadable(
- pre_signal_frame_pointer))
+ new_frame_pointer))
return nullptr;
- // Alleged frame pointer is readable, use it for further unwinding.
- new_frame_pointer = pre_signal_frame_pointer;
-
// Skip frame size check if we return from a signal. We may be using a
// an alternate stack for signals.
check_frame_size = false;