use crate::RelocatedLibrary;
use core::ptr::{self, null_mut};
use hashbrown::HashMap;
use std::{
ffi::CString,
sync::{Arc, LazyLock, RwLock},
};
static REGISTER_LIBS: LazyLock<RwLock<HashMap<CString, RelocatedLibrary>>> =
LazyLock::new(|| RwLock::new(HashMap::new()));
impl RelocatedLibrary {
pub fn register(&self) -> Option<RelocatedLibrary> {
let mut writer = REGISTER_LIBS.write().unwrap();
self.set_register();
writer.insert(self.cname().to_owned(), self.clone())
}
}
impl Drop for RelocatedLibrary {
fn drop(&mut self) {
if self.is_register() {
if Arc::strong_count(&self.inner) == 2 {
let mut writer = REGISTER_LIBS.write().unwrap();
let remove = writer.remove(self.cname());
drop(writer);
drop(remove);
}
}
}
}
pub(crate) unsafe extern "C" fn dl_iterate_phdr_impl(
callback: Option<
unsafe extern "C" fn(
info: *mut nix::libc::dl_phdr_info,
size: nix::libc::size_t,
data: *mut nix::libc::c_void,
) -> nix::libc::c_int,
>,
data: *mut nix::libc::c_void,
) -> nix::libc::c_int {
use nix::libc::dl_phdr_info;
let reader = REGISTER_LIBS.read().unwrap();
let mut ret = nix::libc::dl_iterate_phdr(callback, data);
for lib in reader.values() {
let extra = if let Some(extra) = lib.get_extra_data() {
extra
} else {
continue;
};
let (dlpi_phdr, dlpi_phnum) = extra
.phdrs()
.map(|phdrs| (phdrs.as_ptr().cast(), phdrs.len() as _))
.unwrap_or((ptr::null(), 0));
let mut info = dl_phdr_info {
dlpi_addr: lib.base() as _,
dlpi_name: lib.cname().as_ptr().cast(),
dlpi_phdr,
dlpi_phnum,
dlpi_adds: reader.len() as _,
dlpi_subs: 0,
dlpi_tls_modid: 0,
dlpi_tls_data: null_mut(),
};
if let Some(callback) = callback {
ret = callback(&mut info, size_of::<dl_phdr_info>(), data);
if ret != 0 {
break;
}
}
}
ret
}