1#![deny(clippy::all, clippy::pedantic)]
2#![warn(clippy::nursery)]
3#[allow(non_camel_case_types)]
4pub mod bind;
6mod error;
7
8use std::{
9 ffi::{c_void, CStr, CString},
10 ptr,
11};
12
13pub use error::Error;
14
15pub type Address = *mut c_void;
17
18#[allow(clippy::missing_panics_doc)]
28#[allow(clippy::as_ptr_cast_mut)]
29pub unsafe fn patch_code(addr: Address, code: &[u8]) -> Result<(), Error> {
30 let ret = match bind::DobbyCodePatch(
31 addr,
32 code.as_ptr().cast_mut(),
33 u32::try_from(code.len()).unwrap(),
34 ) {
35 0 => return Ok(()),
36 1 => Error::MemoryOperationError,
37 2 => Error::NotSupportAllocateExecutableMemory,
38 3 => Error::MemoryOperationErrorNotEnough,
39 4 => Error::MemoryOperationErrorNone,
40 _ => unreachable!(),
41 };
42
43 Err(ret)
44}
45
46pub unsafe fn hook(
56 target_func_addr: Address,
57 replace_func_addr: Address,
58 ori_func_save: Option<&mut Address>,
59) -> Result<(), Error> {
60 let result = ori_func_save.map_or_else(
61 || bind::DobbyHook(target_func_addr, replace_func_addr, ptr::null_mut()),
62 |save_ptr| bind::DobbyHook(target_func_addr, replace_func_addr, save_ptr),
63 );
64
65 if result == -1 {
66 return Err(Error::FailedToHook);
67 }
68
69 Ok(())
70}
71
72pub unsafe fn undo_hook(undo_addr: Address) -> Result<(), Error> {
82 if bind::DobbyDestroy(undo_addr) == -1 {
83 Err(Error::FailedToUndoHook)
84 } else {
85 Ok(())
86 }
87}
88
89#[allow(clippy::missing_panics_doc)]
101pub fn resolve_func_addr<S: AsRef<str>>(library: Option<S>, symbol: S) -> Result<Address, Error> {
102 let symbol = symbol.as_ref();
103
104 let addr = unsafe {
105 let symbol = CString::new(symbol).unwrap();
106
107 library.map_or_else(
108 || bind::DobbySymbolResolver(ptr::null(), symbol.as_ptr()),
109 |library| {
110 let library = CString::new(library.as_ref()).unwrap();
111 bind::DobbySymbolResolver(library.as_ptr(), symbol.as_ptr())
112 },
113 )
114 };
115
116 if addr.is_null() {
117 Err(Error::FuncNotFound)
118 } else {
119 Ok(addr)
120 }
121}
122
123#[allow(clippy::missing_panics_doc)]
125#[must_use]
126pub fn get_version() -> &'static str {
127 unsafe { CStr::from_ptr(bind::DobbyGetVersion()).to_str().unwrap() }
128}