diff --git a/src/aarch64/unwinder.rs b/src/aarch64/unwinder.rs index e8fafb6..b89ae57 100644 --- a/src/aarch64/unwinder.rs +++ b/src/aarch64/unwinder.rs @@ -51,6 +51,10 @@ impl, P: AllocationPolicy> Unwinder for UnwinderAarch64< self.0.max_known_code_address() } + fn is_address_in_module(&self, address: u64) -> bool { + self.0.is_address_in_module(address) + } + fn unwind_frame( &self, address: FrameAddress, diff --git a/src/unwinder.rs b/src/unwinder.rs index c17b71a..cd712a0 100644 --- a/src/unwinder.rs +++ b/src/unwinder.rs @@ -60,6 +60,16 @@ pub trait Unwinder: Clone { /// to make an educated guess at a pointer authentication mask for Aarch64 return addresses. fn max_known_code_address(&self) -> u64; + /// Returns whether `address` falls within the address range of any known + /// module, i.e. whether it points into code we have a module for. + /// + /// A genuine code address (an instruction pointer or a return address) + /// always lies in a known module. This lets a caller reject frames produced + /// by unreliable unwinding — e.g. frame-pointer walks over code without + /// unwind info, which can mistake a stack-local value for a saved return + /// address — that would otherwise surface as unresolved root frames. + fn is_address_in_module(&self, address: u64) -> bool; + /// Unwind a single frame, to recover return address and caller register values. /// This is the main entry point for unwinding. fn unwind_frame( @@ -284,6 +294,10 @@ impl, A: Unwinding, P: AllocationPolicy> UnwinderInterna self.modules.last().map_or(0, |m| m.avma_range.end) } + pub fn is_address_in_module(&self, address: u64) -> bool { + self.find_module_for_address(address).is_some() + } + fn find_module_for_address(&self, address: u64) -> Option<(usize, u32)> { let (module_index, module) = match self .modules diff --git a/src/x86_64/unwinder.rs b/src/x86_64/unwinder.rs index bb98d60..fd7e0e9 100644 --- a/src/x86_64/unwinder.rs +++ b/src/x86_64/unwinder.rs @@ -53,6 +53,10 @@ impl, P: AllocationPolicy> Unwinder for UnwinderX86_64 bool { + self.0.is_address_in_module(address) + } + fn unwind_frame( &self, address: FrameAddress,