@@ -6,51 +6,62 @@ use super::mystd::borrow::ToOwned;
66use super :: mystd:: env;
77use super :: mystd:: ffi:: { CStr , OsStr } ;
88use super :: mystd:: os:: unix:: prelude:: * ;
9- use super :: { Library , LibrarySegment , OsString , Vec } ;
9+ use super :: { parse_running_mmaps , Library , LibrarySegment , OsString , Vec } ;
1010use core:: slice;
1111
12+ struct CallbackData {
13+ libs : Vec < Library > ,
14+ maps : Option < Vec < parse_running_mmaps:: MapsEntry > > ,
15+ }
1216pub ( super ) fn native_libraries ( ) -> Vec < Library > {
13- let mut ret = Vec :: new ( ) ;
17+ let mut cb_data = CallbackData {
18+ libs : Vec :: new ( ) ,
19+ #[ cfg( not( target_os = "hurd" ) ) ]
20+ maps : parse_running_mmaps:: parse_maps ( ) . ok ( ) ,
21+ #[ cfg( target_os = "hurd" ) ]
22+ maps : None ,
23+ } ;
1424 unsafe {
15- libc:: dl_iterate_phdr ( Some ( callback) , core:: ptr:: addr_of_mut!( ret ) . cast ( ) ) ;
25+ libc:: dl_iterate_phdr ( Some ( callback) , core:: ptr:: addr_of_mut!( cb_data ) . cast ( ) ) ;
1626 }
17- ret
27+ cb_data . libs
1828}
1929
20- fn infer_current_exe ( base_addr : usize ) -> OsString {
21- cfg_if :: cfg_if! {
22- if # [ cfg ( not ( target_os = "hurd" ) ) ] {
23- if let Ok ( entries ) = super :: parse_running_mmaps :: parse_maps ( ) {
24- let opt_path = entries
25- . iter ( )
26- . find ( |e| e . ip_matches ( base_addr ) && e . pathname ( ) . len ( ) > 0 )
27- . map ( |e| e . pathname ( ) )
28- . cloned ( ) ;
29- if let Some ( path ) = opt_path {
30- return path ;
31- }
32- }
30+ fn infer_current_exe (
31+ maps : & Option < Vec < parse_running_mmaps :: MapsEntry > > ,
32+ base_addr : usize ,
33+ ) -> OsString {
34+ # [ cfg ( not ( target_os = "hurd" ) ) ]
35+ if let Some ( entries ) = maps {
36+ let opt_path = entries
37+ . iter ( )
38+ . find ( |e| e . ip_matches ( base_addr ) && e . pathname ( ) . len ( ) > 0 )
39+ . map ( |e| e . pathname ( ) )
40+ . cloned ( ) ;
41+ if let Some ( path ) = opt_path {
42+ return path ;
3343 }
3444 }
45+
3546 env:: current_exe ( ) . map ( |e| e. into ( ) ) . unwrap_or_default ( )
3647}
3748
3849/// # Safety
3950/// `info` must be a valid pointer.
40- /// `vec ` must be a valid pointer to `Vec<Library>`
51+ /// `data ` must be a valid pointer to `CallbackData`.
4152#[ forbid( unsafe_op_in_unsafe_fn) ]
4253unsafe extern "C" fn callback (
4354 info : * mut libc:: dl_phdr_info ,
4455 _size : libc:: size_t ,
45- vec : * mut libc:: c_void ,
56+ data : * mut libc:: c_void ,
4657) -> libc:: c_int {
4758 // SAFETY: We are guaranteed these fields:
4859 let dlpi_addr = unsafe { ( * info) . dlpi_addr } ;
4960 let dlpi_name = unsafe { ( * info) . dlpi_name } ;
5061 let dlpi_phdr = unsafe { ( * info) . dlpi_phdr } ;
5162 let dlpi_phnum = unsafe { ( * info) . dlpi_phnum } ;
5263 // SAFETY: We assured this.
53- let libs = unsafe { & mut * vec . cast :: < Vec < Library > > ( ) } ;
64+ let CallbackData { libs, maps } = unsafe { & mut * data . cast :: < CallbackData > ( ) } ;
5465 // most implementations give us the main program first
5566 let is_main = libs. is_empty ( ) ;
5667 // we may be statically linked, which means we are main and mostly one big blob of code
@@ -63,7 +74,7 @@ unsafe extern "C" fn callback(
6374 // don't try to look up our name from /proc/self/maps, it'll get silly
6475 env:: current_exe ( ) . unwrap_or_default ( ) . into_os_string ( )
6576 } else if is_main && no_given_name {
66- infer_current_exe ( dlpi_addr as usize )
77+ infer_current_exe ( & maps , dlpi_addr as usize )
6778 } else {
6879 // this fallback works even if we are main, because some platforms give the name anyways
6980 if dlpi_name. is_null ( ) {
@@ -73,6 +84,19 @@ unsafe extern "C" fn callback(
7384 OsStr :: from_bytes ( unsafe { CStr :: from_ptr ( dlpi_name) } . to_bytes ( ) ) . to_owned ( )
7485 }
7586 } ;
87+ #[ cfg( target_os = "android" ) ]
88+ let zip_offset: Option < u64 > = {
89+ // only check for ZIP-embedded file if we have data from /proc/self/maps
90+ maps. as_ref ( ) . and_then ( |maps| {
91+ // check if file is embedded within a ZIP archive by searching for `!/`
92+ super :: extract_zip_path_android ( & name) . and_then ( |_| {
93+ // find MapsEntry matching library's base address and get its file offset
94+ maps. iter ( )
95+ . find ( |m| m. ip_matches ( dlpi_addr as usize ) )
96+ . map ( |m| m. offset ( ) )
97+ } )
98+ } )
99+ } ;
76100 let headers = if dlpi_phdr. is_null ( ) || dlpi_phnum == 0 {
77101 & [ ]
78102 } else {
@@ -81,6 +105,8 @@ unsafe extern "C" fn callback(
81105 } ;
82106 libs. push ( Library {
83107 name,
108+ #[ cfg( target_os = "android" ) ]
109+ zip_offset,
84110 segments : headers
85111 . iter ( )
86112 . map ( |header| LibrarySegment {
0 commit comments