/rust/registry/src/index.crates.io-6f17d22bba15001f/backtrace-0.3.73/src/symbolize/gimli/libs_dl_iterate_phdr.rs
Line | Count | Source (jump to first uncovered line) |
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 | 0 | pub(super) fn native_libraries() -> Vec<Library> { |
13 | 0 | let mut ret = Vec::new(); |
14 | 0 | unsafe { |
15 | 0 | libc::dl_iterate_phdr(Some(callback), core::ptr::addr_of_mut!(ret).cast()); |
16 | 0 | } |
17 | 0 | return ret; |
18 | 0 | } |
19 | | |
20 | 0 | fn infer_current_exe(base_addr: usize) -> OsString { |
21 | | cfg_if::cfg_if! { |
22 | | if #[cfg(not(target_os = "hurd"))] { |
23 | 0 | if let Ok(entries) = super::parse_running_mmaps::parse_maps() { |
24 | 0 | let opt_path = entries |
25 | 0 | .iter() |
26 | 0 | .find(|e| e.ip_matches(base_addr) && e.pathname().len() > 0) |
27 | 0 | .map(|e| e.pathname()) |
28 | 0 | .cloned(); |
29 | 0 | if let Some(path) = opt_path { |
30 | 0 | return path; |
31 | 0 | } |
32 | 0 | } |
33 | | } |
34 | | } |
35 | 0 | env::current_exe().map(|e| e.into()).unwrap_or_default() |
36 | 0 | } |
37 | | |
38 | | // `info` should be a valid pointers. |
39 | | // `vec` should be a valid pointer to a `std::Vec`. |
40 | 0 | unsafe extern "C" fn callback( |
41 | 0 | info: *mut libc::dl_phdr_info, |
42 | 0 | _size: libc::size_t, |
43 | 0 | vec: *mut libc::c_void, |
44 | 0 | ) -> libc::c_int { |
45 | 0 | let info = &*info; |
46 | 0 | let libs = &mut *vec.cast::<Vec<Library>>(); |
47 | 0 | let is_main_prog = info.dlpi_name.is_null() || *info.dlpi_name == 0; |
48 | 0 | 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 | 0 | if libs.is_empty() { |
54 | 0 | infer_current_exe(info.dlpi_addr as usize) |
55 | | } else { |
56 | 0 | OsString::new() |
57 | | } |
58 | | } else { |
59 | 0 | let bytes = CStr::from_ptr(info.dlpi_name).to_bytes(); |
60 | 0 | OsStr::from_bytes(bytes).to_owned() |
61 | | }; |
62 | 0 | let headers = slice::from_raw_parts(info.dlpi_phdr, info.dlpi_phnum as usize); |
63 | 0 | libs.push(Library { |
64 | 0 | name, |
65 | 0 | segments: headers |
66 | 0 | .iter() |
67 | 0 | .map(|header| LibrarySegment { |
68 | 0 | len: (*header).p_memsz as usize, |
69 | 0 | stated_virtual_memory_address: (*header).p_vaddr as usize, |
70 | 0 | }) |
71 | 0 | .collect(), |
72 | 0 | bias: info.dlpi_addr as usize, |
73 | 0 | }); |
74 | 0 | 0 |
75 | 0 | } |