use crate::{
Result, logging,
os::{MapFlags, ProtFlags},
sync::Arc,
};
use alloc::vec::Vec;
use core::ffi::c_void;
pub(crate) enum Address {
Relative(usize),
Absolute(usize),
}
impl Address {
pub(super) fn absolute_addr(&self) -> usize {
match self {
Address::Relative(_) => unreachable!(),
Address::Absolute(addr) => *addr,
}
}
pub(super) fn relative_addr(&self) -> usize {
match self {
Address::Relative(addr) => *addr,
Address::Absolute(_) => unreachable!(),
}
}
}
#[derive(Debug)]
pub(crate) struct FileMapInfo {
pub(crate) start: usize,
pub(crate) filesz: usize,
pub(crate) offset: usize,
}
pub(crate) struct ElfSegment {
pub(crate) addr: Address,
pub(crate) prot: ProtFlags,
pub(crate) flags: MapFlags,
pub(crate) len: usize,
pub(crate) page_size: usize,
pub(crate) zero_size: usize,
pub(crate) content_size: usize,
pub(crate) map_info: Vec<FileMapInfo>,
pub(crate) need_copy: bool,
pub(crate) from_relocatable: bool,
}
pub(crate) struct ElfSegmentBacking {
pub(super) memory: *mut c_void,
pub(super) len: usize,
munmap: unsafe fn(*mut c_void, usize) -> Result<()>,
}
impl ElfSegmentBacking {
#[inline]
pub(super) fn new(
memory: *mut c_void,
len: usize,
munmap: unsafe fn(*mut c_void, usize) -> Result<()>,
) -> Self {
Self {
memory,
len,
munmap,
}
}
}
impl Drop for ElfSegmentBacking {
fn drop(&mut self) {
let res = unsafe { (self.munmap)(self.memory, self.len) };
debug_assert!(res.is_ok(), "failed to unmap ELF segments");
if let Err(err) = res {
logging::error!("failed to unmap ELF segments: {err}");
}
}
}
unsafe impl Send for ElfSegmentBacking {}
unsafe impl Sync for ElfSegmentBacking {}
#[derive(Clone)]
pub(crate) struct ElfSegmentSlice {
pub(super) offset: usize,
pub(super) len: usize,
#[cfg_attr(not(windows), allow(dead_code))]
pub(super) backing: Arc<ElfSegmentBacking>,
}
impl ElfSegmentSlice {
#[inline]
pub(super) fn new(offset: usize, len: usize, backing: Arc<ElfSegmentBacking>) -> Self {
Self {
offset,
len,
backing,
}
}
#[inline]
pub(super) fn contains_range(&self, start: usize, len: usize) -> bool {
start
.checked_sub(self.offset)
.and_then(|delta| delta.checked_add(len))
.is_some_and(|end| end <= self.len)
}
#[inline]
pub(super) fn len(&self) -> usize {
self.len
}
#[inline]
pub(super) fn offset(&self) -> usize {
self.offset
}
}