Add some utility stuff

This commit is contained in:
William Venner 2021-09-11 02:07:38 +01:00
parent 9ae3c1a18c
commit 36dc7fe6ea
4 changed files with 208 additions and 9 deletions

56
Cargo.lock generated
View File

@ -150,6 +150,16 @@ dependencies = [
"winapi 0.2.8", "winapi 0.2.8",
] ]
[[package]]
name = "proc-macro-crate"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41fdbd1df62156fbc5945f4762632564d7d038153091c3fcf1067f6aef7cff92"
dependencies = [
"thiserror",
"toml",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.29" version = "1.0.29"
@ -181,10 +191,16 @@ dependencies = [
] ]
[[package]] [[package]]
name = "skidscan" name = "serde"
version = "0.1.1" version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89c52ddc5d6dde2bbb702e353d78c059cbbe07f15189ead0b7ac7da49b44bacc" checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
[[package]]
name = "skidscan"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ddb509ef676cf26d1eac42416142360a15862275770dfada57e9b150244912"
dependencies = [ dependencies = [
"libc", "libc",
"skidscan-macros", "skidscan-macros",
@ -193,10 +209,11 @@ dependencies = [
[[package]] [[package]]
name = "skidscan-macros" name = "skidscan-macros"
version = "0.1.1" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c98a622ae309bfbfe69e99bbf9e8ce23efc15817eda4bda1369bbb3eea668f83" checksum = "881ef2150f0e4e2a855bb661a3ecd621ab1b6aa07b34aef941d1bd37b4267e8d"
dependencies = [ dependencies = [
"proc-macro-crate",
"syn", "syn",
] ]
@ -217,6 +234,35 @@ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "thiserror"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.14.0" version = "1.14.0"

View File

@ -1,4 +1,5 @@
#[macro_export] #[macro_export]
/// Common pattern for detouring.
macro_rules! __vtable_offset { macro_rules! __vtable_offset {
($name:ident = { ($name:ident = {
win64: $win64:literal, win64: $win64:literal,
@ -22,7 +23,8 @@ macro_rules! __vtable_offset {
} }
#[macro_export] #[macro_export]
macro_rules! __vtable_func { /// Common pattern for detouring.
macro_rules! __gmod_func {
($ty:ident = extern fn($($ident:ident: $arg:ty),*) $(-> $rtn:ty)?) => { ($ty:ident = extern fn($($ident:ident: $arg:ty),*) $(-> $rtn:ty)?) => {
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
pub type $ty = extern "fastcall" fn($($ident: $arg),*) $(-> $rtn)?; pub type $ty = extern "fastcall" fn($($ident: $arg),*) $(-> $rtn)?;
@ -36,6 +38,7 @@ macro_rules! __vtable_func {
} }
#[macro_export] #[macro_export]
/// Common pattern for detouring.
macro_rules! __hook_func { macro_rules! __hook_func {
($ty:ident = extern fn $fn:ident($($ident:ident: $arg:ty),*) $(-> $rtn:ty)? $code:block) => { ($ty:ident = extern fn $fn:ident($($ident:ident: $arg:ty),*) $(-> $rtn:ty)? $code:block) => {
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
@ -57,3 +60,49 @@ macro_rules! __hook_func {
extern "C" fn $fn($($ident: $arg),*) $(-> $rtn)? $code extern "C" fn $fn($($ident: $arg),*) $(-> $rtn)? $code
}; };
} }
#[macro_export]
/// Common pattern for detouring.
macro_rules! find_gmod_signature {
(($library:ident, $library_path:ident), @EXPORT = $export:literal) => {
$library.get($export).ok().map(|func: Symbol<'static, _>| *func)
};
(($library:ident, $library_path:ident), @SIG = $sig:literal) => {
$crate::sigscan::signature!($sig).scan_module($library_path).ok().map(|x| std::mem::transmute(x))
};
(($library:ident, $library_path:ident) -> {
win64_x86_64: [$($win64_x86_64:tt)+],
win32_x86_64: [$($win32_x86_64:tt)+],
linux64_x86_64: [$($linux64_x86_64:tt)+],
linux32_x86_64: [$($linux32_x86_64:tt)+],
win32: [$($win32:tt)+],
linux32: [$($linux32:tt)+],
}) => {{
let x86_64 = $crate::is_x86_64();
if x86_64 {
#[cfg(all(target_os = "windows", target_pointer_width = "64"))] {
$crate::find_gmod_signature!(($library, $library_path), $($win64_x86_64)+)
}
#[cfg(all(target_os = "windows", target_pointer_width = "32"))] {
$crate::find_gmod_signature!(($library, $library_path), $($win32_x86_64)+)
}
#[cfg(all(target_os = "linux", target_pointer_width = "64"))] {
$crate::find_gmod_signature!(($library, $library_path), $($linux64_x86_64)+)
}
#[cfg(all(target_os = "linux", target_pointer_width = "32"))] {
$crate::find_gmod_signature!(($library, $library_path), $($linux32_x86_64)+)
}
} else {
#[cfg(target_os = "windows")] {
$crate::find_gmod_signature!(($library, $library_path), $($win32)+)
}
#[cfg(target_os = "linux")] {
$crate::find_gmod_signature!(($library, $library_path), $($linux32)+)
}
}
}}
}

View File

@ -15,3 +15,103 @@ pub mod msgc;
/// Advanced dark magic utilities /// Advanced dark magic utilities
pub mod hax; pub mod hax;
/// Returns whether this client is running the x86-64 branch
///
/// Current implementation checks the LuaJIT version exported by lua_shared
pub fn is_x86_64() -> bool {
lua::LUA_SHARED.x86_64
}
/// Opens & returns a shared library loaded by Garry's Mod using the raw path to the module.
///
/// # Example
/// ```no_run
/// // This would only work on Windows x86-64 branch in 64-bit mode
/// let (engine, engine_path): (gmod::libloading::Library, &'static str) = open_library_srv!("bin/win64/engine.dll").expect("Failed to open engine.dll!");
/// println!("Opened engine.dll from: {}", engine_path);
/// ```
#[macro_export]
macro_rules! open_library_raw {
($($path:literal),+) => {
::gmod::libloading::Library::new(concat!($($path),+)).map(|lib| (lib, concat!($($path),+)))
}
}
/// Opens & returns a shared library loaded by Garry's Mod, in "server mode" (will prioritize _srv.so on Linux main branch)
///
/// Respects 32-bit/64-bit main/x86-64 branches and finds the correct library.
///
/// # Example
/// ```no_run
/// let (engine, engine_path): (gmod::libloading::Library, &'static str) = open_library_srv!("engine").expect("Failed to open engine.dll!");
/// println!("Opened engine.dll from: {}", engine_path);
/// ```
#[macro_export]
macro_rules! open_library_srv {
($name:literal) => {{
#[cfg(not(all(any(target_os = "windows", target_os = "linux"), any(target_pointer_width = "32", target_pointer_width = "64"))))] {
compile_error!("Unsupported platform");
}
#[cfg(all(target_os = "windows", target_pointer_width = "64"))] {
::gmod::open_library_raw!("bin/win64/", $name, ".dll")
}
#[cfg(all(target_os = "windows", target_pointer_width = "32"))] {
::gmod::open_library_raw!("bin/", $name, ".dll")
.or_else(|_| ::gmod::open_library_raw!("garrysmod/bin/", $name, ".dll"))
}
#[cfg(all(target_os = "linux", target_pointer_width = "64"))] {
::gmod::open_library_raw!("bin/linux64/", $name, ".so")
.or_else(|_| ::gmod::open_library_raw!("bin/linux64/lib", $name, ".so"))
}
#[cfg(all(target_os = "linux", target_pointer_width = "32"))] {
::gmod::open_library_raw!("bin/linux32/", $name, ".so")
.or_else(|_| ::gmod::open_library_raw!("bin/linux32/lib", $name, ".so"))
.or_else(|_| ::gmod::open_library_raw!("bin/", $name, "_srv.so"))
.or_else(|_| ::gmod::open_library_raw!("bin/lib", $name, "_srv.so"))
.or_else(|_| ::gmod::open_library_raw!("bin/", $name, ".so"))
.or_else(|_| ::gmod::open_library_raw!("bin/lib", $name, ".so"))
}
}};
}
/// Opens & returns a shared library loaded by Garry's Mod. You are most likely looking for `open_library_srv!`, as this will prioritize non-_srv.so libraries on Linux main branch.
///
/// Respects 32-bit/64-bit main/x86-64 branches and finds the correct library.
///
/// # Example
/// ```no_run
/// let (engine, engine_path): (gmod::libloading::Library, &'static str) = open_library!("engine").expect("Failed to open engine.dll!");
/// println!("Opened engine.dll from: {}", engine_path);
/// ```
#[macro_export]
macro_rules! open_library {
($name:literal) => {{
#[cfg(not(all(any(target_os = "windows", target_os = "linux"), any(target_pointer_width = "32", target_pointer_width = "64"))))] {
compile_error!("Unsupported platform");
}
#[cfg(all(target_os = "windows", target_pointer_width = "64"))] {
::gmod::open_library_raw!("bin/win64/", $name, ".dll")
}
#[cfg(all(target_os = "windows", target_pointer_width = "32"))] {
::gmod::open_library_raw!("bin/", $name, ".dll")
.or_else(|_| ::gmod::open_library_raw!("garrysmod/bin/", $name, ".dll"))
}
#[cfg(all(target_os = "linux", target_pointer_width = "64"))] {
::gmod::open_library_raw!("bin/linux64/", $name, ".so")
.or_else(|_| ::gmod::open_library_raw!("bin/linux64/lib", $name, ".so"))
}
#[cfg(all(target_os = "linux", target_pointer_width = "32"))] {
::gmod::open_library_raw!("bin/linux32/", $name, ".so")
.or_else(|_| ::gmod::open_library_raw!("bin/linux32/lib", $name, ".so"))
.or_else(|_| ::gmod::open_library_raw!("bin/", $name, ".so"))
.or_else(|_| ::gmod::open_library_raw!("bin/lib", $name, ".so"))
.or_else(|_| ::gmod::open_library_raw!("bin/", $name, "_srv.so"))
.or_else(|_| ::gmod::open_library_raw!("bin/lib", $name, "_srv.so"))
}
}};
}

View File

@ -69,10 +69,12 @@ impl LuaError {
} }
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub(super) static ref LUA_SHARED: LuaShared = LuaShared::import(); pub(crate) static ref LUA_SHARED: LuaShared = LuaShared::import();
} }
pub(super) struct LuaShared { pub(crate) struct LuaShared {
pub x86_64: bool,
pub lual_loadfile: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, path: LuaString) -> i32>, pub lual_loadfile: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, path: LuaString) -> i32>,
pub lual_loadstring: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, path: LuaString) -> i32>, pub lual_loadstring: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, path: LuaString) -> i32>,
pub lua_getfield: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32, k: LuaString)>, pub lua_getfield: Symbol<'static, unsafe extern "C-unwind" fn(state: LuaState, index: i32, k: LuaString)>,
@ -132,6 +134,8 @@ impl LuaShared {
} }
Self { Self {
x86_64: library.get::<unsafe extern "C-unwind" fn()>(b"luaJIT_version_2_1_0_beta3\0").is_ok(),
lual_loadfile: find_symbol!("luaL_loadfile"), lual_loadfile: find_symbol!("luaL_loadfile"),
lual_loadstring: find_symbol!("luaL_loadstring"), lual_loadstring: find_symbol!("luaL_loadstring"),
lua_getfield: find_symbol!("lua_getfield"), lua_getfield: find_symbol!("lua_getfield"),