#include "prx/libc/include/Api.hpp" #include "prx/libc/include/exceptions/Runtime.hpp" #include #include #include #include #include #include struct TypeRecord { const void* vtable; const char* name; const TypeRecord* base; }; struct Vtable { std::intptr_t offsetToTop; const TypeRecord* type; const void* first; }; struct Object { const void* vtable; }; struct Source { virtual ~Source() = default; }; struct Side { virtual ~Side() = default; }; struct Native : Side, Source {}; struct PrivateNative : private Source { virtual ~PrivateNative() = default; }; struct VirtualNative : virtual Source { virtual ~VirtualNative() = default; }; struct BaseRecord { const TypeRecord* type; std::ptrdiff_t flags; }; struct MultipleRecord { const void* vtable; const char* name; unsigned flags; unsigned count; BaseRecord bases[1]; }; extern "C" { extern const unsigned char _ZTVN10__cxxabiv117__class_type_infoE_nid_postfix[]; extern const unsigned char _ZTVN10__cxxabiv120__si_class_type_infoE_nid_postfix[]; extern const unsigned char _ZTVN10__cxxabiv121__vmi_class_type_infoE_nid_postfix[]; } namespace { void Require(bool value) { if (!value) std::abort(); } void Destroy(void*) {} const TypeRecord BaseType{_ZTVN10__cxxabiv117__class_type_infoE_nid_postfix + 16, "4Base", nullptr}; const TypeRecord DerivedType{_ZTVN10__cxxabiv120__si_class_type_infoE_nid_postfix + 16, "7Derived", &BaseType}; const TypeRecord OtherType{_ZTVN10__cxxabiv120__si_class_type_infoE_nid_postfix + 16, "5Other", &BaseType}; const Vtable BaseVtable{0, &BaseType, nullptr}; const Vtable DerivedVtable{0, &DerivedType, nullptr}; const MultipleRecord MultipleType{_ZTVN10__cxxabiv121__vmi_class_type_infoE_nid_postfix + 16, "8Multiple", 0, 1, {{&BaseType, (16 << 8) | 2}}}; const MultipleRecord PrivateType{_ZTVN10__cxxabiv121__vmi_class_type_infoE_nid_postfix + 16, "7Private", 0, 1, {{&BaseType, 16 << 8}}}; const MultipleRecord VirtualType{_ZTVN10__cxxabiv121__vmi_class_type_infoE_nid_postfix + 16, "7Virtual", 0, 1, {{&BaseType, (-3 * static_cast(sizeof(void*)) * 256) | 3}}}; int FindPublic(const TypeRecord* type, std::ptrdiff_t hint, const void* object, const TypeRecord* sourceType, const void* source) { using Function = int (APS5_VABI *)(const void*, std::ptrdiff_t, const void*, const void*, const void*); const auto* table = static_cast(type->vtable); Function function; std::memcpy(&function, table + 8 * sizeof(void*), sizeof(function)); return function(type, hint, object, sourceType, source); } } // namespace int main() { const Object derived{&DerivedVtable.first}; const Object base{&BaseVtable.first}; Require(__dynamic_cast_nid_postfix(&derived, reinterpret_cast(&BaseType), reinterpret_cast(&DerivedType), 0) == &derived); Require(__dynamic_cast_nid_postfix(&derived, reinterpret_cast(&BaseType), reinterpret_cast(&OtherType), 0) == nullptr); Require(__dynamic_cast_nid_postfix(&base, reinterpret_cast(&BaseType), reinterpret_cast(&DerivedType), 0) == nullptr); Require(__dynamic_cast_nid_postfix(nullptr, reinterpret_cast(&BaseType), reinterpret_cast(&DerivedType), 0) == nullptr); std::array multipleObject{}; Require(FindPublic(reinterpret_cast(&MultipleType), -1, multipleObject.data(), &BaseType, multipleObject.data() + 16) == 6); Require(FindPublic(reinterpret_cast(&MultipleType), -1, multipleObject.data(), &BaseType, multipleObject.data()) == 1); Require(FindPublic(reinterpret_cast(&PrivateType), -1, multipleObject.data(), &BaseType, multipleObject.data() + 16) == 1); std::array virtualTable{}; virtualTable[0] = 16; const auto* virtualAddressPoint = virtualTable.data() + 3; alignas(std::intptr_t) std::array virtualObject{}; *reinterpret_cast(virtualObject.data()) = virtualAddressPoint; Require(FindPublic(reinterpret_cast(&VirtualType), -1, virtualObject.data(), &BaseType, virtualObject.data() + 16) == 7); Require(FindPublic(reinterpret_cast(&MultipleType), -3, multipleObject.data(), &BaseType, multipleObject.data() + 16) == 6); Require(FindPublic(reinterpret_cast(&VirtualType), -3, virtualObject.data(), &BaseType, virtualObject.data() + 16) == 1); void* object = __cxa_allocate_exception_nid_postfix(16); auto* type = reinterpret_cast(const_cast(&DerivedType)); LibcException::Header* header = __cxa_init_primary_exception_nid_postfix(object, type, Destroy); Require(header == LibcException::FromObject(object)); Require(header->type == type && header->destructor == Destroy && header->adjusted == object); __cxa_free_exception_nid_postfix(object); }