use super::RelocationArch;
use crate::tls::{TlsModuleId, TlsTpOffset};
use crate::{
Result,
elf::{ElfRelType, Lifecycle},
image::ElfCore,
segment::ElfSegments,
};
use core::marker::PhantomData;
pub trait EmulatedArch: RelocationArch {}
pub struct EmuContext<'a, Arch: RelocationArch> {
name: &'a str,
base: usize,
segments: &'a ElfSegments,
_marker: PhantomData<fn() -> Arch>,
}
impl<'a, Arch: RelocationArch> EmuContext<'a, Arch> {
#[inline]
pub(crate) fn new<D: 'static>(core: &'a ElfCore<D, Arch>) -> Self {
Self::from_parts(core.name(), core.base_addr().into_inner(), core.segments())
}
#[inline]
pub(crate) const fn from_parts(name: &'a str, base: usize, segments: &'a ElfSegments) -> Self {
Self {
name,
base,
segments,
_marker: PhantomData,
}
}
#[inline]
pub fn name(&self) -> &'a str {
self.name
}
#[inline]
pub fn base(&self) -> usize {
self.base
}
#[inline]
pub fn contains_addr(&self, addr: usize) -> bool {
self.segments.contains_addr(addr)
}
}
pub struct EmuRelocationContext<'a, Arch: RelocationArch> {
image: EmuContext<'a, Arch>,
rel: &'a ElfRelType<Arch>,
}
impl<'a, Arch: RelocationArch> EmuRelocationContext<'a, Arch> {
#[inline]
pub(crate) fn new<D: 'static>(core: &'a ElfCore<D, Arch>, rel: &'a ElfRelType<Arch>) -> Self {
Self {
image: EmuContext::new(core),
rel,
}
}
#[inline]
pub fn image(&self) -> &EmuContext<'a, Arch> {
&self.image
}
#[inline]
pub fn rel(&self) -> &'a ElfRelType<Arch> {
self.rel
}
}
#[derive(Clone, Copy, Debug)]
pub struct TlsDescEmuRequest {
symbol_value: usize,
addend: isize,
module_id: Option<TlsModuleId>,
tp_offset: Option<TlsTpOffset>,
tls_get_addr: usize,
}
impl TlsDescEmuRequest {
#[inline]
pub const fn new(
symbol_value: usize,
addend: isize,
module_id: Option<TlsModuleId>,
tp_offset: Option<TlsTpOffset>,
tls_get_addr: usize,
) -> Self {
Self {
symbol_value,
addend,
module_id,
tp_offset,
tls_get_addr,
}
}
#[inline]
pub const fn symbol_value(&self) -> usize {
self.symbol_value
}
#[inline]
pub const fn addend(&self) -> isize {
self.addend
}
#[inline]
pub const fn module_id(&self) -> Option<TlsModuleId> {
self.module_id
}
#[inline]
pub const fn tp_offset(&self) -> Option<TlsTpOffset> {
self.tp_offset
}
#[inline]
pub const fn tls_get_addr(&self) -> usize {
self.tls_get_addr
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TlsDescEmuValue {
resolver: usize,
arg: usize,
}
impl TlsDescEmuValue {
#[inline]
pub const fn new(resolver: usize, arg: usize) -> Self {
Self { resolver, arg }
}
#[inline]
pub const fn resolver(&self) -> usize {
self.resolver
}
#[inline]
pub const fn arg(&self) -> usize {
self.arg
}
}
pub trait Emulator<Arch: RelocationArch>: Send + Sync + 'static {
fn resolve_ifunc(&self, ctx: &EmuRelocationContext<'_, Arch>, resolver: usize)
-> Result<usize>;
fn call_init(&self, ctx: &EmuContext<'_, Arch>, lifecycle: &Lifecycle<'_>) -> Result<()>;
fn call_fini(&self, ctx: &EmuContext<'_, Arch>, lifecycle: &Lifecycle<'_>);
fn resolve_tlsdesc(
&self,
ctx: &EmuRelocationContext<'_, Arch>,
request: TlsDescEmuRequest,
) -> Result<TlsDescEmuValue>;
}