remove meta and hook-core remnants

This commit is contained in:
altalk23 2023-01-24 17:51:18 +03:00 committed by alk
parent 8551071ac9
commit a90b3e18dd
29 changed files with 4 additions and 1694 deletions

View file

@ -1,43 +0,0 @@
#pragma once
#include "../meta/meta.hpp"
namespace geode::core {
namespace impl {
/* the handler itself */
template <auto& Det, class Ret, class... Args>
Ret handler(Args... args) {
static thread_local int counter = 0;
if constexpr (std::is_same_v<Ret, void>) {
if (counter == (int)Det->size()) counter = 0;
Det->at(counter++)(args...);
if (--counter < 0) counter = Det->size() - 1;
}
else {
if (counter == (int)Det->size()) counter = 0;
Ret ret = Det->at(counter++)(args...);
if (--counter < 0) counter = Det->size() - 1;
return ret;
}
}
template <template <class, class...> class Conv, auto& Func, class Ret, class... Args>
Ret trampoline(Args... args) {
return meta::Function<Ret(Args...), Conv>(Func)(args...);
}
}
template <template <class, class...> class Conv, auto& Det, class Ret, class... Args>
static inline auto handler =
Conv<Ret, Args...>::template get_wrapper<&impl::handler<Det, Ret, Args...>>();
template <template <class, class...> class Conv, auto& Det, class Ret, class... Args>
static constexpr inline auto trampoline = &impl::trampoline<Conv, Det, Ret, Args...>;
}

View file

@ -1,53 +0,0 @@
#pragma once
#include "../utils/Result.hpp"
#include "Handler.hpp"
#include <vector>
namespace geode::core {
// The handle returned from adding a hook. It is used to remove a hook.
struct HookHandle {
void* handler;
void* address;
void* detour;
void* trampoline;
};
namespace impl {
// a type alias for convenience and for clear type differentiation inside the source file
using VectorPointer = std::vector<void*>*;
GEODE_DLL void addHook(
void* address, void* detour, VectorPointer* detourVectorAddress, void* generatedHandler,
void** originalTrampolineAddress, void* generatedTrampoline
);
GEODE_DLL void removeHook(HookHandle const& handle);
}
namespace hook {
template <auto Detour, template <class, class...> class Conv, class Ret, class... Args>
Result<HookHandle> add(Ret (*address)(Args...)) {
static std::vector<decltype(Detour)>* detourVector;
static decltype(Detour) originalTrampoline;
void* generatedHandler = (void*)handler<Conv, detourVector, Ret, Args...>;
void* generatedTrampoline = (void*)trampoline<Conv, originalTrampoline, Ret, Args...>;
impl::addHook(
(void*)address, (void*)Detour, (impl::VectorPointer*)&detourVector,
(void*)generatedHandler, (void**)&originalTrampoline, (void*)generatedTrampoline
);
return Ok<HookHandle>({ (void*)generatedHandler, (void*)address, (void*)Detour,
(void*)generatedTrampoline });
}
inline Result<> remove(HookHandle const& handle) {
impl::removeHook(handle);
return Ok();
}
}
}

View file

@ -1,7 +1,6 @@
#pragma once
#include "../DefaultInclude.hpp"
#include "../hook-core/Hook.hpp"
#include "../utils/general.hpp"
#include "../external/json/json_fwd.hpp"
#include "Tulip.hpp"

View file

@ -1,44 +0,0 @@
#ifndef GEODE_CORE_META_CALLCONV_HPP
#define GEODE_CORE_META_CALLCONV_HPP
#include "tuple.hpp"
#include <array>
#include <utility>
namespace geode::core::meta {
/* CRTP class for creating calling conventions for Function and Hook.
* Provides some utilities for less verbose filtering of parameters, and
* some wrappers to require the custom calling convention to supply an
* invoker and a way to get a wrapper for hooks.
*/
template <class Ret, class... Args>
class CallConv {
protected:
using MyTuple = Tuple<Args...>;
template <auto>
class arr_to_seq_impl;
template <class Type, size_t length, std::array<Type, length> const* arr>
class arr_to_seq_impl<arr> {
private:
template <class>
class getter;
template <size_t... indices>
class getter<std::index_sequence<indices...>> {
public:
using result = std::index_sequence<arr->at(indices)...>;
};
public:
using result = typename getter<std::make_index_sequence<length>>::result;
};
template <auto& arr>
using arr_to_seq = typename arr_to_seq_impl<&arr>::result;
};
}
#endif /* GEODE_CORE_META_CALLCONV_HPP */

View file

@ -1,26 +0,0 @@
#ifndef GEODE_CORE_META_CDECL_HPP
#define GEODE_CORE_META_CDECL_HPP
namespace geode::core::meta::x86 {
template <class Ret, class... Args>
class Cdecl {
private:
template <Ret (*detour)(Args...)>
static Ret __cdecl wrapper(Args... all) {
return detour(all...);
}
public:
static Ret invoke(void* address, Args... all) {
Ret(__cdecl * raw)(Args...) = reinterpret_cast<decltype(raw)>(address);
return raw(all...);
}
template <Ret (*detour)(Args...)>
static auto get_wrapper() {
return reinterpret_cast<void*>(&wrapper<detour>);
}
};
}
#endif /* GEODE_CORE_META_THISCALL_HPP */

View file

@ -1,14 +0,0 @@
#ifndef GEODE_CORE_META_COMMON_HPP
#define GEODE_CORE_META_COMMON_HPP
#include <type_traits>
namespace geode::core::meta {
template <class Type, class... Compare>
static constexpr bool any_of = (std::is_same_v<Type, Compare> || ...);
template <class... Classes>
static constexpr bool always_false = false;
}
#endif /* GEODE_CORE_META_COMMON_HPP */

View file

@ -1,20 +0,0 @@
#ifndef GEODE_CORE_META_DEFAULTCONV_HPP
#define GEODE_CORE_META_DEFAULTCONV_HPP
namespace geode::core::meta {
template <class Ret, class... Args>
class DefaultConv {
public:
static Ret invoke(void* address, Args... all) {
Ret (*raw)(Args...) = reinterpret_cast<decltype(raw)>(address);
return raw(all...);
}
template <Ret (*detour)(Args...)>
static auto get_wrapper() {
return reinterpret_cast<void*>(detour);
}
};
}
#endif /* GEODE_CORE_META_DEFAULTCONV_HPP */

View file

@ -1,37 +0,0 @@
#ifndef GEODE_CORE_META_FUNCTION_HPP
#define GEODE_CORE_META_FUNCTION_HPP
#include "callconv.hpp"
#include "common.hpp"
#include "tuple.hpp"
#include <type_traits>
namespace geode::core::meta {
/* The Geode Function class wraps functions with unconventional
* calling conventions (how ironic).
*/
template <class Func, template <class, class...> class Conv>
class Function {
static_assert(always_false<Func>, "Not a valid function pointer!");
};
template <class Ret, class... Args, template <class, class...> class Conv>
class Function<Ret(Args...), Conv> {
private:
using MyConv = Conv<Ret, Args...>;
private:
void* addr;
public:
template <class Pointer>
Function(Pointer const& addr) : addr(reinterpret_cast<void*>(addr)) {}
decltype(auto) operator()(Args... all) const {
return MyConv::invoke(addr, all...);
}
};
}
#endif /* GEODE_CORE_META_FUNCTION_HPP */

View file

@ -1,251 +0,0 @@
#ifndef GEODE_CORE_META_MEMBERCALL_HPP
#define GEODE_CORE_META_MEMBERCALL_HPP
#include "callconv.hpp"
#include "tuple.hpp"
#include "x86.hpp"
namespace geode::core::meta::x86 {
template <class T>
concept MembercallStructReturn = std::is_class_v<T> && sizeof(T) > 8;
template <class Ret, class... Args>
class Membercall {};
template <class Ret, class... Args>
requires (!MembercallStructReturn<Ret>)
class Membercall<Ret, Args...> : public CallConv<Ret, Args...> {
protected:
// Metaprogramming / typedefs we need for the rest of the class.
using MyConv = CallConv<Ret, Args...>;
public:
class Sequences {
private:
// These are required for proper reordering.
static constexpr size_t length = sizeof...(Args);
static constexpr size_t SSES = 3;
static constexpr bool is_sse[length] = { sse_passable<Args>... };
static constexpr bool is_gpr[length] = { gpr_passable<Args>... };
static constexpr auto reordered_arr = reorder_pack<Args...>();
// Setup call from our caller, to "foreign" function
static constexpr auto filter_to() {
/* The size of our output may be longer than the input.
* For the third time, annoyingly, we need to make a lambda for this.
*/
constexpr auto arr_size = []() -> size_t {
// Magic constant 5: XMM0, XMM4, XMM5, ECX, and EDX.
size_t size = length + SSES + 5;
// Check our only GPR.
if (0 < length && is_gpr[reordered_arr[0]]) {
--size;
}
/* We assume there are no SSES initially.
* Any SSES we encounter, we have to remove a "duplicate".
*/
for (size_t i = 1; i < SSES + 1; ++i) {
if (i < length && is_sse[reordered_arr[i]]) {
--size;
}
}
return size;
};
std::array<size_t, arr_size()> to = {};
/* These are the indices of the placeholder float and int, for clobbering SSEs and
* GPRs, respectively.
*/
constexpr size_t CLOBBER_SSE = length;
constexpr size_t CLOBBER_GPR = length + 1;
// Put the SSEs into the right XMM registers, if they exist.
for (size_t i = 1; i < SSES + 1; ++i) {
if (i < length && is_sse[reordered_arr[i]]) {
to[i] = reordered_arr[i];
}
else {
to[i] = CLOBBER_SSE;
}
}
// Clobber XMM0, XMM4, XMM5, and EDX.
to[0] = CLOBBER_SSE;
to[4] = CLOBBER_SSE;
to[5] = CLOBBER_SSE;
to[7] = CLOBBER_GPR;
// Handle our GPR and put it in ECX if we can.
if (length > 0 && is_gpr[reordered_arr[0]]) {
to[6] = reordered_arr[0];
}
else {
to[6] = CLOBBER_GPR;
}
for (size_t in = 1, out = SSES + 5; in < length; ++in) {
// Put all non SSEs and non GPRs in their places.
size_t current = reordered_arr[in];
if (!(is_sse[current] && in < SSES + 1)) {
to[out] = current;
++out;
}
}
return to;
}
// Setup call from "foreign" function, to one of ours.
static constexpr auto filter_from() {
std::array<size_t, length> from = {};
constexpr size_t CLOBBER_SSE = length;
constexpr size_t CLOBBER_GPR = length + 1;
if (length > 0 && is_gpr[reordered_arr[0]]) {
// SSES + 3 = ECX
from[reordered_arr[0]] = SSES + 3;
}
for (size_t i = 1, offset = 0; i < length; ++i) {
size_t current = reordered_arr[i];
if (is_sse[current] && i < SSES + 1) {
// If in SSE, retain index
from[current] = i;
}
else {
// If on stack, offset by 8 (6 SSE + 2 GPR registers available)
from[current] = offset + SSES + 5;
++offset;
}
}
return from;
}
// Annoyingly, unless we're using C++20, we can't eliminate these intermediates. (afaik)
static constexpr auto to_arr = filter_to();
static constexpr auto from_arr = filter_from();
public:
using to = typename MyConv::template arr_to_seq<to_arr>;
using from = typename MyConv::template arr_to_seq<from_arr>;
};
protected:
// Where all the logic is actually implemented.
template <class Class, class>
class Impl {
static_assert(
always_false<Class>,
"Please report a bug to the Geode developers! This should never be reached.\n"
"SFINAE didn't reach the right overload!"
);
};
template <size_t... to, size_t... from>
class Impl<std::index_sequence<to...>, std::index_sequence<from...>> {
public:
static Ret invoke(void* address, Tuple<Args..., float, int> const& all) {
return reinterpret_cast<Ret(__vectorcall*)(
typename Tuple<Args..., float, int>::template type_at<to>...
)>(address)(all.template at<to>()...);
}
template <Ret (*detour)(Args...)>
static Ret __vectorcall wrapper(
/* It's wrapped to stop MSVC from giving me error messages with internal compiler
* info. WTF.
*/
typename Tuple<Args..., float, int>::template type_at_wrap<to>... raw
) {
auto all = Tuple<>::make(raw...);
return detour(all.template at<from>()...);
}
};
protected:
// Putting it all together: instantiating Impl with our filters.
using MyImpl = Impl<typename Sequences::to, typename Sequences::from>;
public:
// Just wrapping MyImpl.
static Ret invoke(void* address, Args... all) {
/* The extra float and int here are so that we can grab placeholders.
* If we don't have anything in XMM0 - 5 or ECX / EDX, we will use
* these placeholders instead. The values are 314 to avoid unintentional
* bugs (since 0 may work coincidentally).
*/
return MyImpl::invoke(address, { all..., 314.0f, 314 });
}
template <Ret (*detour)(Args...)>
static auto get_wrapper() {
return reinterpret_cast<void*>(&MyImpl::template wrapper<detour>);
}
};
template <class Ret, class Class, class... Args>
requires (MembercallStructReturn<Ret>)
class Membercall<Ret, Class, Args...> {
protected:
using Sequences = typename Membercall<Ret*, Class, Ret*, Args...>::Sequences;
// Where all the logic is actually implemented.
template <class ImplClass, class>
class Impl {
static_assert(
always_false<ImplClass>,
"Please report a bug to the Geode developers! This should never be reached.\n"
"SFINAE didn't reach the right overload!"
);
};
template <size_t... to, size_t... from>
class Impl<std::index_sequence<to...>, std::index_sequence<from...>> {
public:
static Ret* invoke(void* address, Tuple<Class, Ret*, Args..., float, int> const& all) {
return reinterpret_cast<Ret*(__vectorcall*)(
typename Tuple<Class, Ret*, Args..., float, int>::template type_at<to>...
)>(address)(all.template at<to>()...);
}
template <Ret (*detour)(Class, Args...)>
static Ret* __vectorcall wrapper(
/* It's wrapped to stop MSVC from giving me error messages with internal compiler
* info. WTF.
*/
typename Tuple<Class, Ret*, Args..., float, int>::template type_at_wrap<to>... raw
) {
auto all = Tuple<>::make(raw...);
return reinterpret_cast<Ret*(*)(Class, Ret*, Args...)>(detour)(all.template at<from>()...);
}
};
protected:
// Putting it all together: instantiating Impl with our filters.
using MyImpl = Impl<typename Sequences::to, typename Sequences::from>;
public:
static Ret invoke(void* address, Class inst, Args... all) {
Ret ret;
(void)MyImpl::invoke(address, { inst, &ret, all..., 314.0f, 314 });
return ret;
}
template <Ret (*detour)(Class, Args...)>
static auto get_wrapper() {
return reinterpret_cast<void*>(&MyImpl::template wrapper<detour>);
}
};
}
#endif /* GEODE_CORE_META_MEMBERCALL_HPP */

View file

@ -1,22 +0,0 @@
#ifndef GEODE_CORE_META_META_HPP
#define GEODE_CORE_META_META_HPP
#include "../platform/platform.hpp"
#include "callconv.hpp"
#include "common.hpp"
#include "defaultconv.hpp"
#include "function.hpp"
namespace geode::core::meta {}
namespace geode::core::meta::x86 {}
#if defined(GEODE_IS_WINDOWS)
#include "cdecl.hpp"
#include "membercall.hpp"
#include "optcall.hpp"
#include "thiscall.hpp"
#include "stdcall.hpp"
#endif
#endif /* GEODE_CORE_META_META_HPP */

View file

@ -1,255 +0,0 @@
#ifndef GEODE_CORE_META_OPTCALL_HPP
#define GEODE_CORE_META_OPTCALL_HPP
#include "callconv.hpp"
#include "tuple.hpp"
#include "x86.hpp"
namespace geode::core::meta::x86 {
template <class Ret, class... Args>
class Optcall : public CallConv<Ret, Args...> {
private:
// Metaprogramming / typedefs we need for the rest of the class.
using MyConv = CallConv<Ret, Args...>;
private:
// These go in a class to not pollute the namespace.
class Sequences {
private:
// These are required for proper reordering.
static constexpr size_t length = sizeof...(Args);
static constexpr size_t SSES = 4;
static constexpr bool is_sse[length] = { sse_passable<Args>... };
static constexpr size_t GPRS = 2;
static constexpr bool is_gpr[length] = { gpr_passable<Args>... };
static constexpr auto reordered_arr = reorder_pack<Args...>();
// Setup call from our caller, to "foreign" function
static constexpr auto filter_to() {
/* The size of our output may be longer than the input.
* Also, annoyingly, we must make a lambda to calculate this.
*/
constexpr auto arr_size = []() -> size_t {
// Magic constant 2 is to pad XMM4 and XMM5: can't be used.
size_t size = length + SSES + 2;
/* We assume there are no SSES initially.
* Any SSES we encounter, we have to remove a "duplicate".
*/
for (size_t i = 0; i < SSES; ++i) {
if (i < length && is_sse[reordered_arr[i]]) {
--size;
}
}
return size;
};
std::array<size_t, arr_size()> to = {};
// This is the index of the placeholder float, for clobbering SSEs.
constexpr size_t CLOBBER_SSE = length;
// Put the SSEs into the right XMM registers, if they exist.
for (size_t i = 0; i < SSES; ++i) {
if (i < length && is_sse[reordered_arr[i]]) {
to[i] = reordered_arr[i];
}
else {
to[i] = CLOBBER_SSE;
}
}
// Clobber XMM4 and XMM5.
to[4] = CLOBBER_SSE;
to[5] = CLOBBER_SSE;
for (size_t in = 0, out = SSES + 2; in < length; ++in) {
// Put all the non SSEs in their correct places. Skip SSEs.
size_t current = reordered_arr[in];
if (!(is_sse[current] && in < SSES)) {
to[out] = current;
++out;
}
}
return to;
}
// Setup call from "foreign" function, to one of ours.
static constexpr auto filter_from() {
std::array<size_t, length> from = {};
for (size_t i = 0, gprs = 0, offset = 0; i < length; ++i) {
size_t current = reordered_arr[i];
if (is_sse[current] && i < SSES) {
// If in SSE, retain index
from[current] = i;
}
else if (is_gpr[current] && gprs < GPRS) {
// If in GPR, offset by 4 (4 SSE registers available)
from[current] = gprs + SSES;
++gprs;
}
else {
// If on stack, offset by 6 (4 SSE + 2 GPR registers available)
from[current] = offset + SSES + GPRS;
++offset;
}
}
return from;
}
// Grab only the stack values. For determining stack fixup.
static constexpr auto filter_stack() {
/* The size of our output may be shorter than the input.
* Again, annoyingly, we must make a lambda to calculate this.
*/
constexpr auto arr_size = []() -> size_t {
size_t size = length;
for (size_t i = 0, gprs = 0; i < length; ++i) {
size_t current = reordered_arr[i];
if (is_sse[current] && i < SSES) {
--size;
}
else if (is_gpr[current] && gprs < GPRS) {
--size;
++gprs;
}
}
return size;
};
std::array<size_t, arr_size()> stack = {};
for (size_t in = 0, out = 0, gprs = 0; in < length; ++in) {
size_t current = reordered_arr[in];
if ((!is_sse[current] || in >= SSES) && (!is_gpr[current] || gprs >= GPRS)) {
stack[out] = current;
++out;
}
if (is_gpr[current]) {
++gprs;
}
}
return stack;
}
// Annoyingly, unless we're using C++20, we can't eliminate these intermediates. (afaik)
static constexpr auto to_arr = filter_to();
static constexpr auto from_arr = filter_from();
static constexpr auto stack_arr = filter_stack();
public:
using to = typename MyConv::template arr_to_seq<to_arr>;
using from = typename MyConv::template arr_to_seq<from_arr>;
using stack = typename MyConv::template arr_to_seq<stack_arr>;
};
private:
// Where all the logic is actually implemented.
template <class Class, class, class>
class Impl {
static_assert(
always_false<Class>,
"Please report a bug to the Geode developers! This should never be reached.\n"
"SFINAE didn't reach the right overload!"
);
};
template <size_t... to, size_t... from, size_t... stack>
class Impl<
std::index_sequence<to...>, std::index_sequence<from...>,
std::index_sequence<stack...>> {
private:
static constexpr size_t fix = (std::is_class_v<Ret> ? stack_fix<Ret> : 0) +
stack_fix<typename Tuple<Args...>::template type_at<stack>...>;
public:
static Ret invoke(void* address, Tuple<Args..., float> const& all) {
if constexpr (!std::is_same_v<Ret, void>) {
Ret ret =
reinterpret_cast<Ret(__vectorcall*)(decltype(all.template at<to>())...)>(
address
)(all.template at<to>()...);
if constexpr (fix != 0) {
__asm add esp, [fix]
}
return ret;
}
else {
reinterpret_cast<Ret(__vectorcall*)(decltype(all.template at<to>())...)>(address
)(all.template at<to>()...);
if constexpr (fix != 0) {
__asm add esp, [fix]
}
}
}
template <Ret (*detour)(Args...)>
static Ret __cdecl wrapper(
/* It's wrapped to stop MSVC from giving me error messages with internal compiler
* info. WTF.
*/
typename Tuple<Args...>::template type_at_wrap<stack>... rest
) {
Register<double> f0, f1, f2, f3;
Register<void*> i0, i1;
__asm {
movlpd f0, xmm0
movlpd f1, xmm1
movlpd f2, xmm2
movlpd f3, xmm3
mov i0, ecx
mov i1, edx
}
auto all = Tuple<>::make(f0, f1, f2, f3, i0, i1, rest...);
// Register<Type> has a explicit conversion operator we can take advantage of.
return detour(static_cast<Args>(all.template at<from>())...);
}
};
private:
// Putting it all together: instantiating Impl with our filters.
using MyImpl =
Impl<typename Sequences::to, typename Sequences::from, typename Sequences::stack>;
public:
// Just wrapping MyImpl.
static Ret invoke(void* address, Args... all) {
/* The extra float here is so that we can grab placeholders.
* If we don't have anything in XMM0 - 5, we will use
* this placeholder instead. The value is 314 to avoid unintentional
* bugs (since 0 may work coincidentally).
*/
return MyImpl::invoke(address, { all..., 314.0f });
}
template <Ret (*detour)(Args...)>
static auto get_wrapper() {
return reinterpret_cast<void*>(&MyImpl::template wrapper<detour>);
}
};
template <class Ret>
class Optcall<Ret> : public Cdecl<Ret> {
public:
using Cdecl<Ret>::invoke;
using Cdecl<Ret>::get_wrapper;
};
}
#endif /* GEODE_CORE_META_OPTCALL_HPP */

View file

@ -1,26 +0,0 @@
#ifndef GEODE_CORE_META_STDCALL_HPP
#define GEODE_CORE_META_STDCALL_HPP
namespace geode::core::meta::x86 {
template <class Ret, class... Args>
class Stdcall {
private:
template <Ret (*detour)(Args...)>
static Ret __stdcall wrapper(Args... all) {
return detour(all...);
}
public:
static Ret invoke(void* address, Args... all) {
Ret(__stdcall * raw)(Args...) = reinterpret_cast<decltype(raw)>(address);
return raw(all...);
}
template <Ret (*detour)(Args...)>
static auto get_wrapper() {
return reinterpret_cast<void*>(&wrapper<detour>);
}
};
}
#endif /* GEODE_CORE_META_STDCALL_HPP */

View file

@ -1,26 +0,0 @@
#ifndef GEODE_CORE_META_THISCALL_HPP
#define GEODE_CORE_META_THISCALL_HPP
namespace geode::core::meta::x86 {
template <class Ret, class... Args>
class Thiscall {
private:
template <Ret (*detour)(Args...)>
static Ret __thiscall wrapper(Args... all) {
return detour(all...);
}
public:
static Ret invoke(void* address, Args... all) {
Ret(__thiscall * raw)(Args...) = reinterpret_cast<decltype(raw)>(address);
return raw(all...);
}
template <Ret (*detour)(Args...)>
static auto get_wrapper() {
return reinterpret_cast<void*>(&wrapper<detour>);
}
};
}
#endif /* GEODE_CORE_META_THISCALL_HPP */

View file

@ -1,99 +0,0 @@
#ifndef GEODE_CORE_META_TUPLE_HPP
#define GEODE_CORE_META_TUPLE_HPP
#include "common.hpp"
#include <type_traits>
#include <utility>
namespace geode::core::meta {
/* The Tuple class presents a nicer way to interact with parameter packs.
* While this container is technically usable in other code, this is mostly
* used for static reflection in function wrapping. Other applications will
* usually be better covered by std::tuple.
*/
template <class...>
class Tuple;
template <>
class Tuple<> {
private:
template <class Type, size_t i>
class Element {
private:
Type value;
protected:
constexpr Type at(std::integral_constant<size_t, i>&&) const {
return this->value;
}
public:
constexpr Element(Type value) : value(value) {}
};
template <class... Parents>
class Elements : public Parents... {
private:
using Parents::at...;
public:
static constexpr size_t size = sizeof...(Parents);
template <size_t i>
constexpr decltype(auto) at() const {
static_assert(i < size, "Out of range access!");
return this->at(std::integral_constant<size_t, i>());
}
};
template <class, class...>
class elements_for_impl;
template <size_t... indices, class... Classes>
class elements_for_impl<std::index_sequence<indices...>, Classes...> {
public:
using result = Elements<Element<Classes, indices>...>;
};
public:
template <class... Classes>
using elements_for = typename elements_for_impl<
std::make_index_sequence<sizeof...(Classes)>, Classes...>::result;
template <class... Classes>
static auto make(Classes&&... values) {
return Tuple<Classes...> { values... };
}
};
template <class Current, class... Rest>
class Tuple<Current, Rest...> : public Tuple<>::elements_for<Current, Rest...> {
private:
using MyElements = Tuple<>::elements_for<Current, Rest...>;
public:
template <size_t i>
using type_at = decltype(std::declval<MyElements>().template at<i>());
private:
template <size_t i, bool>
class type_at_wrap_impl {
public:
using result = void;
};
template <size_t i>
class type_at_wrap_impl<i, true> {
public:
using result = type_at<i>;
};
public:
// MSVC literally shows internal compiler structures if I don't wrap this sometimes.
template <size_t i>
using type_at_wrap = typename type_at_wrap_impl<i, (i < sizeof...(Rest) + 1)>::result;
};
}
#endif /* GEODE_CORE_META_TUPLE_HPP */

View file

@ -1,114 +0,0 @@
#ifndef GEODE_CORE_META_X86_HPP
#define GEODE_CORE_META_X86_HPP
#include "common.hpp"
#include <array>
namespace geode::core::meta::x86 {
// Logic needed by x86 calling conventions for stack fixing / filtering.
template <class Class>
static constexpr bool sse_passable = any_of<std::remove_cv_t<Class>, float, double>;
template <class Class>
static constexpr bool gpr_passable =
((sizeof(Class) <= sizeof(void*) && !std::is_class_v<Class> && !sse_passable<Class>) ||
std::is_member_function_pointer_v<Class>);
template <class... Classes>
static inline constexpr std::array<size_t, sizeof...(Classes)> reorder_pack() {
constexpr size_t length = sizeof...(Classes);
constexpr bool should_reorder[] = { std::is_class_v<Classes> &&
sizeof(Classes) > sizeof(void*)... };
std::array<size_t, length> reordered = {};
size_t out = 0;
// Non-reordered go first.
for (size_t in = 0; in < length; ++in) {
if (!should_reorder[in]) {
reordered[out] = in;
++out;
}
}
// Reordered go last.
for (size_t in = 0; in < length; ++in) {
if (should_reorder[in]) {
reordered[out] = in;
++out;
}
}
return reordered;
}
template <class... Stack>
static constexpr size_t stack_fix =
(((sizeof(Stack) % sizeof(void*) == 0)
? sizeof(Stack)
: sizeof(Stack) - (sizeof(Stack) % sizeof(void*)) + sizeof(void*)) +
...);
template <>
static constexpr size_t stack_fix<> = 0;
template <>
static constexpr size_t stack_fix<void> = 0;
template <class From>
class Register {
public:
From raw;
public:
template <class To>
explicit operator To() {
static_assert(
sizeof(From) >= sizeof(To),
"Please report a bug to the Geode developers! This should never be reached.\n"
"Size of Register is smaller than the size of the destination type!"
);
union {
From from;
To to;
} u;
u.from = raw;
return u.to;
}
};
// Ignore this for now, it's for discarding calling convention qualifier later.
#if 0
template <class Func>
class remove_conv {
public:
using result = Func;
};
// We all hate macros but I'd say this is a good use case.
#define REMOVE_FOR(CC) \
template <class Ret, class... Args> \
class remove_conv<Ret(CC*)(Args...)> { \
public: \
using result = Ret (*)(Args...); \
}; \
\
template <class Ret, class Parent, class... Args> \
class remove_conv<Ret (CC Parent::*)(Args...)> { \
public: \
using result = Ret (Parent::*)(Args...); \
}
REMOVE_FOR(__cdecl);
REMOVE_FOR(__stdcall);
REMOVE_FOR(__thiscall);
REMOVE_FOR(__fastcall);
REMOVE_FOR(__vectorcall);
#undef REMOVE_FOR
#endif
}
#endif /* GEODE_CORE_META_X86_HPP */

View file

@ -1,5 +1,4 @@
#pragma once
#include "../meta/meta.hpp"
#include "AsStaticFunction.hpp"
#include "Field.hpp"
#include "IDManager.hpp"
@ -96,7 +95,7 @@ namespace geode::modifier {
class ModifyDerive {
public:
ModifyDerive() {
static_assert(core::meta::always_false<Derived>, "Custom Modify not implemented.");
static_assert(alwaysFalse<Derived>, "Custom Modify not implemented.");
}
};
}

View file

@ -27,6 +27,9 @@ namespace geode::modifier {
using type = FunctionType*;
};
template <class...>
static constexpr bool alwaysFalse = false;
/**
* The ~unevaluated~ function that gets the appropriate
* version of a function type from its return, parameters, and classes.

View file

@ -4,11 +4,6 @@
#pragma warning(disable : 4251) // dll-interface
#pragma warning(disable : 4244) // narrowing conversion
#include <Geode/meta/cdecl.hpp>
#include <Geode/meta/function.hpp>
#include <Geode/meta/membercall.hpp>
#include <Geode/meta/optcall.hpp>
#include <Geode/meta/thiscall.hpp>
#include <Windows.h>
#include <cstring>
#include <type_traits>

View file

@ -1,189 +0,0 @@
#include "Core.hpp"
#include <map>
#ifndef GEODE_IS_WINDOWS
#if defined(GEODE_IS_MACOS)
#include "../platform/mac/Core.hpp"
#elif defined(GEODE_IS_IOS)
// #include "iOS.hpp"
#endif
namespace geode::core::impl {
namespace {
auto& originalBytes() {
static std::map<void*, std::vector<std::byte>*> ret;
return ret;
}
auto& unhandledTrampolines() {
static std::map<void*, void*> ret;
return ret;
}
auto& unhandledHandlers() {
static std::map<void*, void*> ret;
return ret;
}
}
void* generateRawTrampoline(void* address) {
static constexpr size_t MAX_TRAMPOLINE_SIZE = 0x40;
auto trampoline = TargetPlatform::allocateVM(MAX_TRAMPOLINE_SIZE);
unhandledTrampolines()[address] = trampoline;
// we need to add a trap instruction to the trampoline
// so that it will go to handleContext
const size_t trapSize = TargetPlatform::getTrapSize();
TargetPlatform::writeMemory(trampoline, (void*)TargetPlatform::getTrap().data(), trapSize);
return trampoline;
}
void addJump(void* at, void* to) {
if (unhandledTrampolines().find(at) != unhandledTrampolines().end()) {
// we havent set up the trampoline yet, so this means
// we need to preserve the original bytes to use when
// populating the trampoline. we need to save the handler
// to set a jump to it when we finish the trampoline too.
const size_t jumpSize = TargetPlatform::getJumpSize(at, to);
originalBytes().insert({ at, new std::vector<std::byte>(jumpSize, std::byte(0x00)) });
TargetPlatform::writeMemory((void*)originalBytes()[at]->data(), at, jumpSize);
unhandledHandlers()[at] = to;
}
TargetPlatform::writeMemory(
at, (void*)TargetPlatform::getJump(at, to).data(), TargetPlatform::getJumpSize(at, to)
);
}
void handleContext(void* context, void* current) {
static thread_local void* original = nullptr;
static thread_local bool originalFlag = false;
for (auto& [k, v] : unhandledTrampolines()) {
if (v == current) {
// we are inside a trampoline, which means we need
// to jump to the original function and add a trap
// instruction to the original function to mark the
// beginning of the instruction measuring
const size_t jumpSize = TargetPlatform::getJumpSize(current, k);
TargetPlatform::writeMemory(
current, (void*)TargetPlatform::getJump(current, k).data(), jumpSize
);
const size_t trapSize = TargetPlatform::getTrapSize();
TargetPlatform::writeMemory(k, (void*)TargetPlatform::getTrap().data(), trapSize);
originalFlag = true;
return;
}
}
if (originalFlag) {
// we are at the beginning of the original function,
// which means we need to put back the original
// instructions and enable single stepping to
// come back to here every instruction
//
// we can get rid of the original bytes vector since
// we already recovered it
original = current;
originalFlag = false;
auto origBytes = originalBytes()[original];
TargetPlatform::writeMemory(original, (void*)origBytes->data(), origBytes->size());
delete origBytes;
originalBytes().erase(original);
TargetPlatform::enableSingleStep(context);
return;
}
else {
// we are at an instruction somewhere after the
// beginning of the original function, which
// means we need to check if we can fit a jump
// instruction
auto trampoline = unhandledTrampolines()[original];
const size_t jumpSize =
TargetPlatform::getJumpSize(trampoline, unhandledHandlers()[original]);
const size_t difference = (size_t)current - (size_t)original;
if (difference >= jumpSize) {
// we have enough space to fit a jump from the
// beginning of the function to the handler
// now we can copy the instructions we have
// measured to the trampoline, add a jump back
// at the end of it. and also put the jump from
// the original function to the handler.
// now that we are done, we can disable single
// stepping
TargetPlatform::writeMemory(trampoline, original, difference);
TargetPlatform::writeMemory(
(void*)((size_t)trampoline + difference),
(void*)TargetPlatform::getJump(
(void*)((size_t)trampoline + difference),
(void*)((size_t)original + difference)
)
.data(),
difference
);
TargetPlatform::writeMemory(
original,
(void*)TargetPlatform::getJump(original, unhandledHandlers()[original]).data(),
TargetPlatform::getJumpSize(original, unhandledHandlers()[original])
);
TargetPlatform::disableSingleStep(context);
unhandledTrampolines().erase(original);
unhandledHandlers().erase(original);
}
return;
}
}
}
bool geode::core::hook::initialize() {
return geode::core::impl::TargetPlatform::initialize();
}
#else
// #include <dobby.h>
#include <MinHook.h>
namespace geode::core::impl {
namespace {
auto& trampolines() {
static std::map<void*, void*> ret;
return ret;
}
}
void* generateRawTrampoline(void* address) {
return trampolines()[address];
}
void addJump(void* at, void* to) {
// DobbyDestroy(at);
// DobbyHook(at, to, &trampolines()[at]);
MH_RemoveHook(at);
MH_CreateHook(at, to, &trampolines()[at]);
MH_EnableHook(at);
}
}
bool geode::core::hook::initialize() {
return MH_Initialize() == MH_OK;
}
#endif

View file

@ -1,19 +0,0 @@
#pragma once
#include "Platform.hpp"
/*
Internal use functions
*/
namespace geode::core {
namespace impl {
void* generateRawTrampoline(void* address);
void addJump(void* at, void* to);
void handleContext(void* context, void* current);
}
namespace hook {
bool initialize();
}
}

View file

@ -1,122 +0,0 @@
#include "Core.hpp"
#include <Geode/hook-core/Hook.hpp>
#include <unordered_map>
namespace geode::core::impl {
namespace {
inline auto& generatedTrampolines() {
static std::unordered_map<void*, void*> ret;
return ret;
}
inline auto& currentHandlers() {
static std::unordered_map<void*, void*> ret;
return ret;
}
inline auto& mappedTrampolines() {
static std::unordered_map<void*, VectorPointer> ret;
return ret;
}
inline auto& mappedHandlers() {
static std::unordered_map<void*, VectorPointer> ret;
return ret;
}
inline auto& mappedDetours() {
static std::unordered_map<void*, VectorPointer> ret;
return ret;
}
}
void addHook(
void* address, void* detour, VectorPointer* detourVectorAddress, void* generatedHandler,
void** originalTrampolineAddress, void* generatedTrampoline
) {
#ifdef GEODE_IS_WINDOWS
if (mappedHandlers().find(address) == mappedHandlers().end()) {
// std::cout << "allocate handler vector for " << address << std::endl;
mappedHandlers().insert({ address, new std::vector<void*> });
currentHandlers()[address] = generatedHandler;
addJump(address, generatedHandler);
}
mappedHandlers()[address]->push_back(generatedHandler);
#endif
if (mappedTrampolines().find(address) == mappedTrampolines().end()) {
// std::cout << "allocate trampoline vector for " << address << std::endl;
mappedTrampolines().insert({ address, new std::vector<void*> });
if (generatedTrampolines().find(address) == generatedTrampolines().end()) {
generatedTrampolines()[address] = generateRawTrampoline(address);
}
}
auto puretramp = generatedTrampolines()[address];
mappedTrampolines()[address]->push_back(generatedTrampoline);
*originalTrampolineAddress = puretramp;
#ifndef GEODE_IS_WINDOWS
if (mappedHandlers().find(address) == mappedHandlers().end()) {
// std::cout << "allocate handler vector for " << address << std::endl;
mappedHandlers().insert({ address, new std::vector<void*> });
currentHandlers()[address] = generatedHandler;
addJump(address, generatedHandler);
}
mappedHandlers()[address]->push_back(generatedHandler);
#endif
if (mappedDetours().find(address) == mappedDetours().end()) {
// std::cout << "allocate detour vector for " << address << std::endl;
mappedDetours().insert({ address, new std::vector<void*> });
}
auto detours = mappedDetours().at(address);
*detourVectorAddress = detours;
if (detours->size() == 0) {
// std::cout << "add trampoline to the detour vector (it will not get deallocated now)"
// << std::endl;
detours->push_back(mappedTrampolines()[address]->front());
}
detours->insert(detours->end() - 1, detour);
}
void removeHook(HookHandle const& handle) {
auto [handler, address, detour, trampoline] = handle;
auto detours = mappedDetours().at(address);
detours->erase(std::remove(detours->begin(), detours->end(), detour), detours->end());
auto handlers = mappedHandlers().at(address);
handlers->erase(std::remove(handlers->begin(), handlers->end(), handler), handlers->end());
auto trampolines = mappedTrampolines().at(address);
trampolines->erase(
std::remove(trampolines->begin(), trampolines->end(), trampoline), trampolines->end()
);
if (handlers->size() == 0 /* trampolines size should be 0 now */) {
// std::cout << "deallocate handler vector for " << address << std::endl;
delete handlers;
mappedHandlers().erase(address);
// std::cout << "deallocate trampoline vector for " << address << std::endl;
delete trampolines;
mappedTrampolines().erase(address);
// TODO: bandaid
// addJump(address, generatedTrampolines()[address]);
// afterHookHander = (decltype(afterHookHander))generatedTrampoline[address]; // switch
// the trampoline (inline)
}
else if (currentHandlers()[address] == handler) {
// std::cout << "using a different trampoline and handler for " << address << std::endl;
detours->back() = trampolines->front();
currentHandlers()[address] = handlers->front();
addJump(address, handlers->front());
// afterHookHander = (decltype(afterHookHander))(handlers->front()); // switch the
// handler (inline)
}
}
}

View file

@ -1,63 +0,0 @@
#pragma once
#include <Geode/platform/platform.hpp>
#include <vector>
namespace geode::core::impl {
template <typename T>
class Platform {
public:
static const std::vector<std::byte> getTrap() {
return T::trap;
}
static const size_t getTrapSize() {
return T::trap.size();
}
static const std::vector<std::byte> getJump(void* from, void* to) {
// static_assert(&Platform<T>::jump != T::jump, "implement jump");
return T::jump(from, to);
}
static const size_t getJumpSize(void* from, void* to) {
// static_assert(&Platform<T>::jump != T::jump, "implement trap");
return T::jump(from, to).size();
}
static void* allocateVM(size_t size) {
// static_assert(&Platform<T>::allocateVM != T::allocateVM, "implement allocateVM");
return T::allocateVM(size);
}
static bool writeMemory(void* to, void* from, size_t size) {
static_assert(&Platform<T>::writeMemory != &T::writeMemory, "implement writeMemory");
return T::writeMemory(to, from, size);
}
// static bool readMemory(const void* addr, const void* to, const size_t size) {
// static_assert(&Platform<T>::read_memory != &T::read_memory, "implement readMemory");
// return T::readMemory(addr, to, size);
// }
static bool initialize() {
static_assert(&Platform<T>::initialize != &T::initialize, "implement initialize");
return T::initialize();
}
static bool enableSingleStep(void* context) {
static_assert(
&Platform<T>::enableSingleStep != &T::enableSingleStep, "implement enableSingleStep"
);
return T::enableSingleStep(context);
}
static bool disableSingleStep(void* context) {
static_assert(
&Platform<T>::disableSingleStep != &T::disableSingleStep,
"implement disableSingleStep"
);
return T::disableSingleStep(context);
}
};
}

View file

@ -4,10 +4,7 @@
#include <Geode/utils/casts.hpp>
#include <Geode/utils/ranges.hpp>
#include <vector>
// #include <hook/hook.hpp>
#include "ModImpl.hpp"
#include <Geode/hook-core/Hook.hpp>
#include "HookImpl.hpp"
USE_GEODE_NAMESPACE();

View file

@ -4,11 +4,8 @@
#include <Geode/utils/casts.hpp>
#include <Geode/utils/ranges.hpp>
#include <vector>
// #include <hook/hook.hpp>
#include "ModImpl.hpp"
#include <Geode/hook-core/Hook.hpp>
USE_GEODE_NAMESPACE();
class Hook::Impl {

View file

@ -1,4 +1,3 @@
#include "../core/Core.hpp"
#include "loader/LoaderImpl.hpp"
#include <Geode/loader/IPC.hpp>
@ -7,7 +6,6 @@
#include <Geode/loader/Mod.hpp>
#include <Geode/loader/Setting.hpp>
#include <Geode/loader/SettingEvent.hpp>
#include <loader/ModImpl.hpp>
#include <Geode/loader/ModJsonTest.hpp>
#include <Geode/utils/JsonValidation.hpp>
#include <array>
@ -152,17 +150,6 @@ $execute {
}
int geodeEntry(void* platformData) {
// setup internals
if (!geode::core::hook::initialize()) {
LoaderImpl::get()->platformMessageBox(
"Unable to load Geode!",
"There was an unknown fatal error setting up "
"internal tools and Geode can not be loaded. "
"(Unable to set up hook manager)"
);
return 1;
}
// set up internal mod, settings and data
auto internalSetupRes = LoaderImpl::get()->setupInternalMod();

View file

@ -1,116 +0,0 @@
#include "Core.hpp"
#include "../../core/Core.hpp"
#include <Geode/DefaultInclude.hpp>
#ifdef GEODE_IS_MACOS
#include <mach/mach.h>
#include <mach/mach_init.h> /* mach_task_self() */
#include <mach/mach_port.h>
#include <mach/mach_vm.h> /* mach_vm_* */
#include <mach/task.h>
#include <signal.h> /* sigaction */
#include <sys/ucontext.h> /* ucontext_t */
using namespace geode::core::hook;
using namespace geode::core::impl;
namespace {
void signalHandler(int signal, siginfo_t* signal_info, void* vcontext) {
auto context = reinterpret_cast<ucontext_t*>(vcontext);
auto current = reinterpret_cast<void*>(context->uc_mcontext->__ss.__rip);
handleContext(vcontext, current);
}
}
bool MacOSX::enableSingleStep(void* vcontext) {
auto context = reinterpret_cast<ucontext_t*>(vcontext);
context->uc_mcontext->__ss.__rflags |= ((unsigned long)0x100);
return true;
}
bool MacOSX::disableSingleStep(void* vcontext) {
auto context = reinterpret_cast<ucontext_t*>(vcontext);
context->uc_mcontext->__ss.__rflags &= ~((unsigned long)0x100);
return true;
}
void* MacOSX::allocateVM(size_t size) {
mach_vm_address_t ret;
kern_return_t status; // return status
status = mach_vm_allocate(mach_task_self(), &ret, (mach_vm_size_t)size, VM_FLAGS_ANYWHERE);
return (void*)ret;
}
std::vector<std::byte> MacOSX::jump(void* from, void* to) {
constexpr size_t size = sizeof(int) + 1;
std::vector<std::byte> ret(size);
ret[0] = { 0xe9 };
int offset = (int)((size_t)to - (size_t)from - size);
// im too lazy
((int*)((size_t)ret.data() + 1))[0] = offset;
return ret;
}
bool MacOSX::writeMemory(void* to, void* from, size_t size) {
kern_return_t status; // return status
mach_vm_size_t vmsize;
mach_vm_address_t address = (mach_vm_address_t)to;
vm_region_basic_info_data_t info;
mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
mach_port_t object;
// std::cout << "get memory protection" << std::endl;
// // get memory protection
// status = mach_vm_region(mach_task_self(), &address, &vmsize, VM_REGION_BASIC_INFO,
// (vm_region_info_t)&info, &info_count, &object); std::cout << status << std::endl; if (status
// != KERN_SUCCESS) return false;
// std::cout << "set to write protection" << std::endl;
// set to write protection
status = mach_vm_protect(
mach_task_self(), (mach_vm_address_t)to, size, FALSE,
VM_PROT_COPY | VM_PROT_EXECUTE | VM_PROT_WRITE | VM_PROT_READ
);
if (status != KERN_SUCCESS) return false;
// std::cout << "write to memory" << std::endl;
// write to memory
status = mach_vm_write(
mach_task_self(), (mach_vm_address_t)to, (vm_offset_t)from, (mach_msg_type_number_t)size
);
if (status != KERN_SUCCESS) return false;
// std::cout << "revert to old protection" << std::endl;
// // revert to old protection
// status = mach_vm_protect(mach_task_self(), (mach_vm_address_t)to, size, FALSE,
// info.protection); if (status != KERN_SUCCESS) return false;
return status == KERN_SUCCESS;
}
bool MacOSX::initialize() {
task_set_exception_ports(
mach_task_self(), EXC_MASK_BAD_INSTRUCTION,
MACH_PORT_NULL, // m_exception_port,
EXCEPTION_DEFAULT, 0
);
// first reached here
struct sigaction action = {};
action.sa_sigaction = &signalHandler;
action.sa_flags = SA_SIGINFO;
return sigaction(SIGILL, &action, NULL) == 0 && sigaction(SIGTRAP, &action, NULL) == 0;
}
#endif

View file

@ -1,21 +0,0 @@
#pragma once
#include "../../core/Platform.hpp"
#include <vector>
namespace geode::core::impl {
class MacOSX : public Platform<MacOSX> {
public:
static inline auto trap = { std::byte(0x0f), std::byte(0x0b) };
static bool writeMemory(void* to, void* from, size_t size);
static std::vector<std::byte> jump(void* from, void* to);
static bool initialize();
static bool enableSingleStep(void* context);
static bool disableSingleStep(void* context);
static void* allocateVM(size_t size);
};
using TargetPlatform = Platform<MacOSX>;
}

View file

@ -1,81 +0,0 @@
#include "Core.hpp"
#include "../../core/Core.hpp"
#ifdef GEODE_IS_WINDOWS
#include <Windows.h>
using namespace geode::core::hook;
using namespace geode::core::impl;
namespace {
LONG WINAPI signalHandler(EXCEPTION_POINTERS* info) {
#if defined(_WIN64)
auto current = reinterpret_cast<void*>(info->ContextRecord->Rip);
#elif defined(_WIN32)
auto current = reinterpret_cast<void*>(info->ContextRecord->Eip);
#endif
// handleContext(reinterpret_cast<void*>(info), current);
return EXCEPTION_CONTINUE_EXECUTION;
}
}
void* Windows::allocateVM(size_t size) {
return VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
}
std::vector<std::byte> Windows::jump(void* from, void* to) {
std::vector<std::byte> ret;
ret.resize(5, std::byte(0u));
ret[0] = std::byte(0xe9);
// target - src - 5
intptr_t offset = reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from) - 5;
std::byte data[4];
std::memcpy(data, &offset, 4);
ret[1] = data[0];
ret[2] = data[1];
ret[3] = data[2];
ret[4] = data[3];
return ret;
}
bool Windows::enableSingleStep(void* vcontext) {
auto info = reinterpret_cast<EXCEPTION_POINTERS*>(vcontext);
#if defined(_WIN64)
info->ContextRecord->RFlags |= ((QWORD)0x100);
#elif defined(_WIN32)
info->ContextRecord->EFlags |= ((DWORD)0x100);
#endif
return true;
}
bool Windows::disableSingleStep(void* vcontext) {
auto info = reinterpret_cast<EXCEPTION_POINTERS*>(vcontext);
#if defined(_WIN64)
info->ContextRecord->RFlags &= ~((QWORD)0x100);
#elif defined(_WIN32)
info->ContextRecord->EFlags &= ~((DWORD)0x100);
#endif
return true;
}
bool Windows::writeMemory(void* to, void* from, size_t size) {
DWORD old;
VirtualProtect(to, size, PAGE_EXECUTE_READWRITE, &old);
auto res = WriteProcessMemory(GetCurrentProcess(), to, from, size, nullptr);
VirtualProtect(to, size, old, &old);
return res;
}
bool Windows::initialize() {
// return AddVectoredExceptionHandler(true, signalHandler);
return true;
}
#endif

View file

@ -1,26 +0,0 @@
#pragma once
#include "../../core/Platform.hpp"
#include <vector>
namespace geode::core::impl {
class Windows : public Platform<Windows> {
public:
#if defined(NDEBUG)
static inline auto trap = { std::byte(0xcc) };
#else
static inline auto trap = { std::byte(0x0f), std::byte(0x0b) };
#endif
public:
static bool writeMemory(void* to, void* from, size_t size);
static std::vector<std::byte> jump(void* from, void* to);
static bool initialize();
static bool enableSingleStep(void* context);
static bool disableSingleStep(void* context);
static void* allocateVM(size_t size);
};
using TargetPlatform = Platform<Windows>;
}