1 | // Other Unix (e.g. Linux) platforms use ELF as an object file format |
2 | // and typically implement an API called `dl_iterate_phdr` to load |
3 | // native libraries. |
4 | |
5 | use super::mystd::borrow::ToOwned; |
6 | use super::mystd::env; |
7 | use super::mystd::ffi::{CStr, OsStr}; |
8 | use super::mystd::os::unix::prelude::*; |
9 | use super::{Library, LibrarySegment, OsString, Vec}; |
10 | use core::slice; |
11 | |
12 | pub(super) fn native_libraries() -> Vec<Library> { |
13 | let mut ret: Vec = Vec::new(); |
14 | unsafe { |
15 | libc::dl_iterate_phdr(callback:Some(callback), data:core::ptr::addr_of_mut!(ret).cast()); |
16 | } |
17 | return ret; |
18 | } |
19 | |
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 | } |
33 | } |
34 | } |
35 | env::current_exe().map(|e: PathBuf| e.into()).unwrap_or_default() |
36 | } |
37 | |
38 | // `info` should be a valid pointers. |
39 | // `vec` should be a valid pointer to a `std::Vec`. |
40 | unsafe extern "C" fn callback( |
41 | info: *mut libc::dl_phdr_info, |
42 | _size: libc::size_t, |
43 | vec: *mut libc::c_void, |
44 | ) -> libc::c_int { |
45 | let info = &*info; |
46 | let libs = &mut *vec.cast::<Vec<Library>>(); |
47 | let is_main_prog = info.dlpi_name.is_null() || *info.dlpi_name == 0; |
48 | let name = if is_main_prog { |
49 | // The man page for dl_iterate_phdr says that the first object visited by |
50 | // callback is the main program; so the first time we encounter a |
51 | // nameless entry, we can assume its the main program and try to infer its path. |
52 | // After that, we cannot continue that assumption, and we use an empty string. |
53 | if libs.is_empty() { |
54 | infer_current_exe(info.dlpi_addr as usize) |
55 | } else { |
56 | OsString::new() |
57 | } |
58 | } else { |
59 | let bytes = CStr::from_ptr(info.dlpi_name).to_bytes(); |
60 | OsStr::from_bytes(bytes).to_owned() |
61 | }; |
62 | let headers = slice::from_raw_parts(info.dlpi_phdr, info.dlpi_phnum as usize); |
63 | libs.push(Library { |
64 | name, |
65 | segments: headers |
66 | .iter() |
67 | .map(|header| LibrarySegment { |
68 | len: (*header).p_memsz as usize, |
69 | stated_virtual_memory_address: (*header).p_vaddr as usize, |
70 | }) |
71 | .collect(), |
72 | bias: info.dlpi_addr as usize, |
73 | }); |
74 | 0 |
75 | } |
76 | |