-
Notifications
You must be signed in to change notification settings - Fork 973
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add classes for finding RTTI on Windows
- Loading branch information
1 parent
7c35978
commit a88ca48
Showing
8 changed files
with
151 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#pragma once | ||
|
||
struct RttiCompleteObjectLocator { | ||
static constexpr auto kOffsetOfOffsetInCompleteClass{4}; | ||
static constexpr auto kOffsetOfTypeDescriptorRva{12}; | ||
}; |
55 changes: 55 additions & 0 deletions
55
Source/Platform/Windows/RTTI/RttiCompleteObjectLocatorFinder.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
#pragma once | ||
|
||
#include <cstdint> | ||
#include <cstring> | ||
|
||
#include "RttiCompleteObjectLocator.h" | ||
#include "ToRvaConverter.h" | ||
#include <Utils/MemorySection.h> | ||
|
||
struct RttiTypeDescriptor; | ||
|
||
class RttiCompleteObjectLocatorFinder { | ||
public: | ||
RttiCompleteObjectLocatorFinder(MemorySection rdataSection, ToRvaConverter toRvaConverter) noexcept | ||
: rdataSection{rdataSection} | ||
, toRvaConverter{toRvaConverter} | ||
{ | ||
} | ||
|
||
[[nodiscard]] const RttiCompleteObjectLocator* findCompleteObjectLocator(const RttiTypeDescriptor* typeDescriptor) const noexcept | ||
{ | ||
const BinaryBytePattern typeDescriptorRvaPattern{toRvaConverter.toRva(reinterpret_cast<std::uintptr_t>(typeDescriptor))}; | ||
HybridPatternFinder typeDescriptorCrossReferenceFinder{rdataSection.raw(), typeDescriptorRvaPattern}; | ||
|
||
auto typeDescriptorReference{typeDescriptorCrossReferenceFinder.findNextOccurrence()}; | ||
while (typeDescriptorReference && (!isCompleteObjectLocator(reinterpret_cast<std::uintptr_t>(typeDescriptorReference)) || !isCompleteObjectLocatorOfCompleteClass(typeDescriptorReference))) | ||
typeDescriptorReference = typeDescriptorCrossReferenceFinder.findNextOccurrence(); | ||
|
||
if (typeDescriptorReference) | ||
return reinterpret_cast<const RttiCompleteObjectLocator*>(typeDescriptorReference - RttiCompleteObjectLocator::kOffsetOfTypeDescriptorRva); | ||
|
||
return nullptr; | ||
} | ||
|
||
private: | ||
[[nodiscard]] bool isCompleteObjectLocatorOfCompleteClass(const std::byte* typeDescriptorReference) const noexcept | ||
{ | ||
std::uint32_t offsetInCompleteClass; | ||
std::memcpy(&offsetInCompleteClass, typeDescriptorReference - RttiCompleteObjectLocator::kOffsetOfTypeDescriptorRva + RttiCompleteObjectLocator::kOffsetOfOffsetInCompleteClass, sizeof(std::uint32_t)); | ||
return offsetInCompleteClass == 0; | ||
} | ||
|
||
[[nodiscard]] bool isCompleteObjectLocator(std::uintptr_t typeDescriptorReference) const noexcept | ||
{ | ||
return hasNoCrossReferences(BinaryBytePattern{toRvaConverter.toRva(typeDescriptorReference)}) && rdataSection.offsetOf(typeDescriptorReference) >= RttiCompleteObjectLocator::kOffsetOfTypeDescriptorRva; | ||
} | ||
|
||
[[nodiscard]] bool hasNoCrossReferences(BytePattern pattern) const noexcept | ||
{ | ||
return HybridPatternFinder{rdataSection.raw(), pattern}.findNextOccurrence() == nullptr; | ||
} | ||
|
||
MemorySection rdataSection; | ||
ToRvaConverter toRvaConverter; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#pragma once | ||
|
||
struct RttiTypeDescriptor { | ||
static constexpr auto kOffsetOfName{16}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#pragma once | ||
|
||
#include <cstddef> | ||
#include <cstdint> | ||
#include <string_view> | ||
|
||
#include <MemorySearch/HybridPatternFinder.h> | ||
#include "RttiTypeDescriptor.h" | ||
#include <Utils/MemorySection.h> | ||
|
||
class RttiTypeDescriptorFinder { | ||
public: | ||
RttiTypeDescriptorFinder(MemorySection dataSection) noexcept | ||
: dataSection{dataSection} | ||
{ | ||
} | ||
|
||
[[nodiscard]] const RttiTypeDescriptor* findTypeDescriptor(std::string_view mangledTypeName) const noexcept | ||
{ | ||
if (const auto typeDescriptorName{findTypeDescriptorName(mangledTypeName)}; canBePartOfTypeDescriptor(typeDescriptorName)) | ||
return toTypeDescriptorPointer(typeDescriptorName); | ||
return nullptr; | ||
} | ||
|
||
private: | ||
[[nodiscard]] const std::byte* findTypeDescriptorName(std::string_view typeDescriptorName) const noexcept | ||
{ | ||
return HybridPatternFinder{dataSection.raw(), BytePattern{typeDescriptorName}}.findNextOccurrence(); | ||
} | ||
|
||
[[nodiscard]] bool canBePartOfTypeDescriptor(const std::byte* typeDescriptorName) const noexcept | ||
{ | ||
return typeDescriptorName && dataSection.offsetOf(reinterpret_cast<std::uintptr_t>(typeDescriptorName)) >= RttiTypeDescriptor::kOffsetOfName; | ||
} | ||
|
||
[[nodiscard]] static const RttiTypeDescriptor* toTypeDescriptorPointer(const std::byte* typeDescriptorName) noexcept | ||
{ | ||
return reinterpret_cast<const RttiTypeDescriptor*>(typeDescriptorName - RttiTypeDescriptor::kOffsetOfName); | ||
} | ||
|
||
MemorySection dataSection; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#pragma once | ||
|
||
#include <cassert> | ||
#include <cstdint> | ||
|
||
struct ToRvaConverter { | ||
[[nodiscard]] std::uint32_t toRva(std::uintptr_t address) const noexcept | ||
{ | ||
assert(address >= baseAddress); | ||
return static_cast<std::uint32_t>(address - baseAddress); | ||
} | ||
|
||
std::uintptr_t baseAddress; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters