use super::{ElfReader, IntoElfReader, Path, PathBuf};
use crate::{Result, logging, os::RawFile};
use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec};
use core::ops::Range;
fn checked_read_range(offset: usize, len: usize, available: usize) -> Result<Range<usize>> {
let Some(end) = offset.checked_add(len).filter(|&end| end <= available) else {
return Err(
crate::IoError::ReadOutOfBounds(Box::new(crate::ReadBoundsError::new(
offset, len, available,
)))
.into(),
);
};
Ok(offset..end)
}
#[derive(Debug)]
pub struct ElfBinary<'bytes> {
path: PathBuf,
bytes: Cow<'bytes, [u8]>,
}
impl<'bytes> ElfBinary<'bytes> {
pub fn new(path: impl Into<PathBuf>, bytes: &'bytes [u8]) -> Self {
Self {
path: path.into(),
bytes: Cow::Borrowed(bytes),
}
}
pub fn owned(path: impl Into<PathBuf>, bytes: impl Into<Vec<u8>>) -> Self {
Self {
path: path.into(),
bytes: Cow::Owned(bytes.into()),
}
}
}
impl<'bytes> ElfReader for ElfBinary<'bytes> {
fn path(&self) -> &Path {
&self.path
}
fn len(&self) -> usize {
self.bytes.as_ref().len()
}
fn read(&self, buf: &mut [u8], offset: usize) -> crate::Result<()> {
let bytes = self.bytes.as_ref();
let range = checked_read_range(offset, buf.len(), bytes.len())?;
buf.copy_from_slice(&bytes[range]);
Ok(())
}
fn borrow_bytes(&self, offset: usize, len: usize) -> Result<Option<&[u8]>> {
let bytes = self.bytes.as_ref();
let range = checked_read_range(offset, len, bytes.len())?;
Ok(Some(&bytes[range]))
}
fn as_fd(&self) -> Option<isize> {
None
}
}
pub struct ElfFile {
inner: RawFile,
}
impl ElfFile {
pub unsafe fn from_owned_fd(path: impl AsRef<Path>, raw_fd: i32) -> Result<Self> {
let path = path.as_ref();
Ok(ElfFile {
inner: RawFile::from_owned_fd(path, raw_fd)?,
})
}
pub fn from_path(path: impl AsRef<Path>) -> Result<Self> {
let path = path.as_ref();
logging::debug!("Opening ELF file: {}", path);
let inner = RawFile::from_path(path)?;
Ok(ElfFile { inner })
}
}
impl ElfReader for ElfFile {
fn path(&self) -> &Path {
self.inner.path()
}
fn len(&self) -> usize {
self.inner.len()
}
fn read(&self, buf: &mut [u8], offset: usize) -> Result<()> {
self.inner.read(buf, offset)
}
fn as_fd(&self) -> Option<isize> {
self.inner.as_fd()
}
}
impl ElfReader for &[u8] {
fn path(&self) -> &Path {
Path::new("<memory>")
}
fn len(&self) -> usize {
(**self).len()
}
fn read(&self, buf: &mut [u8], offset: usize) -> Result<()> {
let bytes = *self;
let range = checked_read_range(offset, buf.len(), bytes.len())?;
buf.copy_from_slice(&bytes[range]);
Ok(())
}
fn borrow_bytes(&self, offset: usize, len: usize) -> Result<Option<&[u8]>> {
let bytes = *self;
let range = checked_read_range(offset, len, bytes.len())?;
Ok(Some(&bytes[range]))
}
fn as_fd(&self) -> Option<isize> {
None
}
}
impl<'a> IntoElfReader<'a> for &'a str {
type Reader = ElfFile;
fn into_reader(self) -> Result<Self::Reader> {
ElfFile::from_path(self)
}
}
impl<'a> IntoElfReader<'a> for String {
type Reader = ElfFile;
fn into_reader(self) -> Result<Self::Reader> {
ElfFile::from_path(self)
}
}
impl<'a> IntoElfReader<'a> for &'a Path {
type Reader = ElfFile;
fn into_reader(self) -> Result<Self::Reader> {
ElfFile::from_path(self)
}
}
impl<'a> IntoElfReader<'a> for PathBuf {
type Reader = ElfFile;
fn into_reader(self) -> Result<Self::Reader> {
ElfFile::from_path(self)
}
}
impl<'a> IntoElfReader<'a> for &'a PathBuf {
type Reader = ElfFile;
fn into_reader(self) -> Result<Self::Reader> {
ElfFile::from_path(self)
}
}
impl<'a> IntoElfReader<'a> for &'a [u8] {
type Reader = ElfBinary<'a>;
fn into_reader(self) -> Result<Self::Reader> {
Ok(ElfBinary::new("<memory>", self))
}
}
impl<'a> IntoElfReader<'a> for &'a Vec<u8> {
type Reader = ElfBinary<'a>;
fn into_reader(self) -> Result<Self::Reader> {
Ok(ElfBinary::new("<memory>", self.as_slice()))
}
}
impl<'a> IntoElfReader<'a> for Vec<u8> {
type Reader = ElfBinary<'static>;
fn into_reader(self) -> Result<Self::Reader> {
Ok(ElfBinary::owned("<memory>", self))
}
}
impl<'a> IntoElfReader<'a> for Box<[u8]> {
type Reader = ElfBinary<'static>;
fn into_reader(self) -> Result<Self::Reader> {
Ok(ElfBinary::owned("<memory>", self.into_vec()))
}
}
impl<'a> IntoElfReader<'a> for ElfFile {
type Reader = ElfFile;
fn into_reader(self) -> Result<Self::Reader> {
Ok(self)
}
}
impl<'a, 'b> IntoElfReader<'a> for ElfBinary<'b>
where
'b: 'a,
{
type Reader = ElfBinary<'b>;
fn into_reader(self) -> Result<Self::Reader> {
Ok(self)
}
}