1- use std:: { fs, io:: Cursor , path:: Path } ;
1+ use std:: { collections :: HashSet , fs, io:: Cursor , path:: Path } ;
22
33use anyhow:: { anyhow, bail, ensure, Context , Result } ;
44use byteorder:: { BigEndian , ReadBytesExt } ;
@@ -11,6 +11,7 @@ use object::{
1111
1212use crate :: {
1313 arch:: { new_arch, ObjArch } ,
14+ diff:: DiffObjConfig ,
1415 obj:: {
1516 split_meta:: { SplitMeta , SPLITMETA_SECTION } ,
1617 ObjInfo , ObjReloc , ObjSection , ObjSectionKind , ObjSymbol , ObjSymbolFlagSet , ObjSymbolFlags ,
@@ -361,7 +362,105 @@ fn line_info(obj_file: &File<'_>, sections: &mut [ObjSection]) -> Result<()> {
361362 Ok ( ( ) )
362363}
363364
364- pub fn read ( obj_path : & Path ) -> Result < ObjInfo > {
365+ fn update_combined_symbol ( symbol : ObjSymbol , address_change : i64 ) -> Result < ObjSymbol > {
366+ Ok ( ObjSymbol {
367+ name : symbol. name ,
368+ demangled_name : symbol. demangled_name ,
369+ address : ( symbol. address as i64 + address_change) . try_into ( ) ?,
370+ section_address : ( symbol. section_address as i64 + address_change) . try_into ( ) ?,
371+ size : symbol. size ,
372+ size_known : symbol. size_known ,
373+ flags : symbol. flags ,
374+ addend : symbol. addend ,
375+ virtual_address : if let Some ( virtual_address) = symbol. virtual_address {
376+ Some ( ( virtual_address as i64 + address_change) . try_into ( ) ?)
377+ } else {
378+ None
379+ } ,
380+ } )
381+ }
382+
383+ fn combine_sections ( section : ObjSection , combine : ObjSection ) -> Result < ObjSection > {
384+ let mut data = section. data ;
385+ data. extend ( combine. data ) ;
386+
387+ let address_change: i64 = ( section. address + section. size ) as i64 - combine. address as i64 ;
388+ let mut symbols = section. symbols ;
389+ for symbol in combine. symbols {
390+ symbols. push ( update_combined_symbol ( symbol, address_change) ?) ;
391+ }
392+
393+ let mut relocations = section. relocations ;
394+ for reloc in combine. relocations {
395+ relocations. push ( ObjReloc {
396+ flags : reloc. flags ,
397+ address : ( reloc. address as i64 + address_change) . try_into ( ) ?,
398+ target : reloc. target , // TODO: Should be updated?
399+ target_section : reloc. target_section , // TODO: Same as above
400+ } ) ;
401+ }
402+
403+ let mut line_info = section. line_info ;
404+ for ( addr, line) in combine. line_info {
405+ let key = ( addr as i64 + address_change) . try_into ( ) ?;
406+ line_info. insert ( key, line) ;
407+ }
408+
409+ Ok ( ObjSection {
410+ name : section. name ,
411+ kind : section. kind ,
412+ address : section. address ,
413+ size : section. size + combine. size ,
414+ data,
415+ orig_index : section. orig_index ,
416+ symbols,
417+ relocations,
418+ virtual_address : section. virtual_address ,
419+ line_info,
420+ } )
421+ }
422+
423+ fn combine_data_sections ( sections : & mut Vec < ObjSection > ) -> Result < ( ) > {
424+ let names_to_combine: HashSet < _ > = sections
425+ . iter ( )
426+ . filter ( |s| s. kind == ObjSectionKind :: Data )
427+ . map ( |s| s. name . clone ( ) )
428+ . collect ( ) ;
429+
430+ for name in names_to_combine {
431+ // Take section with lowest index
432+ let ( mut section_index, _) = sections
433+ . iter ( )
434+ . enumerate ( )
435+ . filter ( |( _, s) | s. name == name)
436+ . min_by_key ( |( _, s) | s. orig_index )
437+ // Should not happen
438+ . context ( "No combine section found with name" ) ?;
439+ let mut section = sections. remove ( section_index) ;
440+
441+ // Remove equally named sections
442+ let mut combines = vec ! [ ] ;
443+ for i in ( 0 ..sections. len ( ) ) . rev ( ) {
444+ if sections[ i] . name != name || sections[ i] . orig_index == section. orig_index {
445+ continue ;
446+ }
447+ combines. push ( sections. remove ( i) ) ;
448+ if i < section_index {
449+ section_index -= 1 ;
450+ }
451+ }
452+
453+ // Combine sections ordered by index
454+ combines. sort_unstable_by_key ( |c| c. orig_index ) ;
455+ for combine in combines {
456+ section = combine_sections ( section, combine) ?;
457+ }
458+ sections. insert ( section_index, section) ;
459+ }
460+ Ok ( ( ) )
461+ }
462+
463+ pub fn read ( obj_path : & Path , config : & DiffObjConfig ) -> Result < ObjInfo > {
365464 let ( data, timestamp) = {
366465 let file = fs:: File :: open ( obj_path) ?;
367466 let timestamp = FileTime :: from_last_modification_time ( & file. metadata ( ) ?) ;
@@ -377,6 +476,9 @@ pub fn read(obj_path: &Path) -> Result<ObjInfo> {
377476 section. relocations =
378477 relocations_by_section ( arch. as_ref ( ) , & obj_file, section, split_meta. as_ref ( ) ) ?;
379478 }
479+ if config. combine_data_sections {
480+ combine_data_sections ( & mut sections) ?;
481+ }
380482 line_info ( & obj_file, & mut sections) ?;
381483 let common = common_symbols ( arch. as_ref ( ) , & obj_file, split_meta. as_ref ( ) ) ?;
382484 Ok ( ObjInfo { arch, path : obj_path. to_owned ( ) , timestamp, sections, common, split_meta } )
0 commit comments