retour\detours/
raw.rs

1use crate::arch::Detour;
2use crate::error::Result;
3
4/// A raw detour.
5///
6/// # Example
7///
8/// ```rust
9/// # use retour::Result;
10/// use retour::RawDetour;
11/// use std::mem;
12///
13/// fn add5(val: i32) -> i32 {
14///   val + 5
15/// }
16///
17/// fn add10(val: i32) -> i32 {
18///   val + 10
19/// }
20///
21/// # fn main() -> Result<()> {
22/// let mut hook = unsafe { RawDetour::new(add5 as *const (), add10 as *const ())? };
23///
24/// assert_eq!(add5(5), 10);
25/// assert_eq!(hook.is_enabled(), false);
26///
27/// unsafe { hook.enable()? };
28/// assert!(hook.is_enabled());
29///
30/// let original: fn(i32) -> i32 = unsafe { mem::transmute(hook.trampoline()) };
31///
32/// assert_eq!(add5(5), 15);
33/// assert_eq!(original(5), 10);
34///
35/// unsafe { hook.disable()? };
36/// assert_eq!(add5(5), 10);
37/// # Ok(())
38/// # }
39/// ```
40#[derive(Debug)]
41pub struct RawDetour(Detour);
42
43// TODO: stop all threads in target during patch?
44impl RawDetour {
45  /// Constructs a new inline detour patcher.
46  ///
47  /// The hook is disabled by default. Even when this function is succesful,
48  /// there is no guaranteee that the detour function will actually get called
49  /// when the target function gets called. An invocation of the target
50  /// function might for example get inlined in which case it is impossible to
51  /// hook at runtime.
52  pub unsafe fn new(target: *const (), detour: *const ()) -> Result<Self> {
53    Detour::new(target, detour).map(RawDetour)
54  }
55
56  /// Enables the detour.
57  pub unsafe fn enable(&self) -> Result<()> {
58    self.0.enable()
59  }
60
61  /// Disables the detour.
62  pub unsafe fn disable(&self) -> Result<()> {
63    self.0.disable()
64  }
65
66  /// Returns whether the detour is enabled or not.
67  pub fn is_enabled(&self) -> bool {
68    self.0.is_enabled()
69  }
70
71  /// Returns a reference to the generated trampoline.
72  pub fn trampoline(&self) -> &() {
73    self.0.trampoline()
74  }
75}