@@ -14,7 +14,6 @@ use crate::SymbolName;
14
14
use addr2line:: gimli;
15
15
use core:: mem;
16
16
use core:: u32;
17
- use findshlibs:: { self , Segment , SharedLibrary } ;
18
17
use libc:: c_void;
19
18
use std:: convert:: TryInto ;
20
19
use std:: env;
@@ -160,8 +159,14 @@ cfg_if::cfg_if! {
160
159
Some ( self . symbols[ i] . 1 . name( & self . strtab) . ok( ) ?. as_bytes( ) )
161
160
}
162
161
}
162
+
163
+ fn native_libraries( ) -> Vec <Library > {
164
+ Vec :: new( )
165
+ }
163
166
} else if #[ cfg( target_os = "macos" ) ] {
164
167
use goblin:: mach:: MachO ;
168
+ use std:: os:: unix:: prelude:: * ;
169
+ use std:: ffi:: { OsStr , CStr } ;
165
170
166
171
struct Object <' a> {
167
172
macho: MachO <' a>,
@@ -221,8 +226,78 @@ cfg_if::cfg_if! {
221
226
Some ( sym. as_bytes( ) )
222
227
}
223
228
}
229
+
230
+ #[ allow( deprecated) ]
231
+ fn native_libraries( ) -> Vec <Library > {
232
+ let mut ret = Vec :: new( ) ;
233
+ unsafe {
234
+ for i in 0 ..libc:: _dyld_image_count( ) {
235
+ ret. extend( native_library( i) ) ;
236
+ }
237
+ }
238
+ return ret;
239
+ }
240
+
241
+ #[ allow( deprecated) ]
242
+ unsafe fn native_library( i: u32 ) -> Option <Library > {
243
+ let name = libc:: _dyld_get_image_name( i) ;
244
+ if name. is_null( ) {
245
+ return None ;
246
+ }
247
+ let name = CStr :: from_ptr( name) ;
248
+ let header = libc:: _dyld_get_image_header( i) ;
249
+ if header. is_null( ) {
250
+ return None ;
251
+ }
252
+ let mut segments = Vec :: new( ) ;
253
+ match ( * header) . magic {
254
+ libc:: MH_MAGIC => {
255
+ let mut next_cmd = header. offset( 1 ) as * const libc:: load_command;
256
+ for _ in 0 ..( * header) . ncmds {
257
+ segments. extend( segment( next_cmd) ) ;
258
+ next_cmd = ( next_cmd as usize + ( * next_cmd) . cmdsize as usize ) as * const _;
259
+ }
260
+ }
261
+ libc:: MH_MAGIC_64 => {
262
+ let header = header as * const libc:: mach_header_64;
263
+ let mut next_cmd = header. offset( 1 ) as * const libc:: load_command;
264
+ for _ in 0 ..( * header) . ncmds {
265
+ segments. extend( segment( next_cmd) ) ;
266
+ next_cmd = ( next_cmd as usize + ( * next_cmd) . cmdsize as usize ) as * const _;
267
+ }
268
+ }
269
+ _ => return None ,
270
+ }
271
+ Some ( Library {
272
+ name: OsStr :: from_bytes( name. to_bytes( ) ) . to_owned( ) ,
273
+ segments,
274
+ bias: libc:: _dyld_get_image_vmaddr_slide( i) as * const u8 ,
275
+ } )
276
+ }
277
+
278
+ unsafe fn segment( cmd: * const libc:: load_command) -> Option <LibrarySegment > {
279
+ Some ( match ( * cmd) . cmd {
280
+ libc:: LC_SEGMENT => {
281
+ let cmd = cmd as * const libc:: segment_command;
282
+ LibrarySegment {
283
+ len: ( * cmd) . vmsize as usize ,
284
+ stated_virtual_memory_address: ( * cmd) . vmaddr as * const u8 ,
285
+ }
286
+ }
287
+ libc:: LC_SEGMENT_64 => {
288
+ let cmd = cmd as * const libc:: segment_command_64;
289
+ LibrarySegment {
290
+ len: ( * cmd) . vmsize as usize ,
291
+ stated_virtual_memory_address: ( * cmd) . vmaddr as * const u8 ,
292
+ }
293
+ }
294
+ _ => return None ,
295
+ } )
296
+ }
224
297
} else {
225
298
use goblin:: elf:: Elf ;
299
+ use std:: os:: unix:: prelude:: * ;
300
+ use std:: ffi:: { OsStr , CStr } ;
226
301
227
302
struct Object <' a> {
228
303
elf: Elf <' a>,
@@ -300,6 +375,45 @@ cfg_if::cfg_if! {
300
375
}
301
376
}
302
377
}
378
+
379
+ fn native_libraries( ) -> Vec <Library > {
380
+ let mut ret = Vec :: new( ) ;
381
+ unsafe {
382
+ libc:: dl_iterate_phdr( Some ( callback) , & mut ret as * mut _ as * mut _) ;
383
+ }
384
+ return ret;
385
+ }
386
+
387
+ unsafe extern "C" fn callback(
388
+ info: * mut libc:: dl_phdr_info,
389
+ _size: libc:: size_t,
390
+ vec: * mut libc:: c_void,
391
+ ) -> libc:: c_int {
392
+ let libs = & mut * ( vec as * mut Vec <Library >) ;
393
+ let name = if ( * info) . dlpi_name. is_null( ) || * ( * info) . dlpi_name == 0 {
394
+ if libs. is_empty( ) {
395
+ std:: env:: current_exe( ) . map( |e| e. into( ) ) . unwrap_or_default( )
396
+ } else {
397
+ OsString :: new( )
398
+ }
399
+ } else {
400
+ let bytes = CStr :: from_ptr( ( * info) . dlpi_name) . to_bytes( ) ;
401
+ OsStr :: from_bytes( bytes) . to_owned( )
402
+ } ;
403
+ let headers = std:: slice:: from_raw_parts( ( * info) . dlpi_phdr, ( * info) . dlpi_phnum as usize ) ;
404
+ libs. push( Library {
405
+ name,
406
+ segments: headers
407
+ . iter( )
408
+ . map( |header| LibrarySegment {
409
+ len: ( * header) . p_memsz as usize ,
410
+ stated_virtual_memory_address: ( * header) . p_vaddr as * const u8 ,
411
+ } )
412
+ . collect( ) ,
413
+ bias: ( * info) . dlpi_addr as * const u8 ,
414
+ } ) ;
415
+ 0
416
+ }
303
417
}
304
418
}
305
419
@@ -402,12 +516,12 @@ struct Cache {
402
516
struct Library {
403
517
name : OsString ,
404
518
segments : Vec < LibrarySegment > ,
405
- bias : findshlibs :: Bias ,
519
+ bias : * const u8 ,
406
520
}
407
521
408
522
struct LibrarySegment {
409
523
len : usize ,
410
- stated_virtual_memory_address : findshlibs :: Svma ,
524
+ stated_virtual_memory_address : * const u8 ,
411
525
}
412
526
413
527
// unsafe because this is required to be externally synchronized
@@ -417,29 +531,9 @@ pub unsafe fn clear_symbol_cache() {
417
531
418
532
impl Cache {
419
533
fn new ( ) -> Cache {
420
- let mut libraries = Vec :: new ( ) ;
421
- // Iterate over all loaded shared libraries and cache information we
422
- // learn about them. This way we only load information here once instead
423
- // of once per symbol.
424
- findshlibs:: TargetSharedLibrary :: each ( |so| {
425
- use findshlibs:: IterationControl :: * ;
426
- libraries. push ( Library {
427
- name : so. name ( ) . to_owned ( ) ,
428
- segments : so
429
- . segments ( )
430
- . map ( |s| LibrarySegment {
431
- len : s. len ( ) ,
432
- stated_virtual_memory_address : s. stated_virtual_memory_address ( ) ,
433
- } )
434
- . collect ( ) ,
435
- bias : so. virtual_memory_bias ( ) ,
436
- } ) ;
437
- Continue
438
- } ) ;
439
-
440
534
Cache {
441
535
mappings : Vec :: with_capacity ( MAPPINGS_CACHE_SIZE ) ,
442
- libraries,
536
+ libraries : native_libraries ( ) ,
443
537
}
444
538
}
445
539
@@ -460,14 +554,14 @@ impl Cache {
460
554
f ( MAPPINGS_CACHE . get_or_insert_with ( || Cache :: new ( ) ) )
461
555
}
462
556
463
- fn avma_to_svma ( & self , addr : * const u8 ) -> Option < ( usize , findshlibs:: Svma ) > {
464
- // Note that for now `findshlibs` is unimplemented on Windows, so we
465
- // just unhelpfully assume that the address is an SVMA. Surprisingly it
466
- // seems to at least somewhat work on Wine on Linux though...
557
+ fn avma_to_svma ( & self , addr : * const u8 ) -> Option < ( usize , * const u8 ) > {
558
+ // Note that we don't implement iterating native libraries on Windows,
559
+ // so we just unhelpfully assume that the address is an SVMA.
560
+ // Surprisingly it seems to at least somewhat work on Wine on Linux
561
+ // though...
467
562
//
468
563
// This probably means ASLR on Windows is busted.
469
564
if cfg ! ( windows) {
470
- let addr = findshlibs:: Svma ( addr) ;
471
565
return Some ( ( usize:: max_value ( ) , addr) ) ;
472
566
}
473
567
@@ -478,24 +572,20 @@ impl Cache {
478
572
// First up, test if this `lib` has any segment containing the
479
573
// `addr` (handling relocation). If this check passes then we
480
574
// can continue below and actually translate the address.
481
- //
482
- // Note that this is an inlining of `contains_avma` in the
483
- // `findshlibs` crate here.
484
575
if !lib. segments . iter ( ) . any ( |s| {
485
- let svma = s. stated_virtual_memory_address ;
486
- let start = unsafe { svma . 0 . offset ( lib. bias . 0 ) as usize } ;
576
+ let svma = s. stated_virtual_memory_address as usize ;
577
+ let start = svma + lib. bias as usize ;
487
578
let end = start + s. len ;
488
579
let address = addr as usize ;
489
580
start <= address && address < end
490
581
} ) {
491
582
return None ;
492
583
}
493
584
494
- // Now that we know `lib` contains `addr`, do the equiavlent of
495
- // `avma_to_svma` in the `findshlibs` crate.
496
- let reverse_bias = -lib. bias . 0 ;
497
- let svma = findshlibs:: Svma ( unsafe { addr. offset ( reverse_bias) } ) ;
498
- Some ( ( i, svma) )
585
+ // Now that we know `lib` contains `addr`, we can offset with
586
+ // the bias to find the stated virutal memory address.
587
+ let svma = addr as usize - lib. bias as usize ;
588
+ Some ( ( i, svma as * const u8 ) )
499
589
} )
500
590
. next ( )
501
591
}
@@ -560,20 +650,20 @@ pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) {
560
650
Some ( cx) => cx,
561
651
None => return ,
562
652
} ;
563
- if let Ok ( mut frames) = cx. dwarf . find_frames ( addr. 0 as u64 ) {
653
+ if let Ok ( mut frames) = cx. dwarf . find_frames ( addr as u64 ) {
564
654
while let Ok ( Some ( frame) ) = frames. next ( ) {
565
655
cb. call ( Symbol :: Frame {
566
- addr : addr. 0 as * mut c_void ,
656
+ addr : addr as * mut c_void ,
567
657
location : frame. location ,
568
658
name : frame. function . map ( |f| f. name . slice ( ) ) ,
569
659
} ) ;
570
660
}
571
661
}
572
662
573
663
if !cb. called {
574
- if let Some ( name) = cx. object . search_symtab ( addr. 0 as u64 ) {
664
+ if let Some ( name) = cx. object . search_symtab ( addr as u64 ) {
575
665
cb. call ( Symbol :: Symtab {
576
- addr : addr. 0 as * mut c_void ,
666
+ addr : addr as * mut c_void ,
577
667
name,
578
668
} ) ;
579
669
}
0 commit comments