dlopen_rs/api/
dl_iterate_phdr.rs1use crate::{ElfLibrary, Error, Result, core_impl::register::MANAGER};
2use alloc::boxed::Box;
3use core::{
4 ffi::{c_char, c_int, c_ulonglong, c_void},
5 ptr::null_mut,
6};
7use elf_loader::{elf::ElfPhdr, tls::DefaultTlsResolver};
8
9#[repr(C)]
11pub struct CDlPhdrInfo {
12 pub dlpi_addr: usize,
13 pub dlpi_name: *const c_char,
14 pub dlpi_phdr: *const ElfPhdr,
15 pub dlpi_phnum: u16,
16 pub dlpi_adds: c_ulonglong,
17 pub dlpi_subs: c_ulonglong,
18 pub dlpi_tls_modid: usize,
19 pub dlpi_tls_data: *mut c_void,
20}
21
22pub struct DlPhdrInfo<'lib> {
23 lib_base: usize,
24 lib_name: *const c_char,
25 phdrs: &'lib [ElfPhdr],
26 dlpi_adds: c_ulonglong,
27 dlpi_subs: c_ulonglong,
28 tls_modid: usize,
29 tls_data: Option<&'lib [u8]>,
30}
31
32impl DlPhdrInfo<'_> {
33 #[inline]
35 pub fn name(&self) -> &str {
36 if self.lib_name.is_null() {
37 ""
38 } else {
39 unsafe {
40 core::ffi::CStr::from_ptr(self.lib_name)
41 .to_str()
42 .unwrap_or("")
43 }
44 }
45 }
46
47 #[inline]
49 pub fn cname(&self) -> *const c_char {
50 self.lib_name
51 }
52
53 #[inline]
55 pub fn base(&self) -> usize {
56 self.lib_base
57 }
58
59 #[inline]
61 pub fn phdrs(&self) -> &[ElfPhdr] {
62 self.phdrs
63 }
64}
65
66impl ElfLibrary {
67 pub fn dl_iterate_phdr<F>(mut callback: F) -> Result<()>
69 where
70 F: FnMut(&DlPhdrInfo) -> Result<()>,
71 {
72 let reader = crate::lock_read!(MANAGER);
73 let dlpi_adds = reader.adds();
74 let dlpi_subs = reader.subs();
75 for lib in reader.all_values() {
76 let dylib = lib.dylib_ref();
77 let extra_data = dylib.user_data();
78 let phdrs = dylib.phdrs().unwrap_or(&[]);
79 if phdrs.is_empty() {
80 continue;
81 }
82 let tls_modid = dylib.tls_mod_id().unwrap_or(0);
83 let info = DlPhdrInfo {
84 lib_base: lib.dylib_ref().base(),
85 lib_name: extra_data
86 .c_name
87 .as_ref()
88 .map(|n| n.as_ptr())
89 .unwrap_or(b"\0".as_ptr() as _),
90 phdrs,
91 dlpi_adds,
92 dlpi_subs,
93 tls_modid,
94 tls_data: DefaultTlsResolver::get_tls_data(tls_modid),
95 };
96 callback(&info)?;
97 }
98 Ok(())
99 }
100}
101
102pub(crate) type CallBack =
103 unsafe extern "C" fn(info: *mut CDlPhdrInfo, size: usize, data: *mut c_void) -> c_int;
104
105#[unsafe(no_mangle)]
108pub unsafe extern "C" fn dl_iterate_phdr(callback: Option<CallBack>, data: *mut c_void) -> c_int {
109 let Some(callback) = callback else {
110 return 0;
111 };
112 let f = |info: &DlPhdrInfo| {
113 let mut c_info = CDlPhdrInfo {
114 dlpi_addr: info.lib_base,
115 dlpi_name: info.lib_name,
116 dlpi_phdr: info.phdrs.as_ptr(),
117 dlpi_phnum: info.phdrs.len() as _,
118 dlpi_adds: info.dlpi_adds,
119 dlpi_subs: info.dlpi_subs,
120 dlpi_tls_modid: info.tls_modid,
121 dlpi_tls_data: info
122 .tls_data
123 .map(|data| data.as_ptr() as _)
124 .unwrap_or(null_mut()),
125 };
126 unsafe {
127 let ret = callback(&mut c_info, size_of::<CDlPhdrInfo>(), data);
128 if ret != 0 {
129 return Err(Error::IteratorPhdrError { err: Box::new(ret) });
130 }
131 };
132 Ok(())
133 };
134 if let Err(err) = ElfLibrary::dl_iterate_phdr(f) {
135 if let Error::IteratorPhdrError { err } = err {
136 return *err.downcast::<i32>().unwrap();
137 }
138 }
139 0
140}