dlopen_rs/
dladdr.rs

1use crate::{register::MANAGER, Dylib, ElfLibrary};
2use core::{ffi::CStr, fmt::Debug};
3
4pub struct DlInfo {
5    /// dylib
6    dylib: Dylib,
7    /// Name of symbol whose definition overlaps addr
8    sname: Option<&'static CStr>,
9    /// Exact address of symbol named in dli_sname
10    saddr: usize,
11}
12
13impl DlInfo {
14    #[inline]
15    pub fn dylib(&self) -> &Dylib {
16        &self.dylib
17    }
18
19    /// Name of symbol whose definition overlaps addr
20    #[inline]
21    pub fn symbol_name(&self) -> Option<&CStr> {
22        self.sname
23    }
24
25    /// Exact address of symbol
26    #[inline]
27    pub fn symbol_addr(&self) -> Option<usize> {
28        if self.saddr == 0 {
29            None
30        } else {
31            Some(self.saddr)
32        }
33    }
34}
35
36impl Debug for DlInfo {
37    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
38        f.debug_struct("DlInfo")
39            .field("dylib", &self.dylib)
40            .field("sname", &self.sname)
41            .field("saddr", &format_args!("{:#x}", self.saddr))
42            .finish()
43    }
44}
45
46impl ElfLibrary {
47    fn addr2dso(addr: usize) -> Option<Dylib> {
48        MANAGER.read().all.values().find_map(|v| {
49            let start = v.relocated_dylib_ref().base();
50            let end = start + v.relocated_dylib_ref().map_len();
51            if (start..end).contains(&addr) {
52                Some(v.get_dylib())
53            } else {
54                None
55            }
56        })
57    }
58
59    /// determines whether the address specified in addr is located in one of the shared objects loaded by the calling
60    /// application.  If it is, then `dladdr` returns information about the shared object and
61    /// symbol that overlaps addr.
62    pub fn dladdr(addr: usize) -> Option<DlInfo> {
63        log::info!(
64            "dladdr: Try to find the symbol information corresponding to [{:#x}]",
65            addr
66        );
67        Self::addr2dso(addr).map(|dylib| {
68            let mut dl_info = DlInfo {
69                dylib,
70                sname: None,
71                saddr: 0,
72            };
73            let symtab = dl_info.dylib.inner.symtab();
74            for i in 0..symtab.count_syms() {
75                let (sym, syminfo) = symtab.symbol_idx(i);
76                let start = dl_info.dylib.base() + sym.st_value();
77                let end = start + sym.st_size();
78                if sym.st_value() != 0
79                    && sym.is_ok_bind()
80                    && sym.is_ok_type()
81                    && (start..end).contains(&addr)
82                {
83                    dl_info.sname = Some(unsafe { core::mem::transmute(syminfo.cname().unwrap()) });
84                    dl_info.saddr = start;
85                }
86            }
87            dl_info
88        })
89    }
90}