@@ -13,6 +13,7 @@ use std::path::{Path, PathBuf};
1313use std:: slice:: from_raw_parts;
1414
1515#[ repr( C , packed) ]
16+ #[ derive( Copy , Clone ) ]
1617struct ElfHeader32 {
1718 ident_magic : u32 ,
1819 ident_class : u8 ,
@@ -48,6 +49,7 @@ struct ElfSymbol64 {
4849}
4950
5051#[ repr( C , packed) ]
52+ #[ derive( Copy , Clone ) ]
5153struct ElfSectionHeader64 {
5254 name : u32 ,
5355 type_ : u32 ,
@@ -62,6 +64,7 @@ struct ElfSectionHeader64 {
6264}
6365
6466#[ repr( C , packed) ]
67+ #[ derive( Copy , Clone ) ]
6568struct ElfProgramHeader64 {
6669 type_ : u32 ,
6770 flags : u32 ,
@@ -74,6 +77,7 @@ struct ElfProgramHeader64 {
7477}
7578
7679#[ repr( C , packed) ]
80+ #[ derive( Copy , Clone ) ]
7781struct ElfHeader64 {
7882 ident_magic : u32 ,
7983 ident_class : u8 ,
@@ -186,6 +190,30 @@ pub struct ElfFile {
186190
187191impl ElfFile {
188192 pub fn from_path ( path : & Path ) -> Result < ElfFile , String > {
193+ let reader = ElfFileReader :: from_path ( path) ?;
194+ let segments = reader. segments ( ) ?;
195+ let symbols = reader. symbols ( ) ?;
196+ Ok ( ElfFile {
197+ path : path. to_owned ( ) ,
198+ word_size : reader. word_size ,
199+ entry : reader. hdr . entry ,
200+ machine : reader. hdr . machine ,
201+ segments,
202+ symbols,
203+ } )
204+ }
205+ }
206+
207+ #[ derive( Clone ) ]
208+ struct ElfFileReader < ' a > {
209+ path : & ' a Path ,
210+ bytes : Vec < u8 > ,
211+ word_size : usize ,
212+ hdr : ElfHeader64 ,
213+ }
214+
215+ impl < ' a > ElfFileReader < ' a > {
216+ fn from_path ( path : & ' a Path ) -> Result < Self , String > {
189217 let bytes = match fs:: read ( path) {
190218 Ok ( bytes) => bytes,
191219 Err ( err) => return Err ( format ! ( "Failed to read ELF '{}': {}" , path. display( ) , err) ) ,
@@ -228,7 +256,7 @@ impl ElfFile {
228256
229257 // Now need to read the header into a struct
230258 let hdr_bytes = & bytes[ ..hdr_size] ;
231- let hdr = unsafe { bytes_to_struct :: < ElfHeader64 > ( hdr_bytes) } ;
259+ let hdr = * unsafe { bytes_to_struct :: < ElfHeader64 > ( hdr_bytes) } ;
232260
233261 // We have checked this above but we should check again once we actually cast it to
234262 // a struct.
@@ -242,18 +270,30 @@ impl ElfFile {
242270 ) ) ;
243271 }
244272
245- let entry = hdr. entry ;
273+ Ok ( Self {
274+ path,
275+ bytes,
276+ word_size,
277+ hdr,
278+ } )
279+ }
280+
281+ fn segments ( & self ) -> Result < Vec < ElfSegment > , String > {
282+ let hdr = & self . hdr ;
246283
247284 // Read all the segments
248285 if hdr. phnum == 0 {
249- return Err ( format ! ( "ELF '{}': has no program headers" , path. display( ) ) ) ;
286+ return Err ( format ! (
287+ "ELF '{}': has no program headers" ,
288+ self . path. display( )
289+ ) ) ;
250290 }
251291
252292 let mut segments = Vec :: with_capacity ( hdr. phnum as usize ) ;
253293 for i in 0 ..hdr. phnum {
254294 let phent_start = hdr. phoff + ( i * hdr. phentsize ) as u64 ;
255295 let phent_end = phent_start + ( hdr. phentsize as u64 ) ;
256- let phent_bytes = & bytes[ phent_start as usize ..phent_end as usize ] ;
296+ let phent_bytes = & self . bytes [ phent_start as usize ..phent_end as usize ] ;
257297
258298 let phent = unsafe { bytes_to_struct :: < ElfProgramHeader64 > ( phent_bytes) } ;
259299
@@ -266,7 +306,7 @@ impl ElfFile {
266306
267307 let mut segment_data_bytes = vec ! [ 0 ; phent. memsz as usize ] ;
268308 segment_data_bytes[ ..phent. filesz as usize ]
269- . copy_from_slice ( & bytes[ segment_start..segment_end] ) ;
309+ . copy_from_slice ( & self . bytes [ segment_start..segment_end] ) ;
270310
271311 let segment_data = ElfSegmentData :: RealData ( segment_data_bytes) ;
272312
@@ -282,14 +322,20 @@ impl ElfFile {
282322 segments. push ( segment)
283323 }
284324
325+ Ok ( segments)
326+ }
327+
328+ fn symbols ( & self ) -> Result < HashMap < String , ( ElfSymbol64 , bool ) > , String > {
329+ let hdr = & self . hdr ;
330+
285331 // Read all the section headers
286332 let mut shents = Vec :: with_capacity ( hdr. shnum as usize ) ;
287333 let mut symtab_shent: Option < & ElfSectionHeader64 > = None ;
288334 let mut shstrtab_shent: Option < & ElfSectionHeader64 > = None ;
289335 for i in 0 ..hdr. shnum {
290336 let shent_start = hdr. shoff + ( i as u64 * hdr. shentsize as u64 ) ;
291337 let shent_end = shent_start + hdr. shentsize as u64 ;
292- let shent_bytes = & bytes[ shent_start as usize ..shent_end as usize ] ;
338+ let shent_bytes = & self . bytes [ shent_start as usize ..shent_end as usize ] ;
293339
294340 let shent = unsafe { bytes_to_struct :: < ElfSectionHeader64 > ( shent_bytes) } ;
295341 match shent. type_ {
@@ -303,27 +349,27 @@ impl ElfFile {
303349 if shstrtab_shent. is_none ( ) {
304350 return Err ( format ! (
305351 "ELF '{}': unable to find string table section" ,
306- path. display( )
352+ self . path. display( )
307353 ) ) ;
308354 }
309355
310356 assert ! ( symtab_shent. is_some( ) ) ;
311357 if symtab_shent. is_none ( ) {
312358 return Err ( format ! (
313359 "ELF '{}': unable to find symbol table section" ,
314- path. display( )
360+ self . path. display( )
315361 ) ) ;
316362 }
317363
318364 // Reading the symbol table
319365 let symtab_start = symtab_shent. unwrap ( ) . offset as usize ;
320366 let symtab_end = symtab_start + symtab_shent. unwrap ( ) . size as usize ;
321- let symtab = & bytes[ symtab_start..symtab_end] ;
367+ let symtab = & self . bytes [ symtab_start..symtab_end] ;
322368
323369 let symtab_str_shent = shents[ symtab_shent. unwrap ( ) . link as usize ] ;
324370 let symtab_str_start = symtab_str_shent. offset as usize ;
325371 let symtab_str_end = symtab_str_start + symtab_str_shent. size as usize ;
326- let symtab_str = & bytes[ symtab_str_start..symtab_str_end] ;
372+ let symtab_str = & self . bytes [ symtab_str_start..symtab_str_end] ;
327373
328374 // Read all the symbols
329375 let mut symbols: HashMap < String , ( ElfSymbol64 , bool ) > = HashMap :: new ( ) ;
@@ -355,16 +401,11 @@ impl ElfFile {
355401 offset += symbol_size;
356402 }
357403
358- Ok ( ElfFile {
359- path : path. to_owned ( ) ,
360- word_size,
361- entry,
362- machine : hdr. machine ,
363- segments,
364- symbols,
365- } )
404+ Ok ( symbols)
366405 }
406+ }
367407
408+ impl ElfFile {
368409 pub fn find_symbol ( & self , variable_name : & str ) -> Result < ( u64 , u64 ) , String > {
369410 if let Some ( ( sym, duplicate) ) = self . symbols . get ( variable_name) {
370411 if * duplicate {
@@ -401,7 +442,9 @@ impl ElfFile {
401442
402443 None
403444 }
445+ }
404446
447+ impl < ' a > ElfFileReader < ' a > {
405448 fn get_string ( strtab : & [ u8 ] , idx : usize ) -> Result < & str , String > {
406449 match strtab[ idx..] . iter ( ) . position ( |& b| b == 0 ) {
407450 Some ( null_byte_pos) => {
@@ -418,7 +461,9 @@ impl ElfFile {
418461 ) ) ,
419462 }
420463 }
464+ }
421465
466+ impl ElfFile {
422467 pub fn lowest_vaddr ( & self ) -> u64 {
423468 // This unwrap is safe as we have ensured that there will always be at least 1 segment when parsing the ELF.
424469 let existing_vaddrs: Vec < u64 > = self
0 commit comments