aboutsummaryrefslogtreecommitdiff
path: root/src/processor
diff options
context:
space:
mode:
Diffstat (limited to 'src/processor')
-rw-r--r--src/processor/stackwalker_arm64.cc27
-rw-r--r--src/processor/stackwalker_arm64.h7
2 files changed, 33 insertions, 1 deletions
diff --git a/src/processor/stackwalker_arm64.cc b/src/processor/stackwalker_arm64.cc
index f9660112..47e245ed 100644
--- a/src/processor/stackwalker_arm64.cc
+++ b/src/processor/stackwalker_arm64.cc
@@ -54,8 +54,29 @@ StackwalkerARM64::StackwalkerARM64(const SystemInfo* system_info,
StackFrameSymbolizer* resolver_helper)
: Stackwalker(system_info, memory, modules, resolver_helper),
context_(context),
- context_frame_validity_(StackFrameARM64::CONTEXT_VALID_ALL) { }
+ context_frame_validity_(StackFrameARM64::CONTEXT_VALID_ALL),
+ address_range_mask_(0xffffffffffffffff) {
+ if (modules && modules->module_count() > 0) {
+ // ARM64 supports storing pointer authentication codes in the upper bits of
+ // a pointer. Make a best guess at the range of valid addresses based on the
+ // range of loaded modules.
+ const CodeModule *high_module =
+ modules->GetModuleAtSequence(modules->module_count() - 1);
+ uint64_t mask = high_module->base_address() + high_module->size();
+ mask |= mask >> 1;
+ mask |= mask >> 2;
+ mask |= mask >> 4;
+ mask |= mask >> 8;
+ mask |= mask >> 16;
+ mask |= mask >> 32;
+ address_range_mask_ = mask;
+ }
+}
+uint64_t StackwalkerARM64::PtrauthStrip(uint64_t ptr) {
+ uint64_t stripped = ptr & address_range_mask_;
+ return modules_ && modules_->GetModuleForAddress(stripped) ? stripped : ptr;
+}
StackFrame* StackwalkerARM64::GetContextFrame() {
if (!context_) {
@@ -71,6 +92,8 @@ StackFrame* StackwalkerARM64::GetContextFrame() {
frame->context_validity = context_frame_validity_;
frame->trust = StackFrame::FRAME_TRUST_CONTEXT;
frame->instruction = frame->context.iregs[MD_CONTEXT_ARM64_REG_PC];
+ frame->context.iregs[MD_CONTEXT_ARM64_REG_LR] =
+ PtrauthStrip(frame->context.iregs[MD_CONTEXT_ARM64_REG_LR]);
return frame;
}
@@ -202,6 +225,8 @@ StackFrameARM64* StackwalkerARM64::GetCallerByFramePointer(
return NULL;
}
+ caller_lr = PtrauthStrip(caller_lr);
+
uint64_t caller_sp = last_fp ? last_fp + 16 :
last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP];
diff --git a/src/processor/stackwalker_arm64.h b/src/processor/stackwalker_arm64.h
index 121e8246..241383ea 100644
--- a/src/processor/stackwalker_arm64.h
+++ b/src/processor/stackwalker_arm64.h
@@ -68,6 +68,9 @@ class StackwalkerARM64 : public Stackwalker {
}
private:
+ // Strip pointer authentication codes from an address.
+ uint64_t PtrauthStrip(uint64_t ptr);
+
// Implementation of Stackwalker, using arm64 context and stack conventions.
virtual StackFrame* GetContextFrame();
virtual StackFrame* GetCallerFrame(const CallStack* stack,
@@ -95,6 +98,10 @@ class StackwalkerARM64 : public Stackwalker {
// CONTEXT_VALID_ALL in real use; it is only changeable for the sake of
// unit tests.
uint64_t context_frame_validity_;
+
+ // A mask of the valid address bits, determined from the address range of
+ // modules_.
+ uint64_t address_range_mask_;
};