use crate::{
Loader, Result,
elf::{ElfDyn, ElfPhdr},
image::{ElfCore, LoadedCore, common::DynamicImage},
input::{ElfReader, IntoElfReader},
loader::LoadHook,
os::Mmap,
parse_ehdr_error,
relocation::{Relocatable, RelocationHandler, Relocator, SupportLazy, SymbolLookup},
tls::TlsResolver,
};
use alloc::vec::Vec;
use core::{borrow::Borrow, fmt::Debug, ops::Deref, ptr::NonNull};
pub struct RawDylib<D>
where
D: 'static,
{
pub(crate) inner: DynamicImage<D>,
}
impl<D: 'static> SupportLazy for RawDylib<D> {}
impl<D> Debug for RawDylib<D> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("RawDylib")
.field("name", &self.inner.name())
.field("needed_libs", &self.inner.needed_libs())
.finish()
}
}
impl<D> Relocatable<D> for RawDylib<D> {
type Output = LoadedDylib<D>;
fn relocate<PreS, PostS, LazyS, PreH, PostH>(
self,
scope: Vec<LoadedCore<D>>,
pre_find: &PreS,
post_find: &PostS,
pre_handler: &PreH,
post_handler: &PostH,
lazy: Option<bool>,
lazy_scope: Option<LazyS>,
) -> Result<Self::Output>
where
PreS: SymbolLookup + ?Sized,
PostS: SymbolLookup + ?Sized,
LazyS: SymbolLookup + Send + Sync + 'static,
PreH: RelocationHandler + ?Sized,
PostH: RelocationHandler + ?Sized,
{
let inner = self.inner.relocate_impl(
scope,
pre_find,
post_find,
pre_handler,
post_handler,
lazy,
lazy_scope,
)?;
Ok(LoadedDylib { inner })
}
}
impl<D> RawDylib<D> {
#[inline]
pub fn entry(&self) -> usize {
self.inner.entry()
}
#[inline]
pub fn core_ref(&self) -> &ElfCore<D> {
self.inner.core_ref()
}
#[inline]
pub fn core(&self) -> ElfCore<D> {
self.inner.core()
}
#[inline]
pub fn into_core(self) -> ElfCore<D> {
self.inner.into_core()
}
#[inline]
pub fn is_lazy(&self) -> bool {
self.inner.is_lazy()
}
#[inline]
pub fn rpath(&self) -> Option<&str> {
self.inner.rpath()
}
#[inline]
pub fn runpath(&self) -> Option<&str> {
self.inner.runpath()
}
#[inline]
pub fn interp(&self) -> Option<&str> {
self.inner.interp()
}
#[inline]
pub fn name(&self) -> &str {
self.inner.name()
}
#[inline]
pub fn short_name(&self) -> &str {
self.inner.core_ref().short_name()
}
pub fn phdrs(&self) -> &[ElfPhdr] {
self.inner.phdrs()
}
pub fn base(&self) -> usize {
self.inner.base()
}
pub fn mapped_len(&self) -> usize {
self.inner.mapped_len()
}
pub fn needed_libs(&self) -> &[&str] {
self.inner.needed_libs()
}
pub fn dynamic_ptr(&self) -> Option<NonNull<ElfDyn>> {
self.inner.dynamic_ptr()
}
pub fn user_data(&self) -> &D {
self.inner.user_data()
}
#[inline]
pub fn user_data_mut(&mut self) -> Option<&mut D> {
self.inner.user_data_mut()
}
pub fn relocator(self) -> Relocator<Self, (), (), (), (), (), D> {
Relocator::new(self)
}
}
impl<M, H, D, Tls> Loader<M, H, D, Tls>
where
M: Mmap,
H: LoadHook,
D: Default,
Tls: TlsResolver,
{
pub fn load_dylib<'a, I>(&mut self, input: I) -> Result<RawDylib<D>>
where
I: IntoElfReader<'a>,
{
let object = input.into_reader()?;
self.load_dylib_impl(object)
}
pub(crate) fn load_dylib_impl(&mut self, mut object: impl ElfReader) -> Result<RawDylib<D>> {
#[cfg(feature = "log")]
log::debug!("Loading dylib: {}", object.file_name());
let ehdr = self.read_ehdr(&mut object)?;
if !ehdr.is_dylib() {
#[cfg(feature = "log")]
log::error!(
"[{}] Type mismatch: expected dylib, found {:?}",
object.file_name(),
ehdr.e_type
);
return Err(parse_ehdr_error("file type mismatch"));
}
let phdrs = self
.buf
.prepare_phdrs(&ehdr, &mut object)?
.unwrap_or_default();
let builder = self.inner.create_builder::<M, Tls>(ehdr, phdrs, object)?;
let inner = builder.build_dynamic(phdrs)?;
#[cfg(feature = "log")]
log::info!(
"Loaded dylib: {} at [0x{:x}-0x{:x}]",
inner.name(),
inner.base(),
inner.base() + inner.mapped_len()
);
Ok(RawDylib { inner })
}
}
#[derive(Debug, Clone)]
pub struct LoadedDylib<D> {
inner: LoadedCore<D>,
}
impl<D> Deref for LoadedDylib<D> {
type Target = LoadedCore<D>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<D> Borrow<LoadedCore<D>> for LoadedDylib<D> {
fn borrow(&self) -> &LoadedCore<D> {
&self.inner
}
}
impl<D> Borrow<LoadedCore<D>> for &LoadedDylib<D> {
fn borrow(&self) -> &LoadedCore<D> {
&self.inner
}
}