mirror of
https://github.com/geode-sdk/geode.git
synced 2025-03-22 02:45:49 -04:00
fix dynamic cast
This commit is contained in:
parent
0ed1a41426
commit
8dd2e15c38
3 changed files with 28 additions and 43 deletions
loader
|
@ -1,8 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace geode::cast {
|
||||
using uinthalf_t = uint32_t;
|
||||
using inthalf_t = int32_t;
|
||||
|
||||
struct DummyClass {
|
||||
virtual ~DummyClass() {}
|
||||
|
@ -14,8 +12,10 @@ namespace geode::cast {
|
|||
|
||||
struct DummyMultipleClass : DummySingleClass, DummyClass2 {};
|
||||
|
||||
struct VtableType;
|
||||
|
||||
struct ClassTypeinfoType {
|
||||
void** m_typeinfoVtable;
|
||||
VtableType* m_typeinfoVtable;
|
||||
char const* m_typeinfoName;
|
||||
};
|
||||
|
||||
|
@ -23,16 +23,17 @@ namespace geode::cast {
|
|||
ClassTypeinfoType* m_baseClassTypeinfo;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct MultipleClassSingleEntryType {
|
||||
ClassTypeinfoType* m_baseClassTypeinfo;
|
||||
uint8_t m_visibilityFlag;
|
||||
inthalf_t m_offset;
|
||||
uint8_t m_padding[sizeof(inthalf_t) - 1];
|
||||
};
|
||||
intptr_t m_metadata;
|
||||
|
||||
#pragma pack(pop)
|
||||
uint8_t visibilityFlag() const {
|
||||
return m_metadata & 0xFF;
|
||||
}
|
||||
intptr_t offset() const {
|
||||
return m_metadata >> 8;
|
||||
}
|
||||
};
|
||||
|
||||
struct MultipleClassTypeinfoType : ClassTypeinfoType {
|
||||
uint32_t m_flags;
|
||||
|
@ -41,7 +42,7 @@ namespace geode::cast {
|
|||
};
|
||||
|
||||
struct VtableTypeinfoType {
|
||||
inthalf_t m_offset;
|
||||
intptr_t m_offset;
|
||||
ClassTypeinfoType* m_typeinfo;
|
||||
};
|
||||
|
||||
|
@ -51,36 +52,25 @@ namespace geode::cast {
|
|||
|
||||
struct CompleteVtableType : VtableTypeinfoType, VtableType {};
|
||||
|
||||
inline void** typeinfoVtableOf(void* ptr) {
|
||||
auto vftable = *reinterpret_cast<VtableType**>(ptr);
|
||||
|
||||
auto typeinfoPtr =
|
||||
static_cast<VtableTypeinfoType*>(static_cast<CompleteVtableType*>(vftable));
|
||||
|
||||
return typeinfoPtr->m_typeinfo->m_typeinfoVtable;
|
||||
}
|
||||
|
||||
inline void* traverseTypeinfoFor(
|
||||
void* ptr, ClassTypeinfoType const* typeinfo, char const* afterIdent
|
||||
) {
|
||||
DummySingleClass dummySingleClass;
|
||||
DummyMultipleClass dummyMultipleClass;
|
||||
|
||||
{
|
||||
auto optionIdent = typeinfo->m_typeinfoName;
|
||||
if (std::strcmp(optionIdent, afterIdent) == 0) {
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
if (typeinfo->m_typeinfoVtable == typeinfoVtableOf(&dummySingleClass)) {
|
||||
auto typeinfoVtableName = static_cast<CompleteVtableType*>(typeinfo->m_typeinfoVtable)->m_typeinfo->m_typeinfoName;
|
||||
if (std::strcmp(typeinfoVtableName, "N10__cxxabiv120__si_class_type_infoE") == 0) {
|
||||
auto siTypeinfo = static_cast<SingleClassTypeinfoType const*>(typeinfo);
|
||||
return traverseTypeinfoFor(ptr, siTypeinfo->m_baseClassTypeinfo, afterIdent);
|
||||
}
|
||||
else if (typeinfo->m_typeinfoVtable == typeinfoVtableOf(&dummyMultipleClass)) {
|
||||
else if (std::strcmp(typeinfoVtableName, "N10__cxxabiv121__vmi_class_type_infoE") == 0) {
|
||||
auto vmiTypeinfo = static_cast<MultipleClassTypeinfoType const*>(typeinfo);
|
||||
for (int i = 0; i < vmiTypeinfo->m_numBaseClass; ++i) {
|
||||
auto& entry = vmiTypeinfo->m_baseClasses[i];
|
||||
auto optionPtr = reinterpret_cast<std::byte*>(ptr) + entry.m_offset;
|
||||
auto optionPtr = reinterpret_cast<std::byte*>(ptr) + entry.offset();
|
||||
auto ret = traverseTypeinfoFor(optionPtr, entry.m_baseClassTypeinfo, afterIdent);
|
||||
if (ret != nullptr) return ret;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include "ItaniumCast.hpp"
|
||||
|
||||
namespace geode {
|
||||
struct PlatformInfo {
|
||||
|
@ -12,10 +13,3 @@ namespace geode::base {
|
|||
/*GEODE_NOINLINE inline*/ uintptr_t get();
|
||||
}
|
||||
|
||||
namespace geode::cast {
|
||||
template <class After, class Before>
|
||||
After typeinfo_cast(Before ptr) {
|
||||
// yall have symbols smh
|
||||
return dynamic_cast<After>(ptr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
#include <Geode/DefaultInclude.hpp>
|
||||
|
||||
#ifdef GEODE_IS_MACOS
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
#include <Geode/modify/Modify.hpp>
|
||||
|
||||
$execute {
|
||||
// this replaces the call to __dynamic_cast with a call to our own
|
||||
// this is needed because the transitions in cocos uses dynamic cast to check
|
||||
// layers, which fail on user layers due to typeinfo not matching
|
||||
(void)Mod::get()->patch(
|
||||
reinterpret_cast<void*>(base::get() + 0x603948), toByteArray(&cast::typeinfoCastInternal)
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(GEODE_IS_MACOS)
|
||||
(void)Mod::get()->patch(
|
||||
reinterpret_cast<void*>(base::get() + 0x603948), toByteArray(&cast::typeinfoCastInternal)
|
||||
);
|
||||
#elif defined(GEODE_IS_ANDROID)
|
||||
(void)Mod::get()->addHook(reinterpret_cast<void*>(base::get() + 0x519a8c), &cast::typeinfoCastInternal, "__dynamic_cast");
|
||||
#endif
|
||||
|
||||
|
||||
}
|
Loading…
Reference in a new issue