mod errors;
mod ffi;
mod symbols;
#[cfg(test)]
mod tests;
use std::ffi::CString;
use std::mem::MaybeUninit;
use std::path::Path;
use std::ptr;
use libc::c_void;
pub use errors::{Error, ErrorKind, Result};
pub use symbols::Symbol;
pub struct ObjectFile {
c_object: ffi::plthook_t,
}
impl ObjectFile {
pub fn open_main_program() -> Result<Self> {
let res = unsafe { ffi::exts::open_cstr(ptr::null()) };
res.map(|c_object| ObjectFile { c_object })
}
#[cfg(unix)]
pub fn open_file<P: AsRef<Path>>(filename: P) -> Result<Self> {
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
let filename_bytes = AsRef::<OsStr>::as_ref(filename.as_ref()).as_bytes();
let filename = match CString::new(filename_bytes) {
Ok(f) => f,
Err(_) => {
return Err(Error::new(ErrorKind::FileNotFound, String::new()));
}
};
let res = unsafe { ffi::exts::open_cstr(filename.as_ptr()) };
res.map(|c_object| ObjectFile { c_object })
}
#[cfg(windows)]
pub fn open_file<P: AsRef<Path>>(filename: P) -> Result<Self> {
let res = ffi::exts::open_path_win32(filename.as_ref());
res.map(|c_object| ObjectFile { c_object })
}
pub unsafe fn open_by_handle(handle: *const c_void) -> Result<Self> {
let mut object = MaybeUninit::uninit();
ffi::exts::check(ffi::plthook_open_by_handle(object.as_mut_ptr(), handle))?;
Ok(ObjectFile {
c_object: object.assume_init(),
})
}
pub unsafe fn replace(
&self,
symbol_name: &str,
func_address: *const c_void,
) -> Result<Replacement<'_>> {
let symbol_name = match CString::new(symbol_name) {
Ok(s) => s,
Err(_) => {
return Err(Error::new(ErrorKind::FunctionNotFound, String::new()));
}
};
let mut old_addr = MaybeUninit::uninit();
ffi::exts::check(ffi::plthook_replace(
self.c_object,
symbol_name.as_ptr(),
func_address,
old_addr.as_mut_ptr(),
))?;
Ok(Replacement {
object: self,
symbol_name,
address: old_addr.assume_init(),
})
}
pub fn symbols(&self) -> impl Iterator<Item = Symbol> + '_ {
symbols::iterator(self)
}
}
impl Drop for ObjectFile {
fn drop(&mut self) {
unsafe {
ffi::plthook_close(self.c_object);
}
}
}
pub struct Replacement<'a> {
object: &'a ObjectFile,
symbol_name: CString,
address: *const c_void,
}
impl Replacement<'_> {
pub fn original_address(&self) -> *const c_void {
self.address
}
pub fn forget(self) {
std::mem::forget(self)
}
}
impl<'a> Drop for Replacement<'a> {
fn drop(&mut self) {
unsafe {
let _ = ffi::exts::check(ffi::plthook_replace(
self.object.c_object,
self.symbol_name.as_ptr(),
self.address,
ptr::null_mut(),
));
};
}
}