2025-02-24 05:23:00 -05:00
|
|
|
#include <functional>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
// Information Interface
|
|
|
|
template <typename Ret, typename... Args>
|
|
|
|
class __FunctionInfo {
|
|
|
|
typedef Ret (*type)(Args...);
|
|
|
|
public:
|
|
|
|
[[nodiscard]] virtual bool can_overwrite() const = 0;
|
|
|
|
[[nodiscard]] virtual type get() const = 0;
|
|
|
|
[[nodiscard]] virtual type *get_addr() const = 0;
|
|
|
|
virtual void update(type new_func) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Thunks
|
|
|
|
typedef void *(*thunk_enabler_t)(void *target, void *thunk);
|
|
|
|
extern thunk_enabler_t thunk_enabler;
|
|
|
|
|
|
|
|
// Function
|
|
|
|
template <unsigned int, typename T>
|
|
|
|
class __Function;
|
|
|
|
template <unsigned int discriminator, typename Ret, typename... Args>
|
|
|
|
class __Function<discriminator, Ret(Args...)> final {
|
|
|
|
// Prevent Copying
|
|
|
|
__PREVENT_COPY(__Function);
|
|
|
|
__PREVENT_DESTRUCTION(__Function);
|
|
|
|
|
|
|
|
// Instance
|
2025-02-25 03:03:26 -05:00
|
|
|
static __Function *instance;
|
2025-02-24 05:23:00 -05:00
|
|
|
|
|
|
|
// Current Function
|
|
|
|
typedef __FunctionInfo<Ret, Args...> *func_t;
|
|
|
|
const func_t func;
|
|
|
|
|
|
|
|
public:
|
|
|
|
// Types
|
|
|
|
typedef Ret (*ptr_type)(Args...);
|
|
|
|
typedef std::function<Ret(Args...)> type;
|
|
|
|
typedef std::function<Ret(const type &, Args...)> overwrite_type;
|
|
|
|
|
|
|
|
// State
|
|
|
|
const bool enabled;
|
|
|
|
const char *const name;
|
|
|
|
|
|
|
|
// Backup Of Original Function Pointer
|
|
|
|
const ptr_type backup;
|
|
|
|
|
|
|
|
#ifdef {{ BUILDING_SYMBOLS_GUARD }}
|
|
|
|
// Constructor
|
|
|
|
__Function(const char *const name_, const func_t func_):
|
|
|
|
func(func_),
|
|
|
|
enabled(func->can_overwrite()),
|
|
|
|
name(name_),
|
|
|
|
backup(func->get())
|
|
|
|
{
|
|
|
|
instance = this;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
// Prevent Construction
|
|
|
|
__PREVENT_JUST_CONSTRUCTION(__Function);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Overwrite Function
|
|
|
|
[[nodiscard]] bool overwrite(const overwrite_type &target) {
|
|
|
|
// Check If Enabled
|
|
|
|
if (!enabled) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Enable Thunk
|
|
|
|
enable_thunk();
|
|
|
|
// Overwrite
|
|
|
|
type original = get_thunk_target();
|
|
|
|
thunk_target = [original, target](Args... args) {
|
|
|
|
return target(original, std::forward<Args>(args)...);
|
|
|
|
};
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Getters
|
|
|
|
[[nodiscard]] ptr_type get(const bool result_will_be_stored) {
|
|
|
|
if (!enabled) {
|
|
|
|
return nullptr;
|
|
|
|
} else {
|
|
|
|
if (result_will_be_stored) {
|
|
|
|
enable_thunk();
|
|
|
|
}
|
|
|
|
return func->get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[[nodiscard]] ptr_type *get_vtable_addr() const {
|
|
|
|
return func->get_addr();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Thunk
|
|
|
|
[[nodiscard]] type get_thunk_target() const {
|
|
|
|
if (thunk_target) {
|
|
|
|
return thunk_target;
|
|
|
|
} else {
|
|
|
|
return backup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static Ret thunk(Args... args) {
|
|
|
|
return instance->get_thunk_target()(std::forward<Args>(args)...);
|
|
|
|
}
|
|
|
|
// Enable Thunk
|
|
|
|
type thunk_target;
|
|
|
|
bool thunk_enabled = false;
|
|
|
|
void enable_thunk() {
|
|
|
|
if (!thunk_enabled && enabled) {
|
|
|
|
ptr_type real_thunk = (ptr_type) thunk_enabler((void *) backup, (void *) thunk);
|
|
|
|
func->update(real_thunk);
|
|
|
|
thunk_enabled = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|