10#include "ll/api/base/CompilerPredefine.h"
11#include "ll/api/base/Concepts.h"
12#include "ll/api/base/Macro.h"
13#include "ll/api/memory/Memory.h"
14#include "ll/api/reflection/TypeName.h"
15#include "ll/api/thread/GlobalThreadPauser.h"
22template <
class T,
class Ret,
class... Args>
33template <
class T,
class Ret,
class... Args>
35 using type = Ret (T::*)(Args...)
const;
39using AddConstAtMemberFunT =
typename AddConstAtMemberFun<T>::type;
45enum class HookPriority :
int {
53LLNDAPI
bool shouldHookSuspendThreads();
56hook(FuncPtr target, FuncPtr detour, FuncPtr* originalFunc, HookPriority priority,
bool suspendThreads =
true);
58LLAPI
bool unhook(FuncPtr target, FuncPtr detour,
bool suspendThreads =
true);
61concept FuncPtrType = std::is_function_v<std::remove_pointer_t<T>> || std::is_member_function_pointer_v<T>;
63template <FuncPtrType T>
64constexpr FuncPtr resolveIdentifier(T identifier) {
65 return toFuncPtr(identifier);
69constexpr FuncPtr resolveIdentifier(
SignatureView identifier) {
70 return identifier.resolve();
74constexpr FuncPtr resolveIdentifier(SymbolView identifier) {
75 return identifier.resolve();
79constexpr FuncPtr resolveIdentifier(uintptr_t address) {
80 return toFuncPtr(address);
84constexpr uintptr_t unchecked(T identifier) {
85 return reinterpret_cast<uintptr_t
>(toFuncPtr(identifier));
88template <
class T, auto>
89 requires(!std::is_member_function_pointer_v<T>)
90consteval bool virtualDetector()
noexcept {
93using ::ll::internal::virtualDetector;
99 std::optional<thread::GlobalThreadPauser> pauser;
100 if (shouldHookSuspendThreads()) {
103 (((++Ts::_AutoHookCount == 1) ? Ts::hook(
false) : 0), ...);
105 static void unhook() {
106 std::optional<thread::GlobalThreadPauser> pauser;
107 if (shouldHookSuspendThreads()) {
110 (((--Ts::_AutoHookCount == 0) ? Ts::unhook(
false) : 0), ...);
116 if (
this != std::addressof(other)) {
117 ((++Ts::_AutoHookCount), ...);
129#define LL_HOOK_IMPL(REGISTER, FUNC_PTR, STATIC, CALL, DEF_TYPE, TYPE, PRIORITY, IDENTIFIER, RET_TYPE, ...) \
130 struct DEF_TYPE : public TYPE { \
131 inline static ::std::atomic_uint _AutoHookCount{}; \
134 using _FuncPtr = ::ll::memory::FuncPtr; \
135 using HookPriority = ::ll::memory::HookPriority; \
136 using _RawFuncType = RET_TYPE FUNC_PTR(__VA_ARGS__); \
137 using _RawConstFuncType = ::ll::memory::AddConstAtMemberFunT<_RawFuncType>; \
140 struct _ConstDetector { \
141 [[maybe_unused]] static constexpr bool value = false; \
142 explicit constexpr _ConstDetector(T) {} \
145 [[maybe_unused]] _ConstDetector(T) -> _ConstDetector<T>; \
146 [[maybe_unused]] _ConstDetector(_RawFuncType) -> _ConstDetector<_RawFuncType>; \
148 struct _ConstDetector<_RawConstFuncType> { \
149 [[maybe_unused]] static constexpr bool value = true; \
150 explicit constexpr _ConstDetector(_RawConstFuncType) {} \
152 template <class T = _RawFuncType, std::enable_if_t<std::is_member_function_pointer_v<T>, int> = 0> \
153 [[maybe_unused]] _ConstDetector(_RawConstFuncType) -> _ConstDetector<_RawConstFuncType>; \
155 static constexpr bool _IsConstMemberFunction = decltype(_ConstDetector{IDENTIFIER})::value; \
157 using _OriginFuncType = ::std::conditional_t<_IsConstMemberFunction, _RawConstFuncType, _RawFuncType>; \
159 inline static _FuncPtr _HookTarget{}; \
160 inline static _OriginFuncType _OriginalFunc{}; \
163 static consteval void _Detector() { \
164 if constexpr (requires { ::ll::memory::virtualDetector<T, IDENTIFIER>(); }) { \
165 if constexpr (::ll::memory::virtualDetector<T, IDENTIFIER>()) { \
167 ::ll::traits::always_false<T>, \
168 #IDENTIFIER " is a virtual function, you need use prefix $ workaround to hook it." \
176 requires(::std::is_polymorphic_v<TYPE> && ::std::is_base_of_v<T, TYPE>) \
177 [[nodiscard]] TYPE* thisFor() { \
178 return static_cast<decltype(this)>(reinterpret_cast<T*>(this)); \
180 template <class... Args> \
181 STATIC RET_TYPE origin(Args&&... params) { \
182 return CALL(::std::forward<Args>(params)...); \
185 STATIC RET_TYPE detour(__VA_ARGS__); \
187 static int hook(bool suspendThreads = true) { \
188 _Detector<_OriginFuncType>(); \
189 if (!_HookTarget) _HookTarget = ::ll::memory::resolveIdentifier<_OriginFuncType>(IDENTIFIER); \
190 return ::ll::memory::hook( \
192 ::ll::memory::toFuncPtr(&DEF_TYPE::detour), \
193 reinterpret_cast<_FuncPtr*>(&_OriginalFunc), \
199 static bool unhook(bool suspendThreads = true) { \
200 return ::ll::memory::unhook(_HookTarget, ::ll::memory::toFuncPtr(&DEF_TYPE::detour), suspendThreads); \
204 RET_TYPE DEF_TYPE::detour(__VA_ARGS__)
206#define LL_AUTO_REG_HOOK_IMPL(FUNC_PTR, STATIC, CALL, DEF_TYPE, ...) \
207 LL_VA_EXPAND(LL_HOOK_IMPL( \
208 inline ::ll::memory::HookRegistrar<DEF_TYPE> DEF_TYPE##AutoRegister, \
216#define LL_MANUAL_REG_HOOK_IMPL(...) LL_VA_EXPAND(LL_HOOK_IMPL(, __VA_ARGS__))
218#define LL_STATIC_HOOK_IMPL(...) LL_VA_EXPAND(LL_MANUAL_REG_HOOK_IMPL((*), static, _OriginalFunc, __VA_ARGS__))
220#define LL_AUTO_STATIC_HOOK_IMPL(...) LL_VA_EXPAND(LL_AUTO_REG_HOOK_IMPL((*), static, _OriginalFunc, __VA_ARGS__))
222#define LL_INSTANCE_HOOK_IMPL(DEF_TYPE, TYPE, ...) \
223 LL_VA_EXPAND(LL_MANUAL_REG_HOOK_IMPL((TYPE::*), , (this->*_OriginalFunc), DEF_TYPE, TYPE, __VA_ARGS__))
225#define LL_AUTO_INSTANCE_HOOK_IMPL(DEF_TYPE, TYPE, ...) \
226 LL_VA_EXPAND(LL_AUTO_REG_HOOK_IMPL((TYPE::*), , (this->*_OriginalFunc), DEF_TYPE, TYPE, __VA_ARGS__))
239#define LL_TYPE_STATIC_HOOK(DEF_TYPE, PRIORITY, TYPE, IDENTIFIER, RET_TYPE, ...) \
240 LL_VA_EXPAND(LL_STATIC_HOOK_IMPL(DEF_TYPE, TYPE, PRIORITY, IDENTIFIER, RET_TYPE, __VA_ARGS__))
252#define LL_STATIC_HOOK(DEF_TYPE, PRIORITY, IDENTIFIER, RET_TYPE, ...) \
253 LL_VA_EXPAND(LL_STATIC_HOOK_IMPL(DEF_TYPE, ::ll::memory::Hook, PRIORITY, IDENTIFIER, RET_TYPE, __VA_ARGS__))
260#define LL_AUTO_TYPE_STATIC_HOOK(DEF_TYPE, PRIORITY, TYPE, IDENTIFIER, RET_TYPE, ...) \
261 LL_VA_EXPAND(LL_AUTO_STATIC_HOOK_IMPL(DEF_TYPE, TYPE, PRIORITY, IDENTIFIER, RET_TYPE, __VA_ARGS__))
268#define LL_AUTO_STATIC_HOOK(DEF_TYPE, PRIORITY, IDENTIFIER, RET_TYPE, ...) \
269 LL_VA_EXPAND(LL_AUTO_STATIC_HOOK_IMPL(DEF_TYPE, ::ll::memory::Hook, PRIORITY, IDENTIFIER, RET_TYPE, __VA_ARGS__))
282#define LL_TYPE_INSTANCE_HOOK(DEF_TYPE, PRIORITY, TYPE, IDENTIFIER, RET_TYPE, ...) \
283 LL_VA_EXPAND(LL_INSTANCE_HOOK_IMPL(DEF_TYPE, TYPE, PRIORITY, IDENTIFIER, RET_TYPE, __VA_ARGS__))
295#define LL_INSTANCE_HOOK(DEF_TYPE, PRIORITY, IDENTIFIER, RET_TYPE, ...) \
296 LL_VA_EXPAND(LL_INSTANCE_HOOK_IMPL(DEF_TYPE, ::ll::memory::Hook, PRIORITY, IDENTIFIER, RET_TYPE, __VA_ARGS__))
303#define LL_AUTO_TYPE_INSTANCE_HOOK(DEF_TYPE, PRIORITY, TYPE, IDENTIFIER, RET_TYPE, ...) \
304 LL_VA_EXPAND(LL_AUTO_INSTANCE_HOOK_IMPL(DEF_TYPE, TYPE, PRIORITY, IDENTIFIER, RET_TYPE, __VA_ARGS__))
311#define LL_AUTO_INSTANCE_HOOK(DEF_TYPE, PRIORITY, IDENTIFIER, RET_TYPE, ...) \
312 LL_VA_EXPAND(LL_AUTO_INSTANCE_HOOK_IMPL(DEF_TYPE, ::ll::memory::Hook, PRIORITY, IDENTIFIER, RET_TYPE, __VA_ARGS__))
Definition Signature.h:43