1313// limitations under the License.
1414
1515use gimli:: { EndianRcSlice , Endianity , RunTimeEndian , SectionId } ;
16+ use object:: { Object , ObjectSection } ;
1617
1718use binaryninja:: {
1819 binary_view:: { BinaryView , BinaryViewBase , BinaryViewExt } ,
@@ -35,6 +36,9 @@ pub enum Error {
3536
3637 #[ error( "{0}" ) ]
3738 IoError ( #[ from] std:: io:: Error ) ,
39+
40+ #[ error( "{0}" ) ]
41+ ObjectError ( #[ from] object:: Error ) ,
3842}
3943
4044pub fn is_non_dwo_dwarf ( view : & BinaryView ) -> bool {
@@ -89,105 +93,80 @@ pub fn get_endian(view: &BinaryView) -> RunTimeEndian {
8993 }
9094}
9195
92- pub fn create_section_reader < ' a , Endian : ' a + Endianity > (
96+ pub fn create_section_reader < Endian : Endianity > (
9397 section_id : SectionId ,
94- view : & ' a BinaryView ,
98+ view : & BinaryView ,
9599 endian : Endian ,
96- dwo_file : bool ,
97- ) -> Result < EndianRcSlice < Endian > , Error > {
98- let section_name = if dwo_file && section_id. dwo_name ( ) . is_some ( ) {
99- section_id. dwo_name ( ) . unwrap ( )
100- } else {
101- section_id. name ( )
102- } ;
100+ is_dwo : bool ,
101+ ) -> Result < RelocateOwned < gimli:: EndianRcSlice < Endian > > , Error > {
102+ let view_data = view. read_vec ( 0 , view. len ( ) as usize ) ;
103+ let file = object:: File :: parse ( & * view_data) ?;
104+ load_file_section ( section_id, & file, endian, is_dwo)
105+ }
106+
107+ #[ derive( Debug , Clone ) ]
108+ pub struct RelocationMap ( Rc < object:: read:: RelocationMap > ) ;
103109
104- if let Some ( section) = view. section_by_name ( section_name) {
105- // TODO : This is kinda broke....should add rust wrappers for some of this
106- if let Some ( symbol) = view
107- . symbols ( )
108- . iter ( )
109- . find ( |symbol| symbol. full_name ( ) . to_string_lossy ( ) == "__elf_section_headers" )
110- {
111- if let Some ( data_var) = view
112- . data_variables ( )
113- . iter ( )
114- . find ( |var| var. address == symbol. address ( ) )
115- {
116- // TODO : This should eventually be wrapped by some DataView sorta thingy thing, like how python does it
117- let data_type = & data_var. ty . contents ;
118- let data = view. read_vec ( data_var. address , data_type. width ( ) as usize ) ;
119- let element_type = data_type. element_type ( ) . unwrap ( ) . contents ;
120-
121- if let Some ( current_section_header) = data
122- . chunks ( element_type. width ( ) as usize )
123- . find ( |section_header| {
124- if view. address_size ( ) == 4 {
125- endian. read_u32 ( & section_header[ 16 ..20 ] ) as u64 == section. start ( )
126- } else {
127- endian. read_u64 ( & section_header[ 24 ..32 ] ) == section. start ( )
128- }
129- } )
130- {
131- let section_flags = if view. address_size ( ) == 4 {
132- endian. read_u32 ( & current_section_header[ 8 ..12 ] ) as u64
133- } else {
134- endian. read_u64 ( & current_section_header[ 8 ..16 ] )
135- } ;
136- // If the section has the compressed bit set
137- if ( section_flags & 2048 ) != 0 {
138- // Get section, trim header, decompress, return
139- let compressed_header_size = view. address_size ( ) * 3 ;
140-
141- let offset = section. start ( ) + compressed_header_size as u64 ;
142- let len = section. len ( ) - compressed_header_size;
143-
144- let ch_type_vec = view. read_vec ( section. start ( ) , 4 ) ;
145- let ch_type = endian. read_u32 ( & ch_type_vec) ;
146-
147- if let Ok ( buffer) = view. read_buffer ( offset, len) {
148- match ch_type {
149- 1 => {
150- return Ok ( EndianRcSlice :: new (
151- buffer. zlib_decompress ( ) . get_data ( ) . into ( ) ,
152- endian,
153- ) ) ;
154- }
155- 2 => {
156- return Ok ( EndianRcSlice :: new (
157- zstd:: decode_all ( buffer. get_data ( ) ) ?. as_slice ( ) . into ( ) ,
158- endian,
159- ) ) ;
160- }
161- x => {
162- return Err ( Error :: UnknownCompressionMethod ( x) ) ;
163- }
164- }
165- }
166- }
167- }
110+ impl Default for RelocationMap {
111+ fn default ( ) -> Self {
112+ Self ( Rc :: new ( object:: read:: RelocationMap :: default ( ) ) )
113+ }
114+ }
115+
116+ impl RelocationMap {
117+ fn add ( & mut self , file : & object:: File , section : & object:: Section ) {
118+ let map = Rc :: get_mut ( & mut self . 0 )
119+ . expect ( "RelocationMap should have exclusive access during construction" ) ;
120+ for ( offset, relocation) in section. relocations ( ) {
121+ if let Err ( e) = map. add ( file, offset, relocation) {
122+ eprintln ! (
123+ "Relocation error for section {} at offset 0x{:08x}: {}" ,
124+ section. name( ) . unwrap( ) ,
125+ offset,
126+ e
127+ ) ;
168128 }
169129 }
170- let offset = section. start ( ) ;
171- let len = section. len ( ) ;
172- if len == 0 {
173- Ok ( EndianRcSlice :: new ( Rc :: from ( [ ] ) , endian) )
174- } else {
175- Ok ( EndianRcSlice :: new (
176- Rc :: from ( view. read_vec ( offset, len) . as_slice ( ) ) ,
177- endian,
178- ) )
179- }
180130 }
181- // Truncate Mach-O section names to 16 bytes
182- else if let Some ( section) = view. section_by_name ( & format ! (
183- "__{}" ,
184- & section_name[ 1 ..section_name. len( ) . min( 15 ) ]
185- ) ) {
186- Ok ( EndianRcSlice :: new (
187- Rc :: from ( view. read_vec ( section. start ( ) , section. len ( ) ) . as_slice ( ) ) ,
188- endian,
189- ) )
190- } else {
191- Ok ( EndianRcSlice :: new ( Rc :: from ( [ ] ) , endian) )
131+ }
132+
133+ impl gimli:: read:: Relocate for RelocationMap {
134+ fn relocate_address ( & self , offset : usize , value : u64 ) -> gimli:: Result < u64 > {
135+ Ok ( self . 0 . relocate ( offset as u64 , value) )
136+ }
137+
138+ fn relocate_offset ( & self , offset : usize , value : usize ) -> gimli:: Result < usize > {
139+ <usize as gimli:: ReaderOffset >:: from_u64 ( self . 0 . relocate ( offset as u64 , value as u64 ) )
192140 }
193141}
142+
143+ type RelocateOwned < R > = gimli:: RelocateReader < R , RelocationMap > ;
144+
145+ pub fn load_file_section < Endian : gimli:: Endianity > (
146+ id : gimli:: SectionId ,
147+ file : & object:: File ,
148+ endian : Endian ,
149+ is_dwo : bool ,
150+ ) -> Result < RelocateOwned < gimli:: EndianRcSlice < Endian > > , Error > {
151+ let mut relocations = RelocationMap :: default ( ) ;
152+ let name = if is_dwo {
153+ id. dwo_name ( )
154+ } else if file. format ( ) == object:: BinaryFormat :: Xcoff {
155+ id. xcoff_name ( )
156+ } else {
157+ Some ( id. name ( ) )
158+ } ;
159+ let data = match name. and_then ( |name| file. section_by_name ( name) ) {
160+ Some ( ref section) => {
161+ // DWO sections never have relocations, so don't bother.
162+ if !is_dwo {
163+ relocations. add ( file, section) ;
164+ }
165+ section. uncompressed_data ( ) ?. into_owned ( )
166+ }
167+ // Use a non-zero capacity so that `ReaderOffsetId`s are unique.
168+ None => Vec :: with_capacity ( 1 ) ,
169+ } ;
170+ let section = EndianRcSlice :: new ( Rc :: from ( data. into_boxed_slice ( ) ) , endian) ;
171+ Ok ( gimli:: RelocateReader :: new ( section, relocations) )
172+ }
0 commit comments