From b1969dc9aba8a80ac22b87c914cd4558d5f58d17 Mon Sep 17 00:00:00 2001 From: Markus Stange <markus.stange@gmail.com> Date: Wed, 13 Mar 2024 22:42:25 -0400 Subject: [PATCH] Use EndianSlice, remove ArcData. The new gimli version stores offsets instead of readers in the evaluation cache, which means that our readers no longer have to take Arcs to the module data. --- src/aarch64/cache.rs | 19 ++++--- src/aarch64/dwarf.rs | 36 +++++++----- src/aarch64/unwinder.rs | 17 +++--- src/arcdata.rs | 30 ---------- src/cache.rs | 33 +++++------ src/dwarf.rs | 30 +++++----- src/lib.rs | 5 +- src/unwinder.rs | 98 ++++++++++++++++---------------- src/x86_64/cache.rs | 19 ++++--- src/x86_64/dwarf.rs | 18 +++--- src/x86_64/unwinder.rs | 12 ++-- tests/integration_tests/linux.rs | 2 +- 12 files changed, 151 insertions(+), 168 deletions(-) delete mode 100644 src/arcdata.rs diff --git a/src/aarch64/cache.rs b/src/aarch64/cache.rs index 04637d6..4b207ea 100644 --- a/src/aarch64/cache.rs +++ b/src/aarch64/cache.rs @@ -1,18 +1,23 @@ -use core::ops::Deref; - use super::unwind_rule::*; use crate::cache::*; /// The unwinder cache type for [`UnwinderAarch64`](super::UnwinderAarch64). -pub struct CacheAarch64<D: Deref<Target = [u8]>, P: AllocationPolicy<D> = MayAllocateDuringUnwind>( - pub Cache<D, UnwindRuleAarch64, P>, +pub struct CacheAarch64<P: AllocationPolicy = MayAllocateDuringUnwind>( + pub Cache<UnwindRuleAarch64, P>, ); -impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> CacheAarch64<D, P> { +impl CacheAarch64<MayAllocateDuringUnwind> { /// Create a new cache. pub fn new() -> Self { Self(Cache::new()) } +} + +impl<P: AllocationPolicy> CacheAarch64<P> { + /// Create a new cache. + pub fn new_in() -> Self { + Self(Cache::new()) + } /// Returns a snapshot of the cache usage statistics. pub fn stats(&self) -> CacheStats { @@ -20,8 +25,8 @@ impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> CacheAarch64<D, P> { } } -impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> Default for CacheAarch64<D, P> { +impl<P: AllocationPolicy> Default for CacheAarch64<P> { fn default() -> Self { - Self::new() + Self::new_in() } } diff --git a/src/aarch64/dwarf.rs b/src/aarch64/dwarf.rs index 0f3ea17..c3ea10a 100644 --- a/src/aarch64/dwarf.rs +++ b/src/aarch64/dwarf.rs @@ -1,5 +1,6 @@ use gimli::{ - AArch64, CfaRule, Encoding, EvaluationStorage, Reader, ReaderOffset, Register, RegisterRule, UnwindContextStorage, UnwindSection, UnwindTableRow + AArch64, CfaRule, Encoding, EvaluationStorage, Reader, ReaderOffset, Register, RegisterRule, + UnwindContextStorage, UnwindSection, UnwindTableRow, }; use super::{arch::ArchAarch64, unwind_rule::UnwindRuleAarch64, unwindregs::UnwindRegsAarch64}; @@ -23,9 +24,9 @@ impl DwarfUnwindRegs for UnwindRegsAarch64 { } impl DwarfUnwinding for ArchAarch64 { - fn unwind_frame<F, R, S>( + fn unwind_frame<F, R, UCS, ES>( section: &impl UnwindSection<R>, - unwind_info: &UnwindTableRow<R::Offset, S>, + unwind_info: &UnwindTableRow<R::Offset, UCS>, encoding: Encoding, regs: &mut Self::UnwindRegs, is_first_frame: bool, @@ -34,7 +35,8 @@ impl DwarfUnwinding for ArchAarch64 { where F: FnMut(u64) -> Result<u64, ()>, R: Reader, - S: UnwindContextStorage<R::Offset> + EvaluationStorage<R>, + UCS: UnwindContextStorage<R::Offset>, + ES: EvaluationStorage<R>, { let cfa_rule = unwind_info.cfa(); let fp_rule = unwind_info.register(AArch64::X29); @@ -48,7 +50,7 @@ impl DwarfUnwinding for ArchAarch64 { } } - let cfa = eval_cfa_rule::<R, _, S>(section, cfa_rule, encoding, regs) + let cfa = eval_cfa_rule::<R, _, ES>(section, cfa_rule, encoding, regs) .ok_or(DwarfUnwinderError::CouldNotRecoverCfa)?; let lr = regs.lr(); @@ -59,19 +61,27 @@ impl DwarfUnwinding for ArchAarch64 { if cfa <= sp { return Err(DwarfUnwinderError::StackPointerMovedBackwards); } - let fp = eval_register_rule::<R, F, _, S>(section, fp_rule, cfa, encoding, fp, regs, read_stack) - .ok_or(DwarfUnwinderError::CouldNotRecoverFramePointer)?; - let lr = eval_register_rule::<R, F, _, S>(section, lr_rule, cfa, encoding, lr, regs, read_stack) - .ok_or(DwarfUnwinderError::CouldNotRecoverReturnAddress)?; + let fp = eval_register_rule::<R, F, _, ES>( + section, fp_rule, cfa, encoding, fp, regs, read_stack, + ) + .ok_or(DwarfUnwinderError::CouldNotRecoverFramePointer)?; + let lr = eval_register_rule::<R, F, _, ES>( + section, lr_rule, cfa, encoding, lr, regs, read_stack, + ) + .ok_or(DwarfUnwinderError::CouldNotRecoverReturnAddress)?; (fp, lr) } else { // For the first frame, be more lenient when encountering errors. // TODO: Find evidence of what this gives us. I think on macOS the prologue often has Unknown register rules // and we only encounter prologues for the first frame. - let fp = eval_register_rule::<R, F, _, S>(section, fp_rule, cfa, encoding, fp, regs, read_stack) - .unwrap_or(fp); - let lr = eval_register_rule::<R, F, _, S>(section, lr_rule, cfa, encoding, lr, regs, read_stack) - .unwrap_or(lr); + let fp = eval_register_rule::<R, F, _, ES>( + section, fp_rule, cfa, encoding, fp, regs, read_stack, + ) + .unwrap_or(fp); + let lr = eval_register_rule::<R, F, _, ES>( + section, lr_rule, cfa, encoding, lr, regs, read_stack, + ) + .unwrap_or(lr); (fp, lr) }; diff --git a/src/aarch64/unwinder.rs b/src/aarch64/unwinder.rs index 417eaef..575b0f5 100644 --- a/src/aarch64/unwinder.rs +++ b/src/aarch64/unwinder.rs @@ -13,27 +13,26 @@ use super::{ArchAarch64, CacheAarch64, UnwindRegsAarch64}; /// /// - `D`: The type for unwind section data in the modules. See [`Module`]. /// - `P`: The [`AllocationPolicy`]. -pub struct UnwinderAarch64< - D: Deref<Target = [u8]>, - P: AllocationPolicy<D> = MayAllocateDuringUnwind, ->(UnwinderInternal<D, ArchAarch64, P>); +pub struct UnwinderAarch64<D: Deref<Target = [u8]>, P: AllocationPolicy = MayAllocateDuringUnwind>( + UnwinderInternal<D, ArchAarch64, P>, +); -impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> Default for UnwinderAarch64<D, P> { +impl<D: Deref<Target = [u8]>, P: AllocationPolicy> Default for UnwinderAarch64<D, P> { fn default() -> Self { Self::new() } } -impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> UnwinderAarch64<D, P> { +impl<D: Deref<Target = [u8]>, P: AllocationPolicy> UnwinderAarch64<D, P> { /// Create an unwinder for a process. pub fn new() -> Self { Self(UnwinderInternal::new()) } } -impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> Unwinder for UnwinderAarch64<D, P> { +impl<D: Deref<Target = [u8]>, P: AllocationPolicy> Unwinder for UnwinderAarch64<D, P> { type UnwindRegs = UnwindRegsAarch64; - type Cache = CacheAarch64<D, P>; + type Cache = CacheAarch64<P>; type Module = Module<D>; fn add_module(&mut self, module: Module<D>) { @@ -52,7 +51,7 @@ impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> Unwinder for UnwinderAarch &self, address: FrameAddress, regs: &mut UnwindRegsAarch64, - cache: &mut CacheAarch64<D, P>, + cache: &mut CacheAarch64<P>, read_stack: &mut F, ) -> Result<Option<u64>, Error> where diff --git a/src/arcdata.rs b/src/arcdata.rs deleted file mode 100644 index 090532a..0000000 --- a/src/arcdata.rs +++ /dev/null @@ -1,30 +0,0 @@ -use alloc::sync::Arc; -use core::{fmt::Debug, ops::Deref}; - -pub type ArcDataReader<D> = gimli::EndianReader<gimli::LittleEndian, ArcData<D>>; - -pub struct ArcData<D: Deref<Target = [u8]>>(pub Arc<D>); - -impl<D: Deref<Target = [u8]>> Deref for ArcData<D> { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl<D: Deref<Target = [u8]>> Clone for ArcData<D> { - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} - -impl<D: Deref<Target = [u8]>> Debug for ArcData<D> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_tuple("ArcData").field(&self.0.as_ptr()).finish() - } -} - -// Safety: See the implementation for Arc. ArcData just wraps Arc, cloning ArcData just clones Arc. -unsafe impl<D: Deref<Target = [u8]>> gimli::StableDeref for ArcData<D> {} -unsafe impl<D: Deref<Target = [u8]>> gimli::CloneStableDeref for ArcData<D> {} diff --git a/src/cache.rs b/src/cache.rs index 2bd99e5..1c7a61f 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,18 +1,14 @@ -use core::ops::Deref; - use alloc::boxed::Box; use crate::{rule_cache::RuleCache, unwind_rule::UnwindRule}; -use super::arcdata::ArcDataReader; - pub use crate::rule_cache::CacheStats; /// A trait which lets you opt into allocation-free unwinding. The two implementations of /// this trait are [`MustNotAllocateDuringUnwind`] and [`MayAllocateDuringUnwind`]. -pub trait AllocationPolicy<D: Deref<Target = [u8]>> { - type GimliStorage: gimli::UnwindContextStorage<usize> - + gimli::EvaluationStorage<ArcDataReader<D>>; +pub trait AllocationPolicy { + type GimliUnwindContextStorage<R: gimli::ReaderOffset>: gimli::UnwindContextStorage<R>; + type GimliEvaluationStorage<R: gimli::Reader>: gimli::EvaluationStorage<R>; } /// Require allocation-free unwinding. This is one of the two [`AllocationPolicy`] @@ -40,8 +36,9 @@ impl<R: gimli::Reader> gimli::EvaluationStorage<R> for StoreOnStack { type Result = [gimli::Piece<R>; 1]; } -impl<D: Deref<Target = [u8]>> AllocationPolicy<D> for MustNotAllocateDuringUnwind { - type GimliStorage = StoreOnStack; +impl AllocationPolicy for MustNotAllocateDuringUnwind { + type GimliUnwindContextStorage<R: gimli::ReaderOffset> = StoreOnStack; + type GimliEvaluationStorage<R: gimli::Reader> = StoreOnStack; } /// Allow allocation during unwinding. This is one of the two [`AllocationPolicy`] @@ -50,8 +47,9 @@ impl<D: Deref<Target = [u8]>> AllocationPolicy<D> for MustNotAllocateDuringUnwin /// This is the preferred policy because it saves memory and places no limitations on /// DWARF CFI evaluation. pub struct MayAllocateDuringUnwind; -impl<D: Deref<Target = [u8]>> AllocationPolicy<D> for MayAllocateDuringUnwind { - type GimliStorage = gimli::StoreOnHeap; +impl AllocationPolicy for MayAllocateDuringUnwind { + type GimliUnwindContextStorage<R: gimli::ReaderOffset> = gimli::StoreOnHeap; + type GimliEvaluationStorage<R: gimli::Reader> = gimli::StoreOnHeap; } /// The unwinder cache. This needs to be created upfront before unwinding. During @@ -61,16 +59,13 @@ impl<D: Deref<Target = [u8]>> AllocationPolicy<D> for MayAllocateDuringUnwind { /// /// The cache stores unwind rules for addresses it has seen before, and it stores the /// unwind context which gimli needs for DWARF CFI evaluation. -pub struct Cache< - D: Deref<Target = [u8]>, - R: UnwindRule, - P: AllocationPolicy<D> = MayAllocateDuringUnwind, -> { - pub(crate) gimli_unwind_context: Box<gimli::UnwindContext<usize, P::GimliStorage>>, +pub struct Cache<R: UnwindRule, P: AllocationPolicy = MayAllocateDuringUnwind> { + pub(crate) gimli_unwind_context: + Box<gimli::UnwindContext<usize, P::GimliUnwindContextStorage<usize>>>, pub(crate) rule_cache: RuleCache<R>, } -impl<D: Deref<Target = [u8]>, R: UnwindRule, P: AllocationPolicy<D>> Cache<D, R, P> { +impl<R: UnwindRule, P: AllocationPolicy> Cache<R, P> { pub fn new() -> Self { Self { gimli_unwind_context: Box::new(gimli::UnwindContext::new_in()), @@ -79,7 +74,7 @@ impl<D: Deref<Target = [u8]>, R: UnwindRule, P: AllocationPolicy<D>> Cache<D, R, } } -impl<D: Deref<Target = [u8]>, R: UnwindRule, P: AllocationPolicy<D>> Default for Cache<D, R, P> { +impl<R: UnwindRule, P: AllocationPolicy> Default for Cache<R, P> { fn default() -> Self { Self::new() } diff --git a/src/dwarf.rs b/src/dwarf.rs index 62cfa43..90214d7 100644 --- a/src/dwarf.rs +++ b/src/dwarf.rs @@ -57,9 +57,9 @@ pub enum ConversionError { } pub trait DwarfUnwinding: Arch { - fn unwind_frame<F, R, S>( + fn unwind_frame<F, R, UCS, ES>( section: &impl UnwindSection<R>, - unwind_info: &UnwindTableRow<R::Offset, S>, + unwind_info: &UnwindTableRow<R::Offset, UCS>, encoding: Encoding, regs: &mut Self::UnwindRegs, is_first_frame: bool, @@ -68,7 +68,8 @@ pub trait DwarfUnwinding: Arch { where F: FnMut(u64) -> Result<u64, ()>, R: Reader, - S: UnwindContextStorage<R::Offset> + EvaluationStorage<R>; + UCS: UnwindContextStorage<R::Offset>, + ES: EvaluationStorage<R>; fn rule_if_uncovered_by_fde() -> Self::UnwindRule; } @@ -82,29 +83,25 @@ pub struct DwarfUnwinder< 'a, R: Reader, A: DwarfUnwinding + ?Sized, - S: UnwindContextStorage<R::Offset>, + UCS: UnwindContextStorage<R::Offset>, > { unwind_section_data: R, unwind_section_type: UnwindSectionType, eh_frame_hdr: Option<ParsedEhFrameHdr<EndianSlice<'a, R::Endian>>>, - unwind_context: &'a mut UnwindContext<R::Offset, S>, + unwind_context: &'a mut UnwindContext<R::Offset, UCS>, base_svma: u64, bases: BaseAddresses, _arch: PhantomData<A>, } -impl< - 'a, - R: Reader, - A: DwarfUnwinding, - S: UnwindContextStorage<R::Offset> + EvaluationStorage<R>, - > DwarfUnwinder<'a, R, A, S> +impl<'a, R: Reader, A: DwarfUnwinding, UCS: UnwindContextStorage<R::Offset>> + DwarfUnwinder<'a, R, A, UCS> { pub fn new( unwind_section_data: R, unwind_section_type: UnwindSectionType, eh_frame_hdr_data: Option<&'a [u8]>, - unwind_context: &'a mut UnwindContext<R::Offset, S>, + unwind_context: &'a mut UnwindContext<R::Offset, UCS>, bases: BaseAddresses, base_svma: u64, ) -> Self { @@ -138,7 +135,7 @@ impl< fde_offset.0.into_u64().try_into().ok() } - pub fn unwind_frame_with_fde<F>( + pub fn unwind_frame_with_fde<F, ES>( &mut self, regs: &mut A::UnwindRegs, is_first_frame: bool, @@ -148,6 +145,7 @@ impl< ) -> Result<UnwindResult<A::UnwindRule>, DwarfUnwinderError> where F: FnMut(u64) -> Result<u64, ()>, + ES: EvaluationStorage<R>, { let lookup_svma = self.base_svma + rel_lookup_address as u64; let unwind_section_data = self.unwind_section_data.clone(); @@ -160,7 +158,7 @@ impl< return Ok(UnwindResult::ExecRule(A::rule_if_uncovered_by_fde())); } let (unwind_info, encoding) = unwind_info?; - A::unwind_frame::<F, R, S>( + A::unwind_frame::<F, R, UCS, ES>( &eh_frame, unwind_info, encoding, @@ -177,7 +175,7 @@ impl< return Ok(UnwindResult::ExecRule(A::rule_if_uncovered_by_fde())); } let (unwind_info, encoding) = unwind_info?; - A::unwind_frame::<F, R, S>( + A::unwind_frame::<F, R, UCS, ES>( &debug_frame, unwind_info, encoding, @@ -194,7 +192,7 @@ impl< unwind_section: &US, lookup_svma: u64, fde_offset: u32, - ) -> Result<(&UnwindTableRow<R::Offset, S>, Encoding), DwarfUnwinderError> { + ) -> Result<(&UnwindTableRow<R::Offset, UCS>, Encoding), DwarfUnwinderError> { let fde = unwind_section.fde_from_offset( &self.bases, US::Offset::from(R::Offset::from_u32(fde_offset)), diff --git a/src/lib.rs b/src/lib.rs index 82610c4..737235c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,7 +116,6 @@ extern crate alloc; mod add_signed; -mod arcdata; mod arch; mod cache; mod code_address; @@ -148,7 +147,7 @@ pub use unwinder::{ /// The unwinder cache for the native CPU architecture. #[cfg(target_arch = "aarch64")] -pub type CacheNative<D, P> = aarch64::CacheAarch64<D, P>; +pub type CacheNative<P> = aarch64::CacheAarch64<P>; /// The unwind registers type for the native CPU architecture. #[cfg(target_arch = "aarch64")] pub type UnwindRegsNative = aarch64::UnwindRegsAarch64; @@ -158,7 +157,7 @@ pub type UnwinderNative<D, P> = aarch64::UnwinderAarch64<D, P>; /// The unwinder cache for the native CPU architecture. #[cfg(target_arch = "x86_64")] -pub type CacheNative<D, P> = x86_64::CacheX86_64<D, P>; +pub type CacheNative<P> = x86_64::CacheX86_64<P>; /// The unwind registers type for the native CPU architecture. #[cfg(target_arch = "x86_64")] pub type UnwindRegsNative = x86_64::UnwindRegsX86_64; diff --git a/src/unwinder.rs b/src/unwinder.rs index d16b63d..e6a2471 100644 --- a/src/unwinder.rs +++ b/src/unwinder.rs @@ -2,9 +2,8 @@ use alloc::string::String; use alloc::sync::Arc; use alloc::vec::Vec; use fallible_iterator::FallibleIterator; -use gimli::{EndianReader, LittleEndian}; +use gimli::{EndianSlice, LittleEndian}; -use crate::arcdata::ArcData; use crate::arch::Arch; use crate::cache::{AllocationPolicy, Cache}; use crate::dwarf::{DwarfCfiIndex, DwarfUnwinder, DwarfUnwinding, UnwindSectionType}; @@ -223,7 +222,7 @@ cfg_if::cfg_if! { } } -pub struct UnwinderInternal<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy<D>> { +pub struct UnwinderInternal<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy> { /// sorted by avma_range.start modules: Vec<Module<D>>, /// Incremented every time modules is changed. @@ -232,7 +231,7 @@ pub struct UnwinderInternal<D: Deref<Target = [u8]>, A: Unwinding, P: Allocation _allocation_policy: PhantomData<P>, } -impl<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy<D>> Default +impl<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy> Default for UnwinderInternal<D, A, P> { fn default() -> Self { @@ -240,7 +239,7 @@ impl<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy<D>> Default } } -impl<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy<D>> UnwinderInternal<D, A, P> { +impl<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy> UnwinderInternal<D, A, P> { pub fn new() -> Self { Self { modules: Vec::new(), @@ -317,7 +316,7 @@ impl<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy<D>> UnwinderInte &self, address: FrameAddress, regs: &mut A::UnwindRegs, - cache: &mut Cache<D, A::UnwindRule, P>, + cache: &mut Cache<A::UnwindRule, P>, read_stack: &mut F, callback: G, ) -> Result<Option<u64>, Error> @@ -328,7 +327,7 @@ impl<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy<D>> UnwinderInte FrameAddress, u32, &mut A::UnwindRegs, - &mut Cache<D, A::UnwindRule, P>, + &mut Cache<A::UnwindRule, P>, &mut F, ) -> Result<UnwindResult<A::UnwindRule>, UnwinderError>, { @@ -375,7 +374,7 @@ impl<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy<D>> UnwinderInte &self, address: FrameAddress, regs: &mut A::UnwindRegs, - cache: &mut Cache<D, A::UnwindRule, P>, + cache: &mut Cache<A::UnwindRule, P>, read_stack: &mut F, ) -> Result<Option<u64>, Error> where @@ -389,7 +388,7 @@ impl<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy<D>> UnwinderInte address: FrameAddress, rel_lookup_address: u32, regs: &mut A::UnwindRegs, - cache: &mut Cache<D, A::UnwindRule, P>, + cache: &mut Cache<A::UnwindRule, P>, read_stack: &mut F, ) -> Result<UnwindResult<A::UnwindRule>, UnwinderError> where @@ -440,18 +439,19 @@ impl<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy<D>> UnwinderInte CuiUnwindResult::ExecRule(rule) => UnwindResult::ExecRule(rule), CuiUnwindResult::NeedDwarf(fde_offset) => { let eh_frame_data = match eh_frame { - Some(data) => ArcData(data.clone()), + Some(data) => &***data, None => return Err(UnwinderError::NoDwarfData), }; - let mut dwarf_unwinder = DwarfUnwinder::<_, A, P::GimliStorage>::new( - EndianReader::new(eh_frame_data, LittleEndian), - UnwindSectionType::EhFrame, - None, - &mut cache.gimli_unwind_context, - base_addresses.clone(), - module.base_svma, - ); - dwarf_unwinder.unwind_frame_with_fde( + let mut dwarf_unwinder = + DwarfUnwinder::<_, A, P::GimliUnwindContextStorage<_>>::new( + EndianSlice::new(eh_frame_data, LittleEndian), + UnwindSectionType::EhFrame, + None, + &mut cache.gimli_unwind_context, + base_addresses.clone(), + module.base_svma, + ); + dwarf_unwinder.unwind_frame_with_fde::<_, P::GimliEvaluationStorage<_>>( regs, is_first_frame, rel_lookup_address, @@ -467,19 +467,19 @@ impl<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy<D>> UnwinderInte base_addresses, } => { let eh_frame_hdr_data = &eh_frame_hdr[..]; - let eh_frame_data = ArcData(eh_frame.clone()); - let mut dwarf_unwinder = DwarfUnwinder::<_, A, P::GimliStorage>::new( - EndianReader::new(eh_frame_data, LittleEndian), - UnwindSectionType::EhFrame, - Some(eh_frame_hdr_data), - &mut cache.gimli_unwind_context, - base_addresses.clone(), - module.base_svma, - ); + let mut dwarf_unwinder = + DwarfUnwinder::<_, A, P::GimliUnwindContextStorage<_>>::new( + EndianSlice::new(eh_frame, LittleEndian), + UnwindSectionType::EhFrame, + Some(eh_frame_hdr_data), + &mut cache.gimli_unwind_context, + base_addresses.clone(), + module.base_svma, + ); let fde_offset = dwarf_unwinder .get_fde_offset_for_relative_address(rel_lookup_address) .ok_or(UnwinderError::EhFrameHdrCouldNotFindAddress)?; - dwarf_unwinder.unwind_frame_with_fde( + dwarf_unwinder.unwind_frame_with_fde::<_, P::GimliEvaluationStorage<_>>( regs, is_first_frame, rel_lookup_address, @@ -492,19 +492,19 @@ impl<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy<D>> UnwinderInte eh_frame, base_addresses, } => { - let eh_frame_data = ArcData(eh_frame.clone()); - let mut dwarf_unwinder = DwarfUnwinder::<_, A, P::GimliStorage>::new( - EndianReader::new(eh_frame_data, LittleEndian), - UnwindSectionType::EhFrame, - None, - &mut cache.gimli_unwind_context, - base_addresses.clone(), - module.base_svma, - ); + let mut dwarf_unwinder = + DwarfUnwinder::<_, A, P::GimliUnwindContextStorage<_>>::new( + EndianSlice::new(eh_frame, LittleEndian), + UnwindSectionType::EhFrame, + None, + &mut cache.gimli_unwind_context, + base_addresses.clone(), + module.base_svma, + ); let fde_offset = index .fde_offset_for_relative_address(rel_lookup_address) .ok_or(UnwinderError::DwarfCfiIndexCouldNotFindAddress)?; - dwarf_unwinder.unwind_frame_with_fde( + dwarf_unwinder.unwind_frame_with_fde::<_, P::GimliEvaluationStorage<_>>( regs, is_first_frame, rel_lookup_address, @@ -517,19 +517,19 @@ impl<D: Deref<Target = [u8]>, A: Unwinding, P: AllocationPolicy<D>> UnwinderInte debug_frame, base_addresses, } => { - let debug_frame_data = ArcData(debug_frame.clone()); - let mut dwarf_unwinder = DwarfUnwinder::<_, A, P::GimliStorage>::new( - EndianReader::new(debug_frame_data, LittleEndian), - UnwindSectionType::DebugFrame, - None, - &mut cache.gimli_unwind_context, - base_addresses.clone(), - module.base_svma, - ); + let mut dwarf_unwinder = + DwarfUnwinder::<_, A, P::GimliUnwindContextStorage<_>>::new( + EndianSlice::new(debug_frame, LittleEndian), + UnwindSectionType::DebugFrame, + None, + &mut cache.gimli_unwind_context, + base_addresses.clone(), + module.base_svma, + ); let fde_offset = index .fde_offset_for_relative_address(rel_lookup_address) .ok_or(UnwinderError::DwarfCfiIndexCouldNotFindAddress)?; - dwarf_unwinder.unwind_frame_with_fde( + dwarf_unwinder.unwind_frame_with_fde::<_, P::GimliEvaluationStorage<_>>( regs, is_first_frame, rel_lookup_address, diff --git a/src/x86_64/cache.rs b/src/x86_64/cache.rs index e499580..fa3abdf 100644 --- a/src/x86_64/cache.rs +++ b/src/x86_64/cache.rs @@ -1,18 +1,23 @@ -use core::ops::Deref; - use super::unwind_rule::*; use crate::cache::*; /// The unwinder cache type for [`UnwinderX86_64`](super::UnwinderX86_64). -pub struct CacheX86_64<D: Deref<Target = [u8]>, P: AllocationPolicy<D> = MayAllocateDuringUnwind>( - pub Cache<D, UnwindRuleX86_64, P>, +pub struct CacheX86_64<P: AllocationPolicy = MayAllocateDuringUnwind>( + pub Cache<UnwindRuleX86_64, P>, ); -impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> CacheX86_64<D, P> { +impl CacheX86_64<MayAllocateDuringUnwind> { /// Create a new cache. pub fn new() -> Self { Self(Cache::new()) } +} + +impl<P: AllocationPolicy> CacheX86_64<P> { + /// Create a new cache. + pub fn new_in() -> Self { + Self(Cache::new()) + } /// Returns a snapshot of the cache usage statistics. pub fn stats(&self) -> CacheStats { @@ -20,8 +25,8 @@ impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> CacheX86_64<D, P> { } } -impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> Default for CacheX86_64<D, P> { +impl<P: AllocationPolicy> Default for CacheX86_64<P> { fn default() -> Self { - Self::new() + Self::new_in() } } diff --git a/src/x86_64/dwarf.rs b/src/x86_64/dwarf.rs index becc57c..12fd80a 100644 --- a/src/x86_64/dwarf.rs +++ b/src/x86_64/dwarf.rs @@ -22,9 +22,9 @@ impl DwarfUnwindRegs for UnwindRegsX86_64 { } impl DwarfUnwinding for ArchX86_64 { - fn unwind_frame<F, R, S>( + fn unwind_frame<F, R, UCS, ES>( section: &impl UnwindSection<R>, - unwind_info: &UnwindTableRow<R::Offset, S>, + unwind_info: &UnwindTableRow<R::Offset, UCS>, encoding: Encoding, regs: &mut Self::UnwindRegs, is_first_frame: bool, @@ -33,7 +33,8 @@ impl DwarfUnwinding for ArchX86_64 { where F: FnMut(u64) -> Result<u64, ()>, R: Reader, - S: UnwindContextStorage<R::Offset> + EvaluationStorage<R>, + UCS: UnwindContextStorage<R::Offset>, + ES: EvaluationStorage<R>, { let cfa_rule = unwind_info.cfa(); let bp_rule = unwind_info.register(X86_64::RBP); @@ -47,18 +48,19 @@ impl DwarfUnwinding for ArchX86_64 { } } - let cfa = eval_cfa_rule::<R, _, S>(section, cfa_rule, encoding, regs) + let cfa = eval_cfa_rule::<R, _, ES>(section, cfa_rule, encoding, regs) .ok_or(DwarfUnwinderError::CouldNotRecoverCfa)?; let ip = regs.ip(); let bp = regs.bp(); let sp = regs.sp(); - let new_bp = - eval_register_rule::<R, F, _, S>(section, bp_rule, cfa, encoding, bp, regs, read_stack) - .unwrap_or(bp); + let new_bp = eval_register_rule::<R, F, _, ES>( + section, bp_rule, cfa, encoding, bp, regs, read_stack, + ) + .unwrap_or(bp); - let return_address = match eval_register_rule::<R, F, _, S>( + let return_address = match eval_register_rule::<R, F, _, ES>( section, ra_rule, cfa, encoding, ip, regs, read_stack, ) { Some(ra) => ra, diff --git a/src/x86_64/unwinder.rs b/src/x86_64/unwinder.rs index c54cb72..1619a62 100644 --- a/src/x86_64/unwinder.rs +++ b/src/x86_64/unwinder.rs @@ -15,26 +15,26 @@ use crate::FrameAddress; /// /// - `D`: The type for unwind section data in the modules. See [`Module`]. /// - `P`: The [`AllocationPolicy`]. -pub struct UnwinderX86_64<D: Deref<Target = [u8]>, P: AllocationPolicy<D> = MayAllocateDuringUnwind>( +pub struct UnwinderX86_64<D: Deref<Target = [u8]>, P: AllocationPolicy = MayAllocateDuringUnwind>( UnwinderInternal<D, ArchX86_64, P>, ); -impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> Default for UnwinderX86_64<D, P> { +impl<D: Deref<Target = [u8]>, P: AllocationPolicy> Default for UnwinderX86_64<D, P> { fn default() -> Self { Self::new() } } -impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> UnwinderX86_64<D, P> { +impl<D: Deref<Target = [u8]>, P: AllocationPolicy> UnwinderX86_64<D, P> { /// Create an unwinder for a process. pub fn new() -> Self { Self(UnwinderInternal::new()) } } -impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> Unwinder for UnwinderX86_64<D, P> { +impl<D: Deref<Target = [u8]>, P: AllocationPolicy> Unwinder for UnwinderX86_64<D, P> { type UnwindRegs = UnwindRegsX86_64; - type Cache = CacheX86_64<D, P>; + type Cache = CacheX86_64<P>; type Module = Module<D>; fn add_module(&mut self, module: Module<D>) { @@ -53,7 +53,7 @@ impl<D: Deref<Target = [u8]>, P: AllocationPolicy<D>> Unwinder for UnwinderX86_6 &self, address: FrameAddress, regs: &mut UnwindRegsX86_64, - cache: &mut CacheX86_64<D, P>, + cache: &mut CacheX86_64<P>, read_stack: &mut F, ) -> Result<Option<u64>, Error> where diff --git a/tests/integration_tests/linux.rs b/tests/integration_tests/linux.rs index 680ac7e..c4b691f 100644 --- a/tests/integration_tests/linux.rs +++ b/tests/integration_tests/linux.rs @@ -9,7 +9,7 @@ use super::common; #[test] fn test_plt_cfa_expr() { - let mut cache = CacheX86_64::<_>::new(); + let mut cache = CacheX86_64::new(); let mut unwinder = UnwinderX86_64::new(); common::add_object( &mut unwinder,