use alloc::boxed::Box; use crate::{rule_cache::RuleCache, unwind_rule::UnwindRule}; 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 { type GimliUnwindContextStorage: gimli::UnwindContextStorage; type GimliEvaluationStorage: gimli::EvaluationStorage; } /// Require allocation-free unwinding. This is one of the two [`AllocationPolicy`] /// implementations. /// /// Using this means that the unwinder cache takes up more memory, because it preallocates /// space for DWARF CFI unwind table row evaluation and for DWARF CFI expression evaluation. /// And because those preallocations are of a fixed size, it is possible that this fixed /// size is not large enough for certain DWARF unwinding tasks. pub struct MustNotAllocateDuringUnwind; /// This is only used in the implementation of [MustNotAllocateDuringUnwind] and /// is not intended to be used by the outside world. #[doc(hidden)] pub struct StoreOnStack; impl gimli::UnwindContextStorage for StoreOnStack { type Rules = [(gimli::Register, gimli::RegisterRule); 192]; type Stack = [gimli::UnwindTableRow; 4]; } impl gimli::EvaluationStorage for StoreOnStack { type Stack = [gimli::Value; 64]; type ExpressionStack = [(R, R); 4]; type Result = [gimli::Piece; 1]; } impl AllocationPolicy for MustNotAllocateDuringUnwind { type GimliUnwindContextStorage = StoreOnStack; type GimliEvaluationStorage = StoreOnStack; } /// Allow allocation during unwinding. This is one of the two [`AllocationPolicy`] /// implementations. /// /// This is the preferred policy because it saves memory and places no limitations on /// DWARF CFI evaluation. pub struct MayAllocateDuringUnwind; impl AllocationPolicy for MayAllocateDuringUnwind { type GimliUnwindContextStorage = gimli::StoreOnHeap; type GimliEvaluationStorage = gimli::StoreOnHeap; } /// The unwinder cache. This needs to be created upfront before unwinding. During /// unwinding, the unwinder needs exclusive access to this cache. /// /// A single unwinder cache can be used with multiple unwinders alternatingly. /// /// 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 { pub(crate) gimli_unwind_context: Box>>, pub(crate) rule_cache: RuleCache, } impl Cache { pub fn new() -> Self { Self { gimli_unwind_context: Box::new(gimli::UnwindContext::new_in()), rule_cache: RuleCache::new(), } } } impl Default for Cache { fn default() -> Self { Self::new() } }