#pragma once // Check Architecture #ifndef __arm__ #error "Symbols Are ARM-Only" #endif // Headers #include #include #include #include #include #include #include // Virtual Function Information template class __Function; template class __VirtualFunctionInfo { __VirtualFunctionInfo(T *const addr_, void *const parent_): addr(addr_), parent(parent_) {} bool can_overwrite() const { return ((void *) *addr) != parent; } T *const addr; void *const parent; friend class __Function>; }; // Thunks template struct __Thunk; typedef void *(*thunk_enabler_t)(void *target, void *thunk); extern thunk_enabler_t thunk_enabler; // Function Information template class __Function { public: // Types using ptr_type = Ret (*)(Args...); using type = std::function; using overwrite_type = std::function; // Normal Function __Function(const char *const name_, const ptr_type func_, const ptr_type thunk_): enabled(true), name(name_), is_virtual(false), func(func_), backup(func_), thunk(thunk_) {} // Virtual Function __Function(const char *const name_, const __VirtualFunctionInfo virtual_info_, const ptr_type thunk_): enabled(virtual_info_.can_overwrite()), name(name_), is_virtual(true), func(virtual_info_), backup(*get_vtable_addr()), thunk(thunk_) {} __Function(const char *const name_, ptr_type *const func_, void *const parent, const ptr_type thunk_): __Function(name_, __VirtualFunctionInfo(func_, parent), thunk_) {} // Overwrite Function bool overwrite(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, args...); }; return true; } // Getters ptr_type get_backup() const { return backup; } ptr_type get() { if (!enabled) { return nullptr; } else { enable_thunk(); if (is_virtual) { return *get_vtable_addr(); } else { return func.normal_addr; } } } ptr_type *get_vtable_addr() const { if (is_virtual) { return func.virtual_info.addr; } else { return nullptr; } } const char *get_name() const { return name; } private: // State const bool enabled; const char *const name; // Current Function const bool is_virtual; union __FunctionInfo { explicit __FunctionInfo(const ptr_type normal_addr_): normal_addr(normal_addr_) {} explicit __FunctionInfo(const __VirtualFunctionInfo virtual_info_): virtual_info(virtual_info_) {} ptr_type normal_addr; const __VirtualFunctionInfo virtual_info; } func; // Backup Of Original Function Pointer const ptr_type backup; // Thunk const ptr_type thunk; bool thunk_enabled = false; type thunk_target; void enable_thunk() { if (!thunk_enabled) { ptr_type real_thunk = (ptr_type) thunk_enabler((void *) backup, (void *) thunk); if (!is_virtual) { func.normal_addr = real_thunk; } thunk_enabled = true; } } type get_thunk_target() const { if (thunk_target) { return thunk_target; } else { return backup; } } friend struct __Thunk; }; // Shortcuts typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; // Duplicate VTable #define RTTI_SIZE 4 template T *dup_vtable(T *vtable) { // Check static_assert(std::is_constructible::value, "Unable To Construct VTable"); // Get Size uchar *real_vtable = (uchar *) vtable; real_vtable -= RTTI_SIZE; size_t real_vtable_size = sizeof(T) + RTTI_SIZE; // Allocate uchar *new_vtable = (uchar *) ::operator new(real_vtable_size); // Copy memcpy((void *) new_vtable, (void *) real_vtable, real_vtable_size); // Return new_vtable += RTTI_SIZE; return (T *) new_vtable; } #undef RTTI_SIZE // Forward Declarations {{ forwardDeclarations }} // Extra Headers {{ extraHeaders }} // Warnings #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Winvalid-offsetof" #pragma GCC diagnostic ignored "-Wshadow" {{ main }} // Cleanup Warnings #pragma GCC diagnostic pop