@@ -6,51 +6,62 @@ use super::mystd::borrow::ToOwned;
6
6
use super :: mystd:: env;
7
7
use super :: mystd:: ffi:: { CStr , OsStr } ;
8
8
use super :: mystd:: os:: unix:: prelude:: * ;
9
- use super :: { Library , LibrarySegment , OsString , Vec } ;
9
+ use super :: { parse_running_mmaps , Library , LibrarySegment , OsString , Vec } ;
10
10
use core:: slice;
11
11
12
+ struct CallbackData {
13
+ libs : Vec < Library > ,
14
+ maps : Option < Vec < parse_running_mmaps:: MapsEntry > > ,
15
+ }
12
16
pub ( 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
+ } ;
14
24
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 ( ) ) ;
16
26
}
17
- ret
27
+ cb_data . libs
18
28
}
19
29
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 ;
33
43
}
34
44
}
45
+
35
46
env:: current_exe ( ) . map ( |e| e. into ( ) ) . unwrap_or_default ( )
36
47
}
37
48
38
49
/// # Safety
39
50
/// `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`.
41
52
#[ forbid( unsafe_op_in_unsafe_fn) ]
42
53
unsafe extern "C" fn callback (
43
54
info : * mut libc:: dl_phdr_info ,
44
55
_size : libc:: size_t ,
45
- vec : * mut libc:: c_void ,
56
+ data : * mut libc:: c_void ,
46
57
) -> libc:: c_int {
47
58
// SAFETY: We are guaranteed these fields:
48
59
let dlpi_addr = unsafe { ( * info) . dlpi_addr } ;
49
60
let dlpi_name = unsafe { ( * info) . dlpi_name } ;
50
61
let dlpi_phdr = unsafe { ( * info) . dlpi_phdr } ;
51
62
let dlpi_phnum = unsafe { ( * info) . dlpi_phnum } ;
52
63
// SAFETY: We assured this.
53
- let libs = unsafe { & mut * vec . cast :: < Vec < Library > > ( ) } ;
64
+ let CallbackData { libs, maps } = unsafe { & mut * data . cast :: < CallbackData > ( ) } ;
54
65
// most implementations give us the main program first
55
66
let is_main = libs. is_empty ( ) ;
56
67
// 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(
63
74
// don't try to look up our name from /proc/self/maps, it'll get silly
64
75
env:: current_exe ( ) . unwrap_or_default ( ) . into_os_string ( )
65
76
} else if is_main && no_given_name {
66
- infer_current_exe ( dlpi_addr as usize )
77
+ infer_current_exe ( & maps , dlpi_addr as usize )
67
78
} else {
68
79
// this fallback works even if we are main, because some platforms give the name anyways
69
80
if dlpi_name. is_null ( ) {
@@ -73,6 +84,19 @@ unsafe extern "C" fn callback(
73
84
OsStr :: from_bytes ( unsafe { CStr :: from_ptr ( dlpi_name) } . to_bytes ( ) ) . to_owned ( )
74
85
}
75
86
} ;
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
+ } ;
76
100
let headers = if dlpi_phdr. is_null ( ) || dlpi_phnum == 0 {
77
101
& [ ]
78
102
} else {
@@ -81,6 +105,8 @@ unsafe extern "C" fn callback(
81
105
} ;
82
106
libs. push ( Library {
83
107
name,
108
+ #[ cfg( target_os = "android" ) ]
109
+ zip_offset,
84
110
segments : headers
85
111
. iter ( )
86
112
. map ( |header| LibrarySegment {
0 commit comments