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<*const c_void> {
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(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);
}
}
}