use core::marker::PhantomPinned;
use core::pin::Pin;
use core::ptr;
use std::fs;
use std::path::Path;
use log::debug;
use memmap2::{Mmap, MmapOptions};
use crate::errors::{Error, Result};
pub(crate) struct BinaryParser {
bytes: Mmap,
object: Option<goblin::Object<'static>>,
_pin: PhantomPinned,
}
impl BinaryParser {
pub(crate) fn open(path: &Path) -> Result<Pin<Box<Self>>> {
debug!("Opening binary file '{}'.", path.display());
let file = fs::File::open(path).map_err(|r| Error::from_io1(r, "open file", path))?;
let bytes = unsafe { MmapOptions::new().map(&file) }
.map_err(|r| Error::from_io1(r, "map file", path))?;
let mut result = Box::pin(Self {
bytes,
object: None,
_pin: PhantomPinned,
});
let bytes_ref: &'static Mmap =
unsafe { ptr::NonNull::from(&result.bytes).as_ptr().as_ref().unwrap() };
debug!("Parsing binary file '{}'.", path.display());
let object =
goblin::Object::parse(bytes_ref).map_err(|source| Error::ParseFile { source })?;
result.as_mut().set_object(Some(object));
Ok(result)
}
pub(crate) fn object(&self) -> &goblin::Object<'_> {
self.object.as_ref().unwrap()
}
pub(crate) fn bytes(&self) -> &[u8] {
&self.bytes
}
fn set_object(mut self: Pin<&mut Self>, object: Option<goblin::Object<'static>>) {
let this = Pin::as_mut(&mut self);
unsafe { Pin::get_unchecked_mut(this) }.object = object;
}
fn drop_pinned(self: Pin<&mut Self>) {
self.set_object(None);
}
}
impl Drop for BinaryParser {
fn drop(&mut self) {
unsafe { Pin::new_unchecked(self) }.drop_pinned();
}
}