use memmap2::Mmap;
use std::fmt;
use std::ops::Deref;
use std::ops::Range;
use std::sync::Arc;
use super::LoadSegment;
#[derive(Clone)]
pub(crate) struct ElfSectionData {
storage: ElfSectionStorage,
range: Range<usize>,
}
#[derive(Clone)]
enum ElfSectionStorage {
Owned(Arc<[u8]>),
Mmap(Arc<Mmap>),
}
impl ElfSectionData {
#[must_use]
pub(crate) fn owned(data: impl Into<Arc<[u8]>>) -> Self {
let data = data.into();
Self {
range: 0..data.len(),
storage: ElfSectionStorage::Owned(data),
}
}
pub(crate) fn owned_range(data: Arc<[u8]>, range: Range<usize>) -> Option<Self> {
(range.start <= range.end && range.end <= data.len()).then_some(Self {
storage: ElfSectionStorage::Owned(data),
range,
})
}
pub(crate) fn mmap(mmap: Arc<Mmap>, range: Range<usize>) -> Option<Self> {
(range.start <= range.end && range.end <= mmap.len()).then_some(Self {
storage: ElfSectionStorage::Mmap(mmap),
range,
})
}
}
impl Deref for ElfSectionData {
type Target = [u8];
fn deref(&self) -> &Self::Target {
match &self.storage {
ElfSectionStorage::Owned(data) => &data[self.range.clone()],
ElfSectionStorage::Mmap(mmap) => &mmap[self.range.clone()],
}
}
}
impl AsRef<[u8]> for ElfSectionData {
fn as_ref(&self) -> &[u8] {
self
}
}
impl fmt::Debug for ElfSectionData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ElfSectionData")
.field("len", &self.len())
.finish()
}
}
impl PartialEq for ElfSectionData {
fn eq(&self, other: &Self) -> bool {
self.deref() == other.deref()
}
}
impl Eq for ElfSectionData {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct ElfSectionInfo {
pub(crate) base_svma: u64,
pub(crate) text_svma: Option<Range<u64>>,
pub(crate) text_file_range: Option<Range<u64>>,
pub(crate) text: Option<ElfSectionData>,
pub(crate) eh_frame_svma: Option<u64>,
pub(crate) eh_frame: Option<ElfSectionData>,
pub(crate) eh_frame_hdr_svma: Option<u64>,
pub(crate) eh_frame_hdr: Option<ElfSectionData>,
pub(crate) got_svma: Option<Range<u64>>,
pub(crate) load_segments: Box<[LoadSegment]>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_support::mmap_from_bytes;
#[test]
fn mmap_section_data_validates_and_slices_ranges() {
let mmap = mmap_from_bytes(&[10, 20, 30, 40, 50]);
let section = ElfSectionData::mmap(mmap.clone(), 1..4).expect("valid mmap range");
assert_eq!(&*section, &[20, 30, 40]);
assert_eq!(section, ElfSectionData::owned(vec![20_u8, 30, 40]));
let start = 4;
let end = 1;
assert!(ElfSectionData::mmap(mmap.clone(), start..end).is_none());
assert!(ElfSectionData::mmap(mmap, 0..6).is_none());
}
}