Coverage Report

Created: 2024-10-16 07:58

/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
}