1use crate::{Dylib, ElfLibrary, register::MANAGER};
2use core::{
3 ffi::{CStr, c_char, c_int, c_void},
4 fmt::Debug,
5 ptr::null,
6};
7
8#[repr(C)]
9pub struct CDlinfo {
10 pub dli_fname: *const c_char,
11 pub dli_fbase: *mut c_void,
12 pub dli_sname: *const c_char,
13 pub dli_saddr: *mut c_void,
14}
15
16pub struct DlInfo {
17 dylib: Dylib,
19 sname: Option<&'static CStr>,
21 saddr: usize,
23}
24
25impl DlInfo {
26 #[inline]
27 pub fn dylib(&self) -> &Dylib {
28 &self.dylib
29 }
30
31 #[inline]
33 pub fn symbol_name(&self) -> Option<&str> {
34 self.sname.map(|s| s.to_str().unwrap())
35 }
36
37 #[inline]
39 pub fn symbol_addr(&self) -> Option<usize> {
40 if self.saddr == 0 {
41 None
42 } else {
43 Some(self.saddr)
44 }
45 }
46}
47
48impl Debug for DlInfo {
49 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
50 f.debug_struct("DlInfo")
51 .field("dylib", &self.dylib)
52 .field("sname", &self.sname)
53 .field("saddr", &format_args!("{:#x}", self.saddr))
54 .finish()
55 }
56}
57
58impl ElfLibrary {
59 fn addr2dso(addr: usize) -> Option<Dylib> {
60 MANAGER.read().all.values().find_map(|v| {
61 let start = v.relocated_dylib_ref().base();
62 let end = start + v.relocated_dylib_ref().map_len();
63 if (start..end).contains(&addr) {
64 Some(v.get_dylib())
65 } else {
66 None
67 }
68 })
69 }
70
71 pub fn dladdr(addr: usize) -> Option<DlInfo> {
75 log::info!(
76 "dladdr: Try to find the symbol information corresponding to [{:#x}]",
77 addr
78 );
79 Self::addr2dso(addr).map(|dylib| {
80 let mut dl_info = DlInfo {
81 dylib,
82 sname: None,
83 saddr: 0,
84 };
85 let symtab = dl_info.dylib.inner.symtab();
86 for i in 0..symtab.count_syms() {
87 let (sym, syminfo) = symtab.symbol_idx(i);
88 let start = dl_info.dylib.base() + sym.st_value();
89 let end = start + sym.st_size();
90 if sym.st_value() != 0
91 && sym.is_ok_bind()
92 && sym.is_ok_type()
93 && (start..end).contains(&addr)
94 {
95 dl_info.sname = Some(unsafe { core::mem::transmute(syminfo.cname().unwrap()) });
96 dl_info.saddr = start;
97 }
98 }
99 dl_info
100 })
101 }
102}
103
104pub unsafe extern "C" fn dladdr(addr: *const c_void, info: *mut CDlinfo) -> c_int {
106 if let Some(dl_info) = ElfLibrary::dladdr(addr as usize) {
107 let info = unsafe { &mut *info };
108 info.dli_fbase = dl_info.dylib().base() as _;
109 info.dli_fname = dl_info.dylib().cname().as_ptr();
110 info.dli_saddr = dl_info.symbol_addr().unwrap_or(0) as _;
111 info.dli_sname = dl_info.sname.map_or(null(), |s| s.as_ptr());
112 1
113 } else {
114 0
115 }
116}