@@ -176,6 +176,7 @@ cfg_if::cfg_if! {
176176 use std:: os:: unix:: prelude:: * ;
177177 use std:: ffi:: { OsStr , CStr } ;
178178 use object:: { Bytes , NativeEndian } ;
179+ use object:: macho;
179180 use object:: read:: macho:: { MachHeader , Section , Segment as _, Nlist } ;
180181
181182 #[ cfg( target_pointer_width = "32" ) ]
@@ -248,71 +249,145 @@ cfg_if::cfg_if! {
248249 }
249250 }
250251
252+ fn find_header( mut data: Bytes <' _>) -> Option <( & ' _ Mach , Bytes <' _>) > {
253+ use object:: endian:: BigEndian ;
254+
255+ let desired_cpu = || {
256+ if cfg!( target_arch = "x86" ) {
257+ Some ( macho:: CPU_TYPE_X86 )
258+ } else if cfg!( target_arch = "x86_64" ) {
259+ Some ( macho:: CPU_TYPE_X86_64 )
260+ } else if cfg!( target_arch = "arm" ) {
261+ Some ( macho:: CPU_TYPE_ARM )
262+ } else if cfg!( target_arch = "aarch64" ) {
263+ Some ( macho:: CPU_TYPE_ARM64 )
264+ } else {
265+ None
266+ }
267+ } ;
268+
269+ match data. clone( ) . read:: <object:: endian:: U32 <NativeEndian >>( ) . ok( ) ?. get( NativeEndian ) {
270+ macho:: MH_MAGIC_64
271+ | macho:: MH_CIGAM_64
272+ | macho:: MH_MAGIC
273+ | macho:: MH_CIGAM => { }
274+
275+ macho:: FAT_MAGIC | macho:: FAT_CIGAM => {
276+ let mut header_data = data;
277+ let endian = BigEndian ;
278+ let header = header_data. read:: <macho:: FatHeader >( ) . ok( ) ?;
279+ let nfat = header. nfat_arch. get( endian) ;
280+ let arch = ( 0 ..nfat)
281+ . filter_map( |_| header_data. read:: <macho:: FatArch32 >( ) . ok( ) )
282+ . find( |arch| desired_cpu( ) == Some ( arch. cputype. get( endian) ) ) ?;
283+ let offset = arch. offset. get( endian) ;
284+ let size = arch. size. get( endian) ;
285+ data = data. read_bytes_at(
286+ offset. try_into( ) . ok( ) ?,
287+ size. try_into( ) . ok( ) ?,
288+ ) . ok( ) ?;
289+ }
290+
291+ macho:: FAT_MAGIC_64 | macho:: FAT_CIGAM_64 => {
292+ let mut header_data = data;
293+ let endian = BigEndian ;
294+ let header = header_data. read:: <macho:: FatHeader >( ) . ok( ) ?;
295+ let nfat = header. nfat_arch. get( endian) ;
296+ let arch = ( 0 ..nfat)
297+ . filter_map( |_| header_data. read:: <macho:: FatArch64 >( ) . ok( ) )
298+ . find( |arch| desired_cpu( ) == Some ( arch. cputype. get( endian) ) ) ?;
299+ let offset = arch. offset. get( endian) ;
300+ let size = arch. size. get( endian) ;
301+ data = data. read_bytes_at(
302+ offset. try_into( ) . ok( ) ?,
303+ size. try_into( ) . ok( ) ?,
304+ ) . ok( ) ?;
305+ }
306+
307+ _ => return None ,
308+ }
309+
310+ Mach :: parse( data) . ok( ) . map( |h| ( h, data) )
311+ }
312+
251313 #[ allow( deprecated) ]
252314 fn native_libraries( ) -> Vec <Library > {
253315 let mut ret = Vec :: new( ) ;
254- unsafe {
255- for i in 0 ..libc:: _dyld_image_count( ) {
256- ret. extend( native_library( i) ) ;
257- }
316+ let images = unsafe { libc:: _dyld_image_count( ) } ;
317+ for i in 0 ..images {
318+ ret. extend( native_library( i) ) ;
258319 }
259320 return ret;
260321 }
261322
262323 #[ allow( deprecated) ]
263- unsafe fn native_library( i: u32 ) -> Option <Library > {
264- let name = libc:: _dyld_get_image_name( i) ;
265- if name. is_null( ) {
266- return None ;
267- }
268- let name = CStr :: from_ptr( name) ;
269- let header = libc:: _dyld_get_image_header( i) ;
270- if header. is_null( ) {
271- return None ;
272- }
273- let mut segments = Vec :: new( ) ;
274- match ( * header) . magic {
275- libc:: MH_MAGIC => {
276- let mut next_cmd = header. offset( 1 ) as * const libc:: load_command;
277- for _ in 0 ..( * header) . ncmds {
278- segments. extend( segment( next_cmd) ) ;
279- next_cmd = ( next_cmd as usize + ( * next_cmd) . cmdsize as usize ) as * const _;
280- }
324+ fn native_library( i: u32 ) -> Option <Library > {
325+ // Fetch the name of this library which corresponds to the path of
326+ // where to load it as well.
327+ let name = unsafe {
328+ let name = libc:: _dyld_get_image_name( i) ;
329+ if name. is_null( ) {
330+ return None ;
281331 }
282- libc:: MH_MAGIC_64 => {
283- let header = header as * const libc:: mach_header_64;
284- let mut next_cmd = header. offset( 1 ) as * const libc:: load_command;
285- for _ in 0 ..( * header) . ncmds {
286- segments. extend( segment( next_cmd) ) ;
287- next_cmd = ( next_cmd as usize + ( * next_cmd) . cmdsize as usize ) as * const _;
332+ CStr :: from_ptr( name)
333+ } ;
334+
335+ // Load the image header of this library and delegate to `object` to
336+ // parse all the load commands so we can figure out all the segments
337+ // involved here.
338+ let ( mut load_commands, endian) = unsafe {
339+ let header = libc:: _dyld_get_image_header( i) ;
340+ if header. is_null( ) {
341+ return None ;
342+ }
343+ match ( * header) . magic {
344+ macho:: MH_MAGIC => {
345+ let endian = NativeEndian ;
346+ let header = & * ( header as * const macho:: MachHeader32 <NativeEndian >) ;
347+ let data = core:: slice:: from_raw_parts(
348+ header as * const _ as * const u8 ,
349+ mem:: size_of_val( header) + header. sizeofcmds. get( endian) as usize
350+ ) ;
351+ ( header. load_commands( endian, Bytes ( data) ) . ok( ) ?, endian)
352+ }
353+ macho:: MH_MAGIC_64 => {
354+ let endian = NativeEndian ;
355+ let header = & * ( header as * const macho:: MachHeader64 <NativeEndian >) ;
356+ let data = core:: slice:: from_raw_parts(
357+ header as * const _ as * const u8 ,
358+ mem:: size_of_val( header) + header. sizeofcmds. get( endian) as usize
359+ ) ;
360+ ( header. load_commands( endian, Bytes ( data) ) . ok( ) ?, endian)
288361 }
362+ _ => return None ,
363+ }
364+ } ;
365+
366+ // Iterate over the segments and register known regions for segments
367+ // that we find. Additionally record information bout text segments
368+ // for processing later, see comments below.
369+ let mut segments = Vec :: new( ) ;
370+ while let Some ( cmd) = load_commands. next( ) . ok( ) ? {
371+ if let Some ( ( seg, _) ) = cmd. segment_32( ) . ok( ) ? {
372+ segments. push( LibrarySegment {
373+ len: seg. vmsize( endian) . try_into( ) . ok( ) ?,
374+ stated_virtual_memory_address: seg. vmaddr( endian) as * const u8 ,
375+ } ) ;
376+ }
377+ if let Some ( ( seg, _) ) = cmd. segment_64( ) . ok( ) ? {
378+ segments. push( LibrarySegment {
379+ len: seg. vmsize( endian) . try_into( ) . ok( ) ?,
380+ stated_virtual_memory_address: seg. vmaddr( endian) as * const u8 ,
381+ } ) ;
289382 }
290- _ => return None ,
291383 }
384+ let slide = unsafe {
385+ libc:: _dyld_get_image_vmaddr_slide( i)
386+ } ;
292387 Some ( Library {
293388 name: OsStr :: from_bytes( name. to_bytes( ) ) . to_owned( ) ,
294389 segments,
295- bias: libc:: _dyld_get_image_vmaddr_slide( i) as * const u8 ,
296- } )
297- }
298-
299- unsafe fn segment( cmd: * const libc:: load_command) -> Option <LibrarySegment > {
300- Some ( match ( * cmd) . cmd {
301- libc:: LC_SEGMENT => {
302- let cmd = cmd as * const libc:: segment_command;
303- LibrarySegment {
304- len: ( * cmd) . vmsize as usize ,
305- stated_virtual_memory_address: ( * cmd) . vmaddr as * const u8 ,
306- }
307- }
308- libc:: LC_SEGMENT_64 => {
309- let cmd = cmd as * const libc:: segment_command_64;
310- LibrarySegment {
311- len: ( * cmd) . vmsize as usize ,
312- stated_virtual_memory_address: ( * cmd) . vmaddr as * const u8 ,
313- }
314- }
315- _ => return None ,
390+ bias: slide as * const u8 ,
316391 } )
317392 }
318393 } else {
@@ -476,8 +551,7 @@ impl Mapping {
476551 // First up we need to load the unique UUID which is stored in the macho
477552 // header of the file we're reading, specified at `path`.
478553 let map = mmap ( path) ?;
479- let data = Bytes ( & map) ;
480- let macho = Mach :: parse ( data) . ok ( ) ?;
554+ let ( macho, data) = find_header ( Bytes ( & map) ) ?;
481555 let endian = macho. endian ( ) . ok ( ) ?;
482556 let uuid = macho. uuid ( endian, data) . ok ( ) ??;
483557
@@ -513,8 +587,7 @@ impl Mapping {
513587 for entry in dir. read_dir ( ) . ok ( ) ? {
514588 let entry = entry. ok ( ) ?;
515589 let map = mmap ( & entry. path ( ) ) ?;
516- let data = Bytes ( & map) ;
517- let macho = Mach :: parse ( data) . ok ( ) ?;
590+ let ( macho, data) = find_header ( Bytes ( & map) ) ?;
518591 let endian = macho. endian ( ) . ok ( ) ?;
519592 let entry_uuid = macho. uuid ( endian, data) . ok ( ) ??;
520593 if entry_uuid != uuid {
0 commit comments