use crate::{
Loader, Result,
input::IntoElfReader,
loader::LoadHook,
os::Mmap,
relocation::{Relocatable, RelocationHandler, Relocator, SymbolLookup},
};
use alloc::vec::Vec;
use core::fmt::Debug;
use elf::abi::{PT_DYNAMIC, PT_INTERP};
mod builder;
mod common;
mod kinds;
pub(crate) use builder::{ImageBuilder, ObjectBuilder};
pub(crate) use common::{CoreInner, DynamicImage};
pub use common::{ElfCore, ElfCoreRef, LoadedCore, Symbol};
pub use kinds::{LoadedDylib, LoadedExec, LoadedObject, RawDylib, RawExec, RawObject};
#[derive(Debug)]
pub enum RawElf<D>
where
D: 'static,
{
Dylib(RawDylib<D>),
Exec(RawExec<D>),
Object(RawObject<D>),
}
#[derive(Debug, Clone)]
pub enum LoadedElf<D> {
Dylib(LoadedDylib<D>),
Exec(LoadedExec<D>),
Object(LoadedObject<D>),
}
impl<D: 'static> RawElf<D> {
pub fn relocator(self) -> Relocator<Self, (), (), (), (), (), D> {
Relocator::new(self)
}
#[inline]
pub fn name(&self) -> &str {
match self {
RawElf::Dylib(dylib) => dylib.name(),
RawElf::Exec(exec) => exec.name(),
RawElf::Object(object) => object.name(),
}
}
#[inline]
pub fn mapped_len(&self) -> usize {
match self {
RawElf::Dylib(dylib) => dylib.mapped_len(),
RawElf::Exec(exec) => exec.mapped_len(),
RawElf::Object(object) => object.mapped_len(),
}
}
}
impl<D> LoadedElf<D> {
#[inline]
pub fn into_dylib(self) -> Option<LoadedDylib<D>> {
match self {
LoadedElf::Dylib(dylib) => Some(dylib),
_ => None,
}
}
#[inline]
pub fn into_exec(self) -> Option<LoadedExec<D>> {
match self {
LoadedElf::Exec(exec) => Some(exec),
_ => None,
}
}
#[inline]
pub fn into_object(self) -> Option<LoadedObject<D>> {
match self {
LoadedElf::Object(object) => Some(object),
_ => None,
}
}
#[inline]
pub fn as_dylib(&self) -> Option<&LoadedDylib<D>> {
match self {
LoadedElf::Dylib(dylib) => Some(dylib),
_ => None,
}
}
#[inline]
pub fn as_exec(&self) -> Option<&LoadedExec<D>> {
match self {
LoadedElf::Exec(exec) => Some(exec),
_ => None,
}
}
#[inline]
pub fn as_object(&self) -> Option<&LoadedObject<D>> {
match self {
LoadedElf::Object(object) => Some(object),
_ => None,
}
}
#[inline]
pub fn name(&self) -> &str {
match self {
LoadedElf::Dylib(dylib) => dylib.name(),
LoadedElf::Exec(exec) => exec.name(),
LoadedElf::Object(object) => object.name(),
}
}
}
impl<D: 'static> Relocatable<D> for RawElf<D> {
type Output = LoadedElf<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
D: 'static,
PreS: SymbolLookup + ?Sized,
PostS: SymbolLookup + ?Sized,
LazyS: SymbolLookup + Send + Sync + 'static,
PreH: RelocationHandler + ?Sized,
PostH: RelocationHandler + ?Sized,
{
match self {
RawElf::Dylib(dylib) => {
let relocated = Relocatable::relocate(
dylib,
scope,
pre_find,
post_find,
pre_handler,
post_handler,
lazy,
lazy_scope,
)?;
Ok(LoadedElf::Dylib(relocated))
}
RawElf::Exec(exec) => {
let relocated = Relocatable::relocate(
exec,
scope,
pre_find,
post_find,
pre_handler,
post_handler,
lazy,
lazy_scope,
)?;
Ok(LoadedElf::Exec(relocated))
}
RawElf::Object(relocatable) => {
let relocated = Relocatable::relocate(
relocatable,
Vec::new(),
pre_find,
post_find,
pre_handler,
post_handler,
lazy,
None::<LazyS>, )?;
Ok(LoadedElf::Object(relocated))
}
}
}
}
impl<M: Mmap, H: LoadHook, D: Default + 'static> Loader<M, H, D> {
pub fn load<'a, I>(&mut self, input: I) -> Result<RawElf<D>>
where
I: IntoElfReader<'a>,
{
let mut object = input.into_reader()?;
let ehdr = self.read_ehdr(&mut object)?;
match ehdr.e_type {
elf::abi::ET_REL => Ok(RawElf::Object(self.load_object_impl(object)?)),
elf::abi::ET_EXEC => Ok(RawElf::Exec(self.load_exec_impl(object)?)),
elf::abi::ET_DYN => {
let phdrs = self.read_phdr(&mut object, &ehdr)?.unwrap_or_default();
let has_dynamic = phdrs.iter().any(|p| p.p_type == PT_DYNAMIC);
let is_pie = phdrs.iter().any(|p| p.p_type == PT_INTERP) || !has_dynamic;
if is_pie {
Ok(RawElf::Exec(self.load_exec_impl(object)?))
} else {
Ok(RawElf::Dylib(self.load_dylib_impl(object)?))
}
}
_ => Ok(RawElf::Exec(self.load_exec_impl(object)?)),
}
}
}