use super::{
Symbol,
module::{ModuleState, lookup_symbol},
};
use crate::{
Result,
arch::NativeArch,
elf::{ElfLayout, ElfSymbol, SymbolLookup, SymbolTable},
memory::{ImageMemory, VmAddr},
relocation::RelocationArch,
sync::Arc,
tls::{ModuleTls, TlsResolver},
};
use core::any::Any;
use super::search::ModuleSearch;
pub trait SymbolExports<L: ElfLayout>: Send + Sync {
fn for_each(&self, visitor: &mut dyn FnMut(&ElfSymbol<L>));
fn symbol_name<'exports>(&'exports self, symbol: &ElfSymbol<L>) -> Option<&'exports str>;
fn lookup<'exports>(
&'exports self,
lookup: &mut SymbolLookup<'_>,
) -> Option<&'exports ElfSymbol<L>>;
}
impl<L> SymbolExports<L> for SymbolTable<L>
where
L: ElfLayout,
{
#[inline]
fn for_each(&self, visitor: &mut dyn FnMut(&ElfSymbol<L>)) {
self.hashtab.for_each(self.view(), visitor);
}
#[inline]
fn symbol_name<'exports>(&'exports self, symbol: &ElfSymbol<L>) -> Option<&'exports str> {
Some(self.strtab().get_str(symbol.st_name()))
}
#[inline]
fn lookup<'exports>(
&'exports self,
lookup: &mut SymbolLookup<'_>,
) -> Option<&'exports ElfSymbol<L>> {
self.view().lookup(lookup)
}
}
pub trait Module<Arch: RelocationArch = NativeArch, Tls: TlsResolver<Arch> = ()>:
Any + Send + Sync
{
fn name(&self) -> &str;
fn search(&self) -> Option<&ModuleSearch> {
None
}
fn exports(&self) -> &dyn SymbolExports<Arch::Layout>;
fn memory(&self) -> &dyn ImageMemory;
fn resolve_symbol(&self, symbol: &ElfSymbol<Arch::Layout>) -> Result<VmAddr>;
fn tls(&self) -> Option<ModuleTls> {
None
}
fn state(&self) -> &ModuleState;
fn initialize(&self) -> Result<()> {
Ok(())
}
fn finalize(&self) -> Result<()> {
Ok(())
}
}
impl<Arch, Tls> dyn Module<Arch, Tls>
where
Arch: RelocationArch,
Tls: TlsResolver<Arch>,
{
#[inline]
pub fn downcast_ref<M>(&self) -> Option<&M>
where
M: Module<Arch, Tls> + 'static,
{
(self as &dyn Any).downcast_ref()
}
#[inline]
pub fn ptr_eq(&self, other: &dyn Module<Arch, Tls>) -> bool {
core::ptr::eq(self.state(), other.state())
}
#[inline]
pub unsafe fn try_get<T>(&self, name: &str) -> Result<Option<Symbol<'_, T>>> {
let addr = lookup_symbol(self, &mut SymbolLookup::new(name))?;
Ok(addr.map(|addr| unsafe { Symbol::from_raw(addr.as_mut_ptr()) }))
}
#[inline]
pub unsafe fn get<T>(&self, name: &str) -> Option<Symbol<'_, T>> {
unsafe { self.try_get(name).ok().flatten() }
}
#[cfg(feature = "version")]
#[inline]
pub unsafe fn try_get_version<T>(
&self,
name: &str,
version: &str,
) -> Result<Option<Symbol<'_, T>>> {
let addr = lookup_symbol(self, &mut SymbolLookup::with_version(name, version))?;
Ok(addr.map(|addr| unsafe { Symbol::from_raw(addr.as_mut_ptr()) }))
}
#[cfg(feature = "version")]
#[inline]
pub unsafe fn get_version<T>(&self, name: &str, version: &str) -> Option<Symbol<'_, T>> {
unsafe { self.try_get_version(name, version).ok().flatten() }
}
}
impl<M, Arch, Tls> Module<Arch, Tls> for Arc<M>
where
M: Module<Arch, Tls> + ?Sized + 'static,
Arch: RelocationArch,
Tls: TlsResolver<Arch> + 'static,
{
#[inline]
fn name(&self) -> &str {
(**self).name()
}
#[inline]
fn search(&self) -> Option<&ModuleSearch> {
(**self).search()
}
#[inline]
fn exports(&self) -> &dyn SymbolExports<Arch::Layout> {
(**self).exports()
}
#[inline]
fn memory(&self) -> &dyn ImageMemory {
(**self).memory()
}
#[inline]
fn resolve_symbol(&self, symbol: &ElfSymbol<Arch::Layout>) -> Result<VmAddr> {
(**self).resolve_symbol(symbol)
}
#[inline]
fn tls(&self) -> Option<ModuleTls> {
(**self).tls()
}
#[inline]
fn state(&self) -> &ModuleState {
(**self).state()
}
#[inline]
fn initialize(&self) -> Result<()> {
(**self).initialize()
}
#[inline]
fn finalize(&self) -> Result<()> {
(**self).finalize()
}
}