use lief_ffi as ffi;
use crate::common::{FromFFI, into_optional};
use crate::declare_standalone_fwd_iterator;
use std::path::Path;
use super::android;
use super::linux;
use super::osx;
use super::windows;
pub trait Module {
#[doc(hidden)]
fn as_generic(&self) -> &ffi::runtime_Module;
fn name(&self) -> String {
self.as_generic().name().to_string()
}
fn path(&self) -> String {
self.as_generic().path().to_string()
}
fn imagebase(&self) -> u64 {
self.as_generic().imagebase()
}
fn size(&self) -> u64 {
self.as_generic().size()
}
fn end(&self) -> u64 {
self.as_generic().end()
}
fn contains(&self, addr: u64) -> bool {
self.as_generic().contains(addr)
}
fn dump(&self) -> Vec<u8> {
let base = self.imagebase();
let size = self.size() as usize;
if base == 0 || size == 0 {
return Vec::new();
}
unsafe { std::slice::from_raw_parts(base as *const u8, size).to_vec() }
}
fn dump_to_file<P: AsRef<Path>>(&self, path: P) -> Vec<u8> {
let data = self.dump();
let _ = std::fs::write(path, &data);
data
}
}
pub enum Modules {
Linux(linux::Module),
Windows(windows::Module),
Android(android::Module),
Osx(osx::Module),
}
impl FromFFI<ffi::runtime_Module> for Modules {
fn from_ffi(ptr: cxx::UniquePtr<ffi::runtime_Module>) -> Self {
unsafe {
let mod_ref = ptr.as_ref().unwrap();
if ffi::runtime_linux_Module::classof(mod_ref) {
let raw = {
type From = cxx::UniquePtr<ffi::runtime_Module>;
type To = cxx::UniquePtr<ffi::runtime_linux_Module>;
std::mem::transmute::<From, To>(ptr)
};
return Modules::Linux(linux::Module::from_ffi(raw));
} else if ffi::runtime_windows_Module::classof(mod_ref) {
let raw = {
type From = cxx::UniquePtr<ffi::runtime_Module>;
type To = cxx::UniquePtr<ffi::runtime_windows_Module>;
std::mem::transmute::<From, To>(ptr)
};
return Modules::Windows(windows::Module::from_ffi(raw));
} else if ffi::runtime_android_Module::classof(mod_ref) {
let raw = {
type From = cxx::UniquePtr<ffi::runtime_Module>;
type To = cxx::UniquePtr<ffi::runtime_android_Module>;
std::mem::transmute::<From, To>(ptr)
};
return Modules::Android(android::Module::from_ffi(raw));
} else if ffi::runtime_osx_Module::classof(mod_ref) {
let raw = {
type From = cxx::UniquePtr<ffi::runtime_Module>;
type To = cxx::UniquePtr<ffi::runtime_osx_Module>;
std::mem::transmute::<From, To>(ptr)
};
return Modules::Osx(osx::Module::from_ffi(raw));
}
panic!("Unsupported module")
}
}
}
impl Module for Modules {
#[doc(hidden)]
fn as_generic(&self) -> &ffi::runtime_Module {
match &self {
Modules::Linux(module) => module.as_generic(),
Modules::Windows(module) => module.as_generic(),
Modules::Android(module) => module.as_generic(),
Modules::Osx(module) => module.as_generic(),
}
}
}
pub fn modules() -> ModulesIt {
ModulesIt::new(ffi::runtime_modules())
}
pub fn module_from_name(name: &str) -> Option<Modules> {
cxx::let_cxx_string!(s = name);
into_optional(ffi::runtime_module_from_name(&s))
}
pub fn module_from_path<P: AsRef<Path>>(path: P) -> Option<Modules> {
cxx::let_cxx_string!(s = path.as_ref().to_str().unwrap());
into_optional(ffi::runtime_module_from_path(&s))
}
pub fn module_from_addr(addr: u64) -> Option<Modules> {
into_optional(ffi::runtime_module_from_addr(addr))
}
declare_standalone_fwd_iterator!(
ModulesIt,
Modules,
ffi::runtime_Module,
ffi::runtime_it_modules
);