@@ -4,7 +4,7 @@ use indexmap::IndexSet;
44use std:: ops:: { Deref , DerefMut } ;
55
66use crate :: collections:: HashMap ;
7- use crate :: common:: { DebugFrameOffset , Encoding , Format , Register , SectionId } ;
7+ use crate :: common:: { DebugFrameOffset , EhFrameOffset , Encoding , Format , Register , SectionId } ;
88use crate :: constants;
99use crate :: write:: { Address , BaseId , Error , Expression , Result , Section , Writer } ;
1010
@@ -14,6 +14,8 @@ define_section!(
1414 "A writable `.debug_frame` section."
1515) ;
1616
17+ define_section ! ( EhFrame , EhFrameOffset , "A writable `.eh_frame` section." ) ;
18+
1719define_id ! ( CieId , "An identifier for a CIE in a `FrameTable`." ) ;
1820
1921/// A table of frame description entries.
@@ -36,6 +38,11 @@ impl FrameTable {
3638 CieId :: new ( self . base_id , index)
3739 }
3840
41+ /// The number of CIEs.
42+ pub fn cie_count ( & self ) -> usize {
43+ self . cies . len ( )
44+ }
45+
3946 /// Add a FDE.
4047 ///
4148 /// Does not check for duplicates.
@@ -48,8 +55,22 @@ impl FrameTable {
4855 self . fdes . push ( ( cie, fde) ) ;
4956 }
5057
51- /// Write the frame table entries to the given section.
52- pub fn write < W : Writer > ( & self , w : & mut DebugFrame < W > ) -> Result < ( ) > {
58+ /// The number of FDEs.
59+ pub fn fde_count ( & self ) -> usize {
60+ self . fdes . len ( )
61+ }
62+
63+ /// Write the frame table entries to the given `.debug_frame` section.
64+ pub fn write_debug_frame < W : Writer > ( & self , w : & mut DebugFrame < W > ) -> Result < ( ) > {
65+ self . write ( & mut w. 0 , false )
66+ }
67+
68+ /// Write the frame table entries to the given `.eh_frame` section.
69+ pub fn write_eh_frame < W : Writer > ( & self , w : & mut EhFrame < W > ) -> Result < ( ) > {
70+ self . write ( & mut w. 0 , true )
71+ }
72+
73+ fn write < W : Writer > ( & self , w : & mut W , eh_frame : bool ) -> Result < ( ) > {
5374 let mut cie_offsets = vec ! [ None ; self . cies. len( ) ] ;
5475 for ( cie_id, fde) in & self . fdes {
5576 let cie_index = cie_id. index ;
@@ -58,13 +79,13 @@ impl FrameTable {
5879 Some ( offset) => offset,
5980 None => {
6081 // Only write CIEs as they are referenced.
61- let offset = cie. write ( w) ?;
82+ let offset = cie. write ( w, eh_frame ) ?;
6283 cie_offsets[ cie_index] = Some ( offset) ;
6384 offset
6485 }
6586 } ;
6687
67- fde. write ( w, cie_offset, cie) ?;
88+ fde. write ( w, eh_frame , cie_offset, cie) ?;
6889 }
6990 // TODO: write length 0 terminator for eh_frame?
7091 Ok ( ( ) )
@@ -144,22 +165,33 @@ impl CommonInformationEntry {
144165 || self . fde_address_encoding != constants:: DW_EH_PE_absptr
145166 }
146167
147- fn write < W : Writer > ( & self , w : & mut DebugFrame < W > ) -> Result < DebugFrameOffset > {
168+ /// Returns the section offset of the CIE.
169+ fn write < W : Writer > ( & self , w : & mut W , eh_frame : bool ) -> Result < usize > {
148170 let encoding = self . encoding ;
149- let offset = w. offset ( ) ;
171+ let offset = w. len ( ) ;
150172
151173 let length_offset = w. write_initial_length ( encoding. format ) ?;
152174 let length_base = w. len ( ) ;
153175
154- match encoding. format {
155- Format :: Dwarf32 => w. write_u32 ( 0xffff_ffff ) ?,
156- Format :: Dwarf64 => w. write_u64 ( 0xffff_ffff_ffff_ffff ) ?,
176+ if eh_frame {
177+ w. write_u32 ( 0 ) ?;
178+ } else {
179+ match encoding. format {
180+ Format :: Dwarf32 => w. write_u32 ( 0xffff_ffff ) ?,
181+ Format :: Dwarf64 => w. write_u64 ( 0xffff_ffff_ffff_ffff ) ?,
182+ }
157183 }
158184
159- match encoding. version {
160- 1 | 3 | 4 => { }
161- _ => return Err ( Error :: UnsupportedVersion ( encoding. version ) ) ,
162- } ;
185+ if eh_frame {
186+ if encoding. version != 1 {
187+ return Err ( Error :: UnsupportedVersion ( encoding. version ) ) ;
188+ } ;
189+ } else {
190+ match encoding. version {
191+ 1 | 3 | 4 => { }
192+ _ => return Err ( Error :: UnsupportedVersion ( encoding. version ) ) ,
193+ } ;
194+ }
163195 w. write_u8 ( encoding. version as u8 ) ?;
164196
165197 let augmentation = self . has_augmentation ( ) ;
@@ -189,8 +221,7 @@ impl CommonInformationEntry {
189221 w. write_uleb128 ( self . code_alignment_factor . into ( ) ) ?;
190222 w. write_sleb128 ( self . data_alignment_factor . into ( ) ) ?;
191223
192- // TODO: eh_frame encoding
193- if encoding. version == 1 {
224+ if !eh_frame && encoding. version == 1 {
194225 let register = self . return_address_register . 0 as u8 ;
195226 if u16:: from ( register) != self . return_address_register . 0 {
196227 return Err ( Error :: ValueTooLarge ) ;
@@ -275,20 +306,25 @@ impl FrameDescriptionEntry {
275306
276307 fn write < W : Writer > (
277308 & self ,
278- w : & mut DebugFrame < W > ,
279- cie_offset : DebugFrameOffset ,
309+ w : & mut W ,
310+ eh_frame : bool ,
311+ cie_offset : usize ,
280312 cie : & CommonInformationEntry ,
281313 ) -> Result < ( ) > {
282314 let encoding = cie. encoding ;
283315 let length_offset = w. write_initial_length ( encoding. format ) ?;
284316 let length_base = w. len ( ) ;
285317
286- // TODO: eh_frame encoding
287- w. write_offset (
288- cie_offset. 0 ,
289- SectionId :: DebugFrame ,
290- encoding. format . word_size ( ) ,
291- ) ?;
318+ if eh_frame {
319+ // .eh_frame uses a relative offset which doesn't need relocation.
320+ w. write_word ( ( w. len ( ) - cie_offset) as u64 , 4 ) ?;
321+ } else {
322+ w. write_offset (
323+ cie_offset,
324+ SectionId :: DebugFrame ,
325+ encoding. format . word_size ( ) ,
326+ ) ?;
327+ }
292328
293329 if cie. fde_address_encoding != constants:: DW_EH_PE_absptr {
294330 w. write_eh_pointer (
@@ -379,7 +415,7 @@ pub enum CallFrameInstruction {
379415}
380416
381417impl CallFrameInstruction {
382- fn write < W : Writer > ( & self , w : & mut DebugFrame < W > , cie : & CommonInformationEntry ) -> Result < ( ) > {
418+ fn write < W : Writer > ( & self , w : & mut W , cie : & CommonInformationEntry ) -> Result < ( ) > {
383419 match * self {
384420 CallFrameInstruction :: Cfa ( register, offset) => {
385421 if offset < 0 {
@@ -490,7 +526,7 @@ impl CallFrameInstruction {
490526}
491527
492528fn write_advance_loc < W : Writer > (
493- w : & mut DebugFrame < W > ,
529+ w : & mut W ,
494530 code_alignment_factor : u8 ,
495531 prev_offset : u32 ,
496532 offset : u32 ,
@@ -514,7 +550,7 @@ fn write_advance_loc<W: Writer>(
514550 Ok ( ( ) )
515551}
516552
517- fn write_nop < W : Writer > ( w : & mut DebugFrame < W > , len : usize , align : u8 ) -> Result < ( ) > {
553+ fn write_nop < W : Writer > ( w : & mut W , len : usize , align : u8 ) -> Result < ( ) > {
518554 debug_assert_eq ! ( align & ( align - 1 ) , 0 ) ;
519555 let tail_len = ( !len + 1 ) & ( align as usize - 1 ) ;
520556 for _ in 0 ..tail_len {
@@ -548,7 +584,7 @@ fn factored_data_offset(offset: i32, factor: i8) -> Result<i32> {
548584#[ cfg( feature = "read" ) ]
549585pub ( crate ) mod convert {
550586 use super :: * ;
551- use crate :: read:: { self , Reader , UnwindSection } ;
587+ use crate :: read:: { self , Reader } ;
552588 use crate :: write:: { ConvertError , ConvertResult } ;
553589
554590 impl FrameTable {
@@ -559,11 +595,16 @@ pub(crate) mod convert {
559595 /// `Address::Constant(address)`. For relocatable addresses, it is the caller's
560596 /// responsibility to determine the symbol and addend corresponding to the address
561597 /// and return `Address::Symbol { symbol, addend }`.
562- pub fn from < R : Reader < Offset = usize > > (
563- frame : & read :: DebugFrame < R > ,
598+ pub fn from < R , Section > (
599+ frame : & Section ,
564600 convert_address : & dyn Fn ( u64 ) -> Option < Address > ,
565- ) -> ConvertResult < FrameTable > {
566- let bases = read:: BaseAddresses :: default ( ) ;
601+ ) -> ConvertResult < FrameTable >
602+ where
603+ R : Reader < Offset = usize > ,
604+ Section : read:: UnwindSection < R > ,
605+ Section :: Offset : read:: UnwindOffset < usize > ,
606+ {
607+ let bases = read:: BaseAddresses :: default ( ) . set_eh_frame ( 0 ) ;
567608
568609 let mut frame_table = FrameTable :: default ( ) ;
569610
@@ -577,7 +618,7 @@ pub(crate) mod convert {
577618
578619 // TODO: is it worth caching the parsed CIEs? It would be better if FDEs only
579620 // stored a reference.
580- let from_fde = partial. parse ( read :: DebugFrame :: cie_from_offset) ?;
621+ let from_fde = partial. parse ( Section :: cie_from_offset) ?;
581622 let from_cie = from_fde. cie ( ) ;
582623 let cie_id = match cie_ids. entry ( from_cie. offset ( ) ) {
583624 hash_map:: Entry :: Occupied ( o) => * o. get ( ) ,
@@ -598,12 +639,17 @@ pub(crate) mod convert {
598639 }
599640
600641 impl CommonInformationEntry {
601- fn from < R : Reader < Offset = usize > > (
642+ fn from < R , Section > (
602643 from_cie : & read:: CommonInformationEntry < R > ,
603- frame : & read :: DebugFrame < R > ,
644+ frame : & Section ,
604645 bases : & read:: BaseAddresses ,
605646 convert_address : & dyn Fn ( u64 ) -> Option < Address > ,
606- ) -> ConvertResult < CommonInformationEntry > {
647+ ) -> ConvertResult < CommonInformationEntry >
648+ where
649+ R : Reader < Offset = usize > ,
650+ Section : read:: UnwindSection < R > ,
651+ Section :: Offset : read:: UnwindOffset < usize > ,
652+ {
607653 let mut cie = CommonInformationEntry :: new (
608654 from_cie. encoding ( ) ,
609655 from_cie. code_alignment_factor ( ) as u8 ,
@@ -641,12 +687,17 @@ pub(crate) mod convert {
641687 }
642688
643689 impl FrameDescriptionEntry {
644- fn from < R : Reader < Offset = usize > > (
690+ fn from < R , Section > (
645691 from_fde : & read:: FrameDescriptionEntry < R > ,
646- frame : & read :: DebugFrame < R > ,
692+ frame : & Section ,
647693 bases : & read:: BaseAddresses ,
648694 convert_address : & dyn Fn ( u64 ) -> Option < Address > ,
649- ) -> ConvertResult < FrameDescriptionEntry > {
695+ ) -> ConvertResult < FrameDescriptionEntry >
696+ where
697+ R : Reader < Offset = usize > ,
698+ Section : read:: UnwindSection < R > ,
699+ Section :: Offset : read:: UnwindOffset < usize > ,
700+ {
650701 let address =
651702 convert_address ( from_fde. initial_address ( ) ) . ok_or ( ConvertError :: InvalidAddress ) ?;
652703 let length = from_fde. len ( ) as u32 ;
@@ -830,8 +881,9 @@ mod tests {
830881 fde4. lsda = Some ( Address :: Constant ( 0x4400 ) ) ;
831882 frames. add_fde ( cie2_id, fde4. clone ( ) ) ;
832883
884+ // Test writing `.debug_frame`.
833885 let mut debug_frame = DebugFrame :: from ( EndianVec :: new ( LittleEndian ) ) ;
834- frames. write ( & mut debug_frame) . unwrap ( ) ;
886+ frames. write_debug_frame ( & mut debug_frame) . unwrap ( ) ;
835887
836888 let mut read_debug_frame =
837889 read:: DebugFrame :: new ( debug_frame. slice ( ) , LittleEndian ) ;
@@ -845,6 +897,24 @@ mod tests {
845897 for ( a, b) in frames. fdes . iter ( ) . zip ( convert_frames. fdes . iter ( ) ) {
846898 assert_eq ! ( a. 1 , b. 1 ) ;
847899 }
900+
901+ if version == 1 {
902+ // Test writing `.eh_frame`.
903+ let mut eh_frame = EhFrame :: from ( EndianVec :: new ( LittleEndian ) ) ;
904+ frames. write_eh_frame ( & mut eh_frame) . unwrap ( ) ;
905+
906+ let mut read_eh_frame = read:: EhFrame :: new ( eh_frame. slice ( ) , LittleEndian ) ;
907+ read_eh_frame. set_address_size ( address_size) ;
908+ let convert_frames = FrameTable :: from ( & read_eh_frame, & |address| {
909+ Some ( Address :: Constant ( address) )
910+ } )
911+ . unwrap ( ) ;
912+ assert_eq ! ( frames. cies, convert_frames. cies) ;
913+ assert_eq ! ( frames. fdes. len( ) , convert_frames. fdes. len( ) ) ;
914+ for ( a, b) in frames. fdes . iter ( ) . zip ( convert_frames. fdes . iter ( ) ) {
915+ assert_eq ! ( a. 1 , b. 1 ) ;
916+ }
917+ }
848918 }
849919 }
850920 }
@@ -913,7 +983,7 @@ mod tests {
913983 frames. add_fde ( cie_id, fde) ;
914984
915985 let mut debug_frame = DebugFrame :: from ( EndianVec :: new ( LittleEndian ) ) ;
916- frames. write ( & mut debug_frame) . unwrap ( ) ;
986+ frames. write_debug_frame ( & mut debug_frame) . unwrap ( ) ;
917987
918988 let mut read_debug_frame =
919989 read:: DebugFrame :: new ( debug_frame. slice ( ) , LittleEndian ) ;
0 commit comments