#![deny(clippy::all, clippy::pedantic)]
#![warn(clippy::nursery)]
#[allow(non_camel_case_types)]
pub mod bind;
mod error;
use std::{
convert::AsRef,
ffi::{c_void, CStr, CString},
ptr,
};
pub use error::Error;
pub type Address = *mut c_void;
#[allow(clippy::missing_panics_doc)]
#[allow(clippy::as_ptr_cast_mut)]
pub unsafe fn patch_code(addr: Address, code: &[u8]) -> Result<(), Error> {
let ret = match bind::DobbyCodePatch(
addr,
code.as_ptr() as *mut _,
u32::try_from(code.len()).unwrap(),
) {
0 => return Ok(()),
1 => Error::MemoryOperationError,
2 => Error::NotSupportAllocateExecutableMemory,
3 => Error::MemoryOperationErrorNotEnough,
4 => Error::MemoryOperationErrorNone,
_ => unreachable!(),
};
Err(ret)
}
pub unsafe fn hook(
target_func_addr: Address,
replace_func_addr: Address,
ori_func_save: Option<&mut Address>,
) -> Result<(), Error> {
let result = ori_func_save.map_or_else(
|| bind::DobbyHook(target_func_addr, replace_func_addr, ptr::null_mut()),
|save_ptr| bind::DobbyHook(target_func_addr, replace_func_addr, save_ptr),
);
if result == -1 {
return Err(Error::FailedToHook);
}
Ok(())
}
pub unsafe fn undo_hook(undo_addr: Address) -> Result<(), Error> {
if bind::DobbyDestroy(undo_addr) == -1 {
Err(Error::FailedToUndoHook)
} else {
Ok(())
}
}
#[allow(clippy::missing_panics_doc)]
pub fn resolve_func_addr<S: AsRef<str>>(library: Option<S>, symbol: S) -> Result<Address, Error> {
let symbol = symbol.as_ref();
let addr = unsafe {
let symbol = CString::new(symbol).unwrap();
library.map_or_else(
|| bind::DobbySymbolResolver(ptr::null(), symbol.as_ptr()),
|library| {
let library = CString::new(library.as_ref()).unwrap();
bind::DobbySymbolResolver(library.as_ptr(), symbol.as_ptr())
},
)
};
if addr.is_null() {
Err(Error::FuncNotFound)
} else {
Ok(addr)
}
}
#[allow(clippy::missing_panics_doc)]
#[must_use]
pub fn get_version() -> &'static str {
unsafe { CStr::from_ptr(bind::DobbyGetVersion()).to_str().unwrap() }
}