### Complete aarch64 Unwinding Example Source: https://context7.com/mstange/framehop/llms.txt Provides a comprehensive example for setting up framehop with aarch64, including module loading and full stack unwinding. This setup is suitable for profiling a process. ```rust use framehop::{ Unwinder, Module, ExplicitModuleSectionInfo, FrameAddress, Error }; use framehop::aarch64::{UnwinderAarch64, CacheAarch64, UnwindRegsAarch64, PtrAuthMask}; fn profile_thread( unwinder: &UnwinderAarch64, cache: &mut CacheAarch64, pc: u64, lr: u64, sp: u64, fp: u64, read_stack: &mut impl FnMut(u64) -> Result, ) -> Vec { // Set up pointer auth mask based on known code addresses let ptr_auth_mask = PtrAuthMask::from_max_known_address( unwinder.max_known_code_address() ); let regs = UnwindRegsAarch64::new_with_ptr_auth_mask(ptr_auth_mask, lr, sp, fp); // Collect all frame addresses let mut frames = Vec::new(); let mut iter = unwinder.iter_frames(pc, regs, cache, read_stack); while let Ok(Some(frame)) = iter.next() { frames.push(frame.address()); } frames } // Setup unwinder with modules fn setup_unwinder() -> UnwinderAarch64 { let mut unwinder = UnwinderAarch64::new(); // Add main executable let exe_module = Module::new( "myapp".to_string(), 0x100000000..0x100100000, 0x100000000, ExplicitModuleSectionInfo { base_svma: 0x100000000, unwind_info: Some(load_section("myapp", "__unwind_info")), eh_frame: Some(load_section("myapp", "__eh_frame")), text_segment_svma: Some(0x100000000..0x100100000), ..Default::default() }, ); unwinder.add_module(exe_module); // Add system libraries let libc_module = Module::new( "/usr/lib/libc.dylib".to_string(), 0x180000000..0x180200000, 0x180000000, ExplicitModuleSectionInfo { base_svma: 0x180000000, unwind_info: Some(load_section("libc", "__unwind_info")), ..Default::default() }, ); unwinder.add_module(libc_module); unwinder } fn load_section(_lib: &str, _section: &str) -> Vec { // Load section data from binary Vec::new() } ``` -------------------------------- ### Configure ELF Sections with ExplicitModuleSectionInfo Source: https://context7.com/mstange/framehop/llms.txt Define section data for a Linux ELF binary using `ExplicitModuleSectionInfo`. This example shows configuration for text, eh_frame, and eh_frame_hdr sections. ```rust use framehop::ExplicitModuleSectionInfo; // Linux ELF binary with DWARF CFI let elf_sections = ExplicitModuleSectionInfo { base_svma: 0x0, // ELF base address is typically 0 text_svma: Some(0x1000..0x50000), eh_frame_svma: Some(0x60000..0x70000), eh_frame: Some(eh_frame_bytes), eh_frame_hdr_svma: Some(0x58000..0x60000), eh_frame_hdr: Some(eh_frame_hdr_bytes), got_svma: Some(0x80000..0x81000), ..Default::default() }; ``` -------------------------------- ### Configure PE Sections with ExplicitModuleSectionInfo Source: https://context7.com/mstange/framehop/llms.txt Define section data for a Windows PE binary using `ExplicitModuleSectionInfo`. This example sets the image base address and text section virtual memory address range. ```rust use framehop::ExplicitModuleSectionInfo; // Windows PE binary let pe_sections = ExplicitModuleSectionInfo::> { base_svma: 0x140000000, // Image base address text_svma: Some(0x140001000..0x140050000), text: Some(text_bytes), // PE uses .pdata section (handled automatically when present) ..Default::default() }; ``` -------------------------------- ### AArch64 Stack Unwinding with Framehop Source: https://github.com/mstange/framehop/blob/main/Readme.md Demonstrates how to use Framehop's AArch64 unwinder to process a module, simulate stack data, and iterate through frames. Requires specific imports and setup for cache, unwinder, and module information. The `read_stack` closure simulates memory access. ```rust use framehop::aarch64::{CacheAarch64, UnwindRegsAarch64, UnwinderAarch64}; use framehop::{ExplicitModuleSectionInfo, FrameAddress, Module}; let mut cache = CacheAarch64::<_>::new(); let mut unwinder = UnwinderAarch64::new(); let module = Module::new( "mybinary".to_string(), 0x1003fc000..0x100634000, 0x1003fc000, ExplicitModuleSectionInfo { base_svma: 0x100000000, text_svma: Some(0x100000b64..0x1001d2d18), text: Some(vec![/* __text */]), stubs_svma: Some(0x1001d2d18..0x1001d309c), stub_helper_svma: Some(0x1001d309c..0x1001d3438), got_svma: Some(0x100238000..0x100238010), unwind_info: Some(vec![/* __unwind_info */]), eh_frame_svma: Some(0x100237f80..0x100237ffc), eh_frame: Some(vec![/* __eh_frame */]), text_segment_svma: Some(0x1003fc000..0x100634000), text_segment: Some(vec![/* __TEXT */]), ..Default::default() }, ); unwinder.add_module(module); let pc = 0x1003fc000 + 0x1292c0; let lr = 0x1003fc000 + 0xe4830; let sp = 0x10; let fp = 0x20; let stack = [ 1, 2, 3, 4, 0x40, 0x1003fc000 + 0x100dc4, 5, 6, 0x70, 0x1003fc000 + 0x12ca28, 7, 8, 9, 10, 0x0, 0x0, ]; let mut read_stack = |addr| stack.get((addr / 8) as usize).cloned().ok_or(()); use framehop::Unwinder; let mut iter = unwinder.iter_frames( pc, UnwindRegsAarch64::new(lr, sp, fp), &mut cache, &mut read_stack, ); let mut frames = Vec::new(); while let Ok(Some(frame)) = iter.next() { frames.push(frame); } assert_eq!( frames, vec![ FrameAddress::from_instruction_pointer(0x1003fc000 + 0x1292c0), FrameAddress::from_return_address(0x1003fc000 + 0x100dc4).unwrap(), FrameAddress::from_return_address(0x1003fc000 + 0x12ca28).unwrap() ] ); ``` -------------------------------- ### Initialize and Use x86_64 Unwinder and Cache Source: https://context7.com/mstange/framehop/llms.txt Demonstrates creating an x86_64 unwinder and cache, initializing register state, and accessing/modifying general-purpose registers. ```rust use framehop::x86_64::{UnwinderX86_64, CacheX86_64, UnwindRegsX86_64, Reg}; use framehop::MayAllocateDuringUnwind; // Create unwinder and cache let mut unwinder = UnwinderX86_64::new(); let mut cache = CacheX86_64::::new(); // Create register state let regs = UnwindRegsX86_64::new( 0x401234, // rip (instruction pointer) 0x7ffd0000, // rsp (stack pointer) 0x7ffd0010, // rbp (base pointer) ); // Access register values let mut regs = UnwindRegsX86_64::new(rip, rsp, rbp); println!("IP: {:#x}, SP: {:#x}, BP: {:#x}", regs.ip(), regs.sp(), regs.bp()); // Access any general purpose register let rax = regs.get(Reg::RAX); let rbx = regs.get(Reg::RBX); regs.set(Reg::R12, 0x12345678); // Modify specific registers regs.set_ip(new_rip); regs.set_sp(new_rsp); regs.set_bp(new_rbp); ``` -------------------------------- ### Create and Analyze FrameAddress Types Source: https://context7.com/mstange/framehop/llms.txt Shows how to create FrameAddress instances for instruction pointers and return addresses, and how their lookup addresses differ. Handles null return addresses indicating the stack bottom. ```rust use framehop::FrameAddress; // First frame uses instruction pointer directly let first_frame = FrameAddress::from_instruction_pointer(0x401234); assert!(!first_frame.is_return_address()); assert_eq!(first_frame.address(), 0x401234); assert_eq!(first_frame.address_for_lookup(), 0x401234); // Subsequent frames use return addresses let return_frame = FrameAddress::from_return_address(0x401300).unwrap(); assert!(return_frame.is_return_address()); assert_eq!(return_frame.address(), 0x401300); // Lookup address is offset by -1 to point inside the call instruction assert_eq!(return_frame.address_for_lookup(), 0x4012ff); // Null return address returns None (indicates stack bottom) let null_frame = FrameAddress::from_return_address(0); assert!(null_frame.is_none()); // Pattern matching on frame type fn process_frame(frame: FrameAddress) { match frame { FrameAddress::InstructionPointer(addr) => { println!("Current instruction at {:#x}", addr); } FrameAddress::ReturnAddress(addr) => { println!("Will return to {:#x}", u64::from(addr)); } } } ``` -------------------------------- ### Create a Module with Explicit Section Info Source: https://context7.com/mstange/framehop/llms.txt Instantiate a `Module` using `ExplicitModuleSectionInfo` to provide detailed section addresses and data for unwinding. This is useful for libraries loaded at specific memory addresses. ```rust use framehop::{Module, ExplicitModuleSectionInfo, ModuleSectionInfo}; use std::ops::Range; // Using ExplicitModuleSectionInfo for explicit section specification let module = Module::new( "/usr/lib/libc.so.6".to_string(), 0x7f8000000000..0x7f8000200000, // Actual virtual memory address range 0x7f8000000000, // Base address in process memory ExplicitModuleSectionInfo { base_svma: 0x0, // ELF base is typically 0 text_svma: Some(0x20000..0x150000), text: Some(text_section_bytes), eh_frame_svma: Some(0x180000..0x190000), eh_frame: Some(eh_frame_bytes), eh_frame_hdr_svma: Some(0x178000..0x180000), eh_frame_hdr: Some(eh_frame_hdr_bytes), ..Default::default() }, ); // Custom ModuleSectionInfo implementation for lazy loading struct LazyModule { base: u64, sections: std::collections::HashMap, (Range, Vec)> } impl ModuleSectionInfo> for LazyModule { fn base_svma(&self) -> u64 { self.base } fn section_svma_range(&mut self, name: &[u8]) -> Option> { self.sections.get(name).map(|(range, _)| range.clone()) } fn section_data(&mut self, name: &[u8]) -> Option> { self.sections.remove(name).map(|(_, data)| data) } } ``` -------------------------------- ### Configure Mach-O Sections with ExplicitModuleSectionInfo Source: https://context7.com/mstange/framehop/llms.txt Define section data for a macOS Mach-O binary using `ExplicitModuleSectionInfo`. This includes specifying addresses for text, stubs, stub helpers, and unwind info sections. ```rust use framehop::ExplicitModuleSectionInfo; // macOS mach-O binary with compact unwind info let macho_sections = ExplicitModuleSectionInfo { base_svma: 0x100000000, // __TEXT segment vmaddr for mach-O executables text_svma: Some(0x100001000..0x100050000), text: Some(text_bytes), stubs_svma: Some(0x100050000..0x100051000), stub_helper_svma: Some(0x100051000..0x100052000), unwind_info: Some(unwind_info_bytes), // __unwind_info section eh_frame_svma: Some(0x100060000..0x100065000), eh_frame: Some(eh_frame_bytes), text_segment_svma: Some(0x100000000..0x100070000), text_segment: Some(text_segment_bytes), ..Default::default() }; ``` -------------------------------- ### Iterate Through Call Stack with x86_64 Unwinder Source: https://context7.com/mstange/framehop/llms.txt Shows how to use `UnwindIterator` with `UnwinderX86_64` to traverse the entire call stack. Requires initial register state and a stack memory reader function. ```rust use framehop::{Unwinder, FrameAddress}; use framehop::x86_64::{UnwinderX86_64, CacheX86_64, UnwindRegsX86_64}; let mut unwinder = UnwinderX86_64::new(); let mut cache = CacheX86_64::<_>::new(); // Set up initial register state (rip, rsp, rbp) let pc = 0x401000; // Current instruction pointer let sp = 0x7ffd0000; let bp = 0x7ffd0010; let regs = UnwindRegsX86_64::new(pc, sp, bp); // Stack memory reader let stack: Vec = vec![0x7ffd0020, 0x401100, 0x7ffd0030, 0x401200, 0, 0]; let mut read_stack = |addr: u64| -> Result { stack.get((addr / 8) as usize).cloned().ok_or(()) }; // Iterate through all frames let mut iter = unwinder.iter_frames(pc, regs, &mut cache, &mut read_stack); let mut frames = Vec::new(); while let Ok(Some(frame)) = iter.next() { frames.push(frame); match frame { FrameAddress::InstructionPointer(addr) => println!("IP: {:#x}", addr), FrameAddress::ReturnAddress(addr) => println!("Return: {:#x}", u64::from(addr)), } } // frames now contains the complete call stack ``` -------------------------------- ### Initialize aarch64 Unwinding Caches Source: https://context7.com/mstange/framehop/llms.txt Create unwinding caches for the aarch64 architecture. `MayAllocateDuringUnwind` allows heap allocation, while `MustNotAllocateDuringUnwind` is for allocation-free contexts like signal handlers. ```rust use framehop::aarch64::{ UnwinderAarch64, CacheAarch64, UnwindRegsAarch64, PtrAuthMask }; use framehop::{MayAllocateDuringUnwind, MustNotAllocateDuringUnwind}; // Standard cache (allows heap allocation during unwinding) let mut cache = CacheAarch64::::new(); // Allocation-free cache (for use in signal handlers) let mut cache_no_alloc = CacheAarch64::::new_in(); ``` -------------------------------- ### Handle x86_64 Unwinding Errors Source: https://context7.com/mstange/framehop/llms.txt Demonstrates how to handle various errors that can occur during x86_64 stack unwinding operations. These errors typically indicate stack corruption, truncation, or missing unwind information. ```rust use framehop::{Error, Unwinder, FrameAddress}; use framehop::x86_64::{UnwinderX86_64, CacheX86_64, UnwindRegsX86_64}; let unwinder = UnwinderX86_64::new(); let mut cache = CacheX86_64::<_>::new(); let mut regs = UnwindRegsX86_64::new(pc, sp, bp); let mut read_stack = |addr: u64| -> Result { if addr >= stack_base && addr < stack_top { Ok(read_memory(addr)) } else { Err(()) // Cannot read this address } }; let address = FrameAddress::from_instruction_pointer(pc); match unwinder.unwind_frame(address, &mut regs, &mut cache, &mut read_stack) { Ok(Some(return_addr)) => { println!("Next frame at {:#x}", return_addr); } Ok(None) => { println!("Successfully reached end of stack"); } Err(Error::CouldNotReadStack(addr)) => { println!("Stack read failed at {:#x} - stack may be truncated", addr); } Err(Error::FramepointerUnwindingMovedBackwards) => { println!("Corrupted frame pointer chain detected"); } Err(Error::DidNotAdvance) => { println!("Unwinding stuck - would loop forever"); } Err(Error::IntegerOverflow) => { println!("Address calculation overflow"); } Err(Error::ReturnAddressIsNull) => { println!("Null return address encountered"); } } ``` -------------------------------- ### Configure Memory Allocation Policy for Unwinding Source: https://context7.com/mstange/framehop/llms.txt Compares and demonstrates the usage of `MayAllocateDuringUnwind` (default) and `MustNotAllocateDuringUnwind` policies for `CacheX86_64`. The latter is suitable for signal handlers. ```rust use framehop::{MayAllocateDuringUnwind, MustNotAllocateDuringUnwind}; use framehop::x86_64::{CacheX86_64, UnwinderX86_64}; // Default: allows allocation during DWARF CFI evaluation // Uses less memory, no limits on DWARF expression complexity let mut cache_alloc = CacheX86_64::::new(); // Allocation-free: preallocates all needed storage // Safe to use in signal handlers, but uses more memory // May fail on very complex DWARF expressions let mut cache_no_alloc = CacheX86_64::::new_in(); // Use with unwinder let unwinder = UnwinderX86_64::new(); // Both cache types work with the same unwinder ``` -------------------------------- ### Unwind Single Frame with aarch64 Unwinder Source: https://context7.com/mstange/framehop/llms.txt Demonstrates creating an `UnwinderAarch64`, adding a module with unwind information, and unwinding a single frame. Requires register values, stack memory access, and module information. ```rust use framehop::{Unwinder, Module, ExplicitModuleSectionInfo, FrameAddress}; use framehop::aarch64::{UnwinderAarch64, CacheAarch64, UnwindRegsAarch64}; // Create unwinder and cache let mut unwinder = UnwinderAarch64::new(); let mut cache = CacheAarch64::<_>::new(); // Add a module with unwind information let module = Module::new( "mylib.so".to_string(), 0x7f000000..0x7f100000, // AVMA range where module is loaded 0x7f000000, // Base AVMA ExplicitModuleSectionInfo { base_svma: 0x0, eh_frame: Some(eh_frame_bytes), eh_frame_hdr: Some(eh_frame_hdr_bytes), ..Default::default() }, ); unwinder.add_module(module); // Unwind a single frame let address = FrameAddress::from_instruction_pointer(0x7f001234); let mut regs = UnwindRegsAarch64::new(lr, sp, fp); let mut read_stack = |addr: u64| -> Result { // Read 8 bytes from stack memory at addr Ok(stack_memory.get(addr)) }; match unwinder.unwind_frame(address, &mut regs, &mut cache, &mut read_stack) { Ok(Some(return_address)) => println!("Return address: {:#x}", return_address), Ok(None) => println!("End of stack reached"), Err(e) => println!("Unwind error: {}", e), } // Remove module when unloaded unwinder.remove_module(0x7f000000); ``` -------------------------------- ### Display Cache Performance Statistics Source: https://context7.com/mstange/framehop/llms.txt Retrieves and prints detailed cache statistics, including total lookups, hits, misses, and specific miss reasons. Useful for monitoring and tuning profiler performance. ```rust use framehop::aarch64::CacheAarch64; use framehop::CacheStats; let mut cache = CacheAarch64::<_>::new(); // After some unwinding operations... let stats: CacheStats = cache.stats(); println!("Cache Statistics:"); println!(" Total lookups: {}", stats.total()); println!(" Hits: {} ({:.1}%)", stats.hits(), 100.0 * stats.hits() as f64 / stats.total() as f64); println!(" Misses: {}", stats.misses()); println!(" - Empty slot misses: {}", stats.miss_empty_slot_count); println!(" - Wrong address misses: {}", stats.miss_wrong_address_count); println!(" - Module generation misses: {}", stats.miss_wrong_modules_count); // Typical hit rate is ~80% for complex applications like Firefox ``` -------------------------------- ### Create aarch64 Register State Source: https://context7.com/mstange/framehop/llms.txt Initialize `UnwindRegsAarch64` with link register (lr), stack pointer (sp), and frame pointer (fp). Supports creating state with or without a pointer authentication mask for Apple Silicon. ```rust use framehop::aarch64::{ UnwinderAarch64, CacheAarch64, UnwindRegsAarch64, PtrAuthMask }; use framehop::{MayAllocateDuringUnwind, MustNotAllocateDuringUnwind}; // Create register state without pointer auth stripping let regs = UnwindRegsAarch64::new( 0x100001234, // lr (link register / return address) 0x16fdff000, // sp (stack pointer) 0x16fdff010, // fp (frame pointer, x29) ); // Create register state with pointer authentication mask (macOS arm64e) let ptr_auth_mask = PtrAuthMask::new_24_40(); // 24 bits hash, 40 bits address let regs_with_mask = UnwindRegsAarch64::new_with_ptr_auth_mask( ptr_auth_mask, 0x80_0000_0100_1234, // lr with pointer auth bits 0x16fdff000, 0x16fdff010, ); ``` -------------------------------- ### Infer Pointer Authentication Mask Source: https://context7.com/mstange/framehop/llms.txt Deduce the pointer authentication mask for aarch64 by using the `UnwinderAarch64` to find the maximum known code address. ```rust use framehop::aarch64::{ UnwinderAarch64, CacheAarch64, UnwindRegsAarch64, PtrAuthMask }; use framehop::{MayAllocateDuringUnwind, MustNotAllocateDuringUnwind}; // Deduce mask from known address range let unwinder = UnwinderAarch64::new(); let max_addr = unwinder.max_known_code_address(); let inferred_mask = PtrAuthMask::from_max_known_address(max_addr); ``` -------------------------------- ### Access and Modify aarch64 Registers Source: https://context7.com/mstange/framehop/llms.txt Read and update the stack pointer (sp), frame pointer (fp), and link register (lr) of `UnwindRegsAarch64`. Setting the link register automatically applies the pointer authentication mask if one is present. ```rust use framehop::aarch64::{ UnwinderAarch64, CacheAarch64, UnwindRegsAarch64, PtrAuthMask }; use framehop::{MayAllocateDuringUnwind, MustNotAllocateDuringUnwind}; // Access and modify register values let mut regs = UnwindRegsAarch64::new(lr, sp, fp); println!("SP: {:#x}, FP: {:#x}, LR: {:#x}", regs.sp(), regs.fp(), regs.lr()); regs.set_sp(new_sp); regs.set_fp(new_fp); regs.set_lr(new_lr); // Automatically applies pointer auth mask ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.