symbol-processor/data/out.h

189 lines
4.8 KiB
C
Raw Normal View History

2024-07-14 09:03:18 +00:00
#pragma once
// Check Architecture
#ifndef __arm__
#error "Symbols Are ARM-Only"
#endif
// Headers
#include <cstddef>
#include <string>
#include <vector>
#include <map>
#include <functional>
#include <type_traits>
#include <cstring>
// Virtual Function Information
template <typename T>
class __Function;
template <typename T>
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;
2024-07-16 17:46:20 +00:00
friend class __Function<std::remove_pointer_t<T>>;
2024-07-14 09:03:18 +00:00
};
// Thunks
template <typename T>
struct __Thunk;
typedef void *(*thunk_enabler_t)(void *target, void *thunk);
extern thunk_enabler_t thunk_enabler;
// Function Information
template <typename Ret, typename... Args>
class __Function<Ret(Args...)> {
public:
// Types
using ptr_type = Ret (*)(Args...);
using type = std::function<Ret(Args...)>;
using overwrite_type = std::function<Ret(type, Args...)>;
// 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<ptr_type> 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<ptr_type> virtual_info_): virtual_info(virtual_info_) {}
ptr_type normal_addr;
const __VirtualFunctionInfo<ptr_type> 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<Ret(Args...)>;
};
// Shortcuts
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
// Duplicate VTable
#define RTTI_SIZE 4
template <typename T>
T *dup_vtable(T *vtable) {
// Check
static_assert(std::is_constructible<T>::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;
}
2024-07-16 17:46:20 +00:00
#undef RTTI_SIZE
2024-07-14 09:03:18 +00:00
// 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