66use crate :: core:: { CfaResult , ComputeStep , Result } ;
77use anyhow:: { anyhow, Context } ;
88use gimli:: {
9- BaseAddresses , CfaRule , CieOrFde , EhFrame , EhFrameHdr , EndianSlice , FrameDescriptionEntry ,
10- LittleEndian , ParsedEhFrameHdr , UnwindContext , UnwindSection ,
9+ BaseAddresses , CfaRule , CieOrFde , EhFrame , EhFrameHdr , FrameDescriptionEntry , LittleEndian ,
10+ ParsedEhFrameHdr , UnwindContext , UnwindSection ,
1111} ;
1212use object:: { Object , ObjectSection } ;
13+ use std:: sync:: Arc ;
1314use tracing:: { debug, info, warn} ;
1415
16+ use gimli:: { EndianSlice , LittleEndian as LE } ;
17+
1518/// CFI index for fast CFA rule lookup
1619pub struct CfiIndex {
17- /// Parsed eh_frame section
18- eh_frame : EhFrame < EndianSlice < ' static , LittleEndian > > ,
20+ /// Keep file data alive
21+ _file_data : Arc < [ u8 ] > ,
22+ /// Keep eh_frame section data alive
23+ _eh_frame_data : Arc < [ u8 ] > ,
24+ /// Keep eh_frame_hdr section data alive (if present)
25+ _eh_frame_hdr_data : Option < Arc < [ u8 ] > > ,
26+ /// Parsed eh_frame section (using 'static via Box::leak)
27+ eh_frame : EhFrame < EndianSlice < ' static , LE > > ,
1928 /// Parsed eh_frame_hdr for fast lookup (if available)
20- eh_frame_hdr : Option < ParsedEhFrameHdr < EndianSlice < ' static , LittleEndian > > > ,
29+ eh_frame_hdr : Option < ParsedEhFrameHdr < EndianSlice < ' static , LE > > > ,
2130 /// Base addresses for DWARF sections
2231 bases : BaseAddresses ,
2332 /// Whether we have eh_frame_hdr for fast lookup
@@ -34,48 +43,63 @@ impl std::fmt::Debug for CfiIndex {
3443}
3544
3645impl CfiIndex {
37- /// Create a new CFI index from an object file
38- pub fn from_static_data ( file_data : & ' static [ u8 ] ) -> Result < Self > {
39- let object = object:: File :: parse ( file_data) . context ( "Failed to parse object file" ) ?;
46+ /// Create a new CFI index from an object file data
47+ pub fn from_arc_data ( file_data : Arc < [ u8 ] > ) -> Result < Self > {
48+ let object = object:: File :: parse ( & file_data[ .. ] ) . context ( "Failed to parse object file" ) ?;
4049
4150 // Load eh_frame section (required)
42- let eh_frame_data = object
51+ let eh_frame_section = object
4352 . section_by_name ( ".eh_frame" )
44- . ok_or_else ( || anyhow ! ( ".eh_frame section not found" ) ) ?
45- . data ( )
46- . context ( "Failed to read .eh_frame section data" ) ?;
47-
48- let eh_frame = EhFrame :: new ( eh_frame_data, LittleEndian ) ;
53+ . ok_or_else ( || anyhow ! ( ".eh_frame section not found" ) ) ?;
54+
55+ // Get section data range
56+ let ( eh_frame_start, eh_frame_size) = eh_frame_section
57+ . file_range ( )
58+ . ok_or_else ( || anyhow ! ( ".eh_frame section has no file range" ) ) ?;
59+ let eh_frame_start = eh_frame_start as usize ;
60+ let eh_frame_end = eh_frame_start + eh_frame_size as usize ;
61+
62+ // Create Arc slice for eh_frame and leak to 'static
63+ // Note: We must copy once for Box::leak (gimli's EhFrame requires 'static lifetime)
64+ let eh_frame_data = file_data[ eh_frame_start..eh_frame_end] . to_vec ( ) ;
65+ let eh_frame_static: & ' static [ u8 ] = Box :: leak ( eh_frame_data. into_boxed_slice ( ) ) ;
66+ let eh_frame_arc: Arc < [ u8 ] > = Arc :: from ( eh_frame_static) ; // Zero-copy: reference leaked data
67+ let eh_frame = EhFrame :: new ( eh_frame_static, LittleEndian ) ;
4968
5069 // Try to load eh_frame_hdr for fast lookup (optional)
70+ let mut hdr_arc_opt: Option < Arc < [ u8 ] > > = None ;
5171 let ( eh_frame_hdr, has_fast_lookup) = match object. section_by_name ( ".eh_frame_hdr" ) {
52- Some ( section) => {
53- match section. data ( ) {
54- Ok ( data) => {
55- let hdr_section = EhFrameHdr :: new ( data, LittleEndian ) ;
56-
57- // Parse with proper address_size
58- let address_size = if object. is_64 ( ) { 8 } else { 4 } ;
59- let mut bases = BaseAddresses :: default ( ) ;
60-
61- // Set eh_frame_hdr section base
62- if let Some ( hdr_section_obj) = object. section_by_name ( ".eh_frame_hdr" ) {
63- bases = bases. set_eh_frame_hdr ( hdr_section_obj. address ( ) ) ;
64- }
65-
66- match hdr_section. parse ( & bases, address_size) {
67- Ok ( parsed) => {
68- info ! ( "Successfully parsed .eh_frame_hdr for fast FDE lookup" ) ;
69- ( Some ( parsed) , true )
70- }
71- Err ( e) => {
72- warn ! ( "Failed to parse .eh_frame_hdr: {:?}, falling back to linear search" , e) ;
73- ( None , false )
74- }
75- }
72+ Some ( hdr_section_obj) => {
73+ let ( hdr_start, hdr_size) = hdr_section_obj
74+ . file_range ( )
75+ . ok_or_else ( || anyhow ! ( ".eh_frame_hdr section has no file range" ) ) ?;
76+ let hdr_start = hdr_start as usize ;
77+ let hdr_end = hdr_start + hdr_size as usize ;
78+
79+ // Create Arc slice for eh_frame_hdr and leak to 'static
80+ let hdr_data = file_data[ hdr_start..hdr_end] . to_vec ( ) ;
81+ let hdr_static: & ' static [ u8 ] = Box :: leak ( hdr_data. into_boxed_slice ( ) ) ;
82+ let hdr_arc: Arc < [ u8 ] > = Arc :: from ( hdr_static) ; // Zero-copy: reference leaked data
83+ hdr_arc_opt = Some ( hdr_arc) ;
84+ let hdr_section = EhFrameHdr :: new ( hdr_static, LittleEndian ) ;
85+
86+ // Parse with proper address_size
87+ let address_size = if object. is_64 ( ) { 8 } else { 4 } ;
88+ let mut bases = BaseAddresses :: default ( ) ;
89+
90+ // Set eh_frame_hdr section base
91+ bases = bases. set_eh_frame_hdr ( hdr_section_obj. address ( ) ) ;
92+
93+ match hdr_section. parse ( & bases, address_size) {
94+ Ok ( parsed) => {
95+ info ! ( "Successfully parsed .eh_frame_hdr for fast FDE lookup" ) ;
96+ ( Some ( parsed) , true )
7697 }
7798 Err ( e) => {
78- warn ! ( "Failed to read .eh_frame_hdr data: {:?}" , e) ;
99+ warn ! (
100+ "Failed to parse .eh_frame_hdr: {:?}, falling back to linear search" ,
101+ e
102+ ) ;
79103 ( None , false )
80104 }
81105 }
@@ -105,6 +129,9 @@ impl CfiIndex {
105129 }
106130
107131 Ok ( Self {
132+ _file_data : file_data. clone ( ) ,
133+ _eh_frame_data : eh_frame_arc,
134+ _eh_frame_hdr_data : hdr_arc_opt,
108135 eh_frame,
109136 eh_frame_hdr,
110137 bases,
@@ -142,7 +169,11 @@ impl CfiIndex {
142169 // Get the expression bytes from the section
143170 let expression = expr. get ( & self . eh_frame ) ?;
144171 // Parse DWARF expression to compute steps
145- let steps = self . parse_dwarf_expression ( expression. 0 . slice ( ) ) ?;
172+ // expression.0 is EndianSlice, get the underlying bytes
173+ use gimli:: Reader ;
174+ let temp = expression. 0 . to_slice ( ) . ok ( ) ;
175+ let expr_bytes = temp. as_deref ( ) . unwrap_or ( & [ ] ) ;
176+ let steps = self . parse_dwarf_expression ( expr_bytes) ?;
146177 CfaResult :: Expression { steps }
147178 }
148179 } ;
@@ -156,7 +187,7 @@ impl CfiIndex {
156187 fn find_fde_for_address (
157188 & self ,
158189 address : u64 ,
159- ) -> Result < FrameDescriptionEntry < EndianSlice < ' static , LittleEndian > , usize > > {
190+ ) -> Result < FrameDescriptionEntry < EndianSlice < ' static , LE > , usize > > {
160191 if let Some ( hdr) = & self . eh_frame_hdr {
161192 // Fast path: O(log n) binary search using eh_frame_hdr
162193 debug ! (
0 commit comments