1use crate::{ElfLibrary, core_impl::register::addr2dso};
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: ElfLibrary,
19 sname: Option<&'static CStr>,
21 saddr: usize,
23}
24
25impl DlInfo {
26 #[inline]
27 pub fn dylib(&self) -> &ElfLibrary {
28 &self.dylib
29 }
30
31 #[inline]
33 pub fn symbol_name(&self) -> Option<&str> {
34 self.sname.and_then(|s| s.to_str().ok())
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 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 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 let mut best_match: Option<(usize, &CStr)> = None;
75 for i in 0..symtab.count_syms() {
76 let (sym, syminfo) = symtab.symbol_idx(i);
77 if sym.st_value() == 0 || !sym.is_ok_bind() || !sym.is_ok_type() {
78 continue;
79 }
80 let start = dl_info.dylib.base() + sym.st_value();
81 let end = start + sym.st_size();
82 if start <= addr && (sym.st_size() == 0 || addr < end) {
83 if let Some((best_start, _)) = best_match {
84 if start > best_start {
85 if let Some(cname) = syminfo.cname() {
86 best_match = Some((start, cname));
87 }
88 }
89 } else {
90 if let Some(cname) = syminfo.cname() {
91 best_match = Some((start, cname));
92 }
93 }
94 }
95 }
96 if let Some((start, cname)) = best_match {
97 dl_info.sname = Some(unsafe { core::mem::transmute(cname) });
98 dl_info.saddr = start;
99 }
100 dl_info
101 })
102 }
103}
104
105#[unsafe(no_mangle)]
108pub unsafe extern "C" fn dladdr(addr: *const c_void, info: *mut CDlinfo) -> c_int {
109 if let Some(dl_info) = ElfLibrary::dladdr(addr as usize) {
110 let info = unsafe { &mut *info };
111 info.dli_fbase = dl_info.dylib().base() as _;
112 info.dli_fname = dl_info.dylib().cname();
113 info.dli_saddr = dl_info.symbol_addr().unwrap_or(0) as _;
114 info.dli_sname = dl_info.sname.map_or(null(), |s| s.as_ptr());
115 1
116 } else {
117 0
118 }
119}