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,