mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-25 17:00:46 +01:00
Merge pull request #5164 from bylaws/gmeo
ImageTracker: Track loaded PE images for LookupExecutableFileSection
This commit is contained in:
7 files changed
+95
-15
No files matched your search
@@ -11,7 +11,6 @@
|
||||
#include <Interface/IR/PassManager.h>
|
||||
|
||||
#include <FEXCore/Core/Thunks.h>
|
||||
#include <FEXCore/HLE/SourcecodeResolver.h>
|
||||
#include <FEXCore/HLE/SyscallHandler.h>
|
||||
|
||||
#include <FEXHeaderUtils/Filesystem.h>
|
||||
@@ -30,7 +29,6 @@ ExecutableFileInfo::ExecutableFileInfo(fextl::unique_ptr<HLE::SourcecodeMap> Map
|
||||
, FileId(FileId)
|
||||
, Filename(Filename) {}
|
||||
#endif
|
||||
ExecutableFileInfo::~ExecutableFileInfo() = default;
|
||||
|
||||
fextl::string CodeMap::GetBaseFilename(const ExecutableFileInfo& MainExecutable, bool AddNombSuffix) {
|
||||
auto FileId = MainExecutable.FileId;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <FEXCore/fextl/string.h>
|
||||
#include <FEXCore/fextl/vector.h>
|
||||
#include <FEXCore/fextl/unordered_map.h>
|
||||
#include <FEXCore/HLE/SourcecodeResolver.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
@@ -31,8 +32,6 @@ enum class GuestRelocationType : uint32_t { Rel32, Rel64 };
|
||||
|
||||
// Generic information associated with an executable file.
|
||||
struct ExecutableFileInfo {
|
||||
~ExecutableFileInfo();
|
||||
|
||||
#if __clang_major__ < 16
|
||||
// Workaround for broken aggregate-initialization with std::piecewise_construct
|
||||
ExecutableFileInfo(fextl::unique_ptr<HLE::SourcecodeMap>, uint64_t, fextl::string);
|
||||
|
||||
@@ -522,7 +522,7 @@ public:
|
||||
}
|
||||
|
||||
std::optional<FEXCore::ExecutableFileSectionInfo> LookupExecutableFileSection(FEXCore::Core::InternalThreadState*, uint64_t Address) override {
|
||||
return std::nullopt;
|
||||
return ImageTracker->LookupExecutableFileSection(Address);
|
||||
}
|
||||
|
||||
void MarkGuestExecutableRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Start, uint64_t Length) override {
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
namespace FEX::Windows {
|
||||
class ScopedHandle final {
|
||||
public:
|
||||
ScopedHandle() = default;
|
||||
|
||||
explicit ScopedHandle(HANDLE Handle)
|
||||
: Handle(Handle) {}
|
||||
|
||||
@@ -23,15 +25,24 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE operator*() const {
|
||||
const HANDLE& operator*() const {
|
||||
return Handle;
|
||||
}
|
||||
|
||||
HANDLE& operator*() {
|
||||
return Handle;
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return Handle != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE Handle;
|
||||
HANDLE Handle {INVALID_HANDLE_VALUE};
|
||||
};
|
||||
|
||||
|
||||
bool ValidateHandleAccess(HANDLE Handle, ACCESS_MASK Access) {
|
||||
inline bool ValidateHandleAccess(HANDLE Handle, ACCESS_MASK Access) {
|
||||
OBJECT_BASIC_INFORMATION Info;
|
||||
|
||||
if (NtQueryObject(Handle, ObjectBasicInformation, &Info, sizeof(Info), nullptr)) {
|
||||
@@ -41,7 +52,7 @@ bool ValidateHandleAccess(HANDLE Handle, ACCESS_MASK Access) {
|
||||
return (Info.GrantedAccess & Access) == Access;
|
||||
}
|
||||
|
||||
ScopedHandle DupHandle(HANDLE Handle, ACCESS_MASK Access) {
|
||||
inline ScopedHandle DupHandle(HANDLE Handle, ACCESS_MASK Access) {
|
||||
HANDLE Duplicated = INVALID_HANDLE_VALUE;
|
||||
NtDuplicateObject(NtCurrentProcess(), Handle, NtCurrentProcess(), &Duplicated, Access, 0, 0);
|
||||
return ScopedHandle {Duplicated};
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <cctype>
|
||||
|
||||
#include <FEXCore/Core/Context.h>
|
||||
#include <FEXCore/Debug/InternalThreadState.h>
|
||||
@@ -13,13 +15,31 @@
|
||||
#include <FEXCore/fextl/fmt.h>
|
||||
#include <FEXCore/fextl/string.h>
|
||||
#include <FEXCore/fextl/vector.h>
|
||||
#include "Common/Config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <winternl.h>
|
||||
#include <xxhash.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Module.h"
|
||||
#include "Priv.h"
|
||||
#include "ImageTracker.h"
|
||||
|
||||
namespace FEX::Windows {
|
||||
static fextl::string ToLower(std::string_view String) {
|
||||
fextl::string Res;
|
||||
Res.resize(String.size());
|
||||
std::transform(String.begin(), String.end(), Res.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||
return Res;
|
||||
}
|
||||
|
||||
FEXCore::CodeMapFileId ComputeCodeMapId(std::string_view FileName, uint32_t TimeDateStamp, uint32_t SizeOfImage) {
|
||||
const auto Norm {ToLower(FileName)};
|
||||
return XXH3_64bits(Norm.data(), Norm.size()) ^ (static_cast<uint64_t>(SizeOfImage) << 32 | TimeDateStamp);
|
||||
}
|
||||
|
||||
static void LoadImageVolatileMetadata(fextl::set<uint64_t>& VolatileInstructions, FEXCore::IntervalList<uint64_t>& VolatileValidRanges,
|
||||
HMODULE Module, ArchImageNtHeaders* Nt, uint64_t Address, uint64_t EndAddress) {
|
||||
ULONG Size;
|
||||
@@ -59,12 +79,35 @@ ImageTracker::ImageTracker(FEXCore::Context::Context& CTX)
|
||||
: CTX {CTX}
|
||||
, ExtendedMetaData {FEX::VolatileMetadata::ParseExtendedVolatileMetadata(ExtendedVolatileMetadataConfig())} {}
|
||||
|
||||
void ImageTracker::HandleImageMap(std::string_view Path, uint64_t Address, bool MainImage) {
|
||||
fextl::string ModuleName {BaseName(Path)};
|
||||
LogMan::Msg::DFmt("Load module {}: {:X}", ModuleName, Address);
|
||||
ImageTracker::MappedImageInfo::MappedImageInfo(std::string_view Path, uint64_t Address, ArchImageNtHeaders* Nt,
|
||||
fextl::unordered_map<uint32_t, FEXCore::GuestRelocationType> Relocations)
|
||||
: Info {.FileId = ComputeCodeMapId(BaseName(Path), Nt->FileHeader.TimeDateStamp, Nt->OptionalHeader.SizeOfImage),
|
||||
.Filename = ToLower(Path), // Normalize path case as Windows paths are case-insensitive
|
||||
.Relocations = std::move(Relocations)}
|
||||
, SectionInfo {.FileInfo = Info, .FileStartVA = Address, .BeginVA = Address, .EndVA = Address + Nt->OptionalHeader.SizeOfImage} {}
|
||||
|
||||
FEXCore::ExecutableFileSectionInfo ImageTracker::HandleImageMap(std::string_view Path, uint64_t Address, bool MainImage) {
|
||||
std::scoped_lock Lock(CTX.GetCodeInvalidationMutex());
|
||||
const fextl::string ModuleName {BaseName(Path)};
|
||||
const auto Module = reinterpret_cast<HMODULE>(Address);
|
||||
auto* Nt = reinterpret_cast<ArchImageNtHeaders*>(RtlImageNtHeader(Module));
|
||||
MappedImageInfo* ImageInfo = nullptr;
|
||||
{
|
||||
std::unique_lock Lk {ImagesLock};
|
||||
auto [It, Inserted] =
|
||||
MappedImages.emplace(std::piecewise_construct, std::forward_as_tuple(Address),
|
||||
std::forward_as_tuple(Path, Address, Nt, fextl::unordered_map<uint32_t, FEXCore::GuestRelocationType> {}));
|
||||
|
||||
if (!Inserted) {
|
||||
return It->second.SectionInfo;
|
||||
}
|
||||
|
||||
ImageInfo = &It->second;
|
||||
}
|
||||
|
||||
auto ID = FEXCore::CodeMap::GetBaseFilename(ImageInfo->Info, false);
|
||||
LogMan::Msg::DFmt("Load module {} ({}): {:X}", ModuleName, ID, Address);
|
||||
|
||||
uint64_t EndAddress = Address + Nt->OptionalHeader.SizeOfImage;
|
||||
fextl::set<uint64_t> VolatileInstructions {};
|
||||
FEXCore::IntervalList<uint64_t> VolatileValidRanges {};
|
||||
@@ -75,13 +118,26 @@ void ImageTracker::HandleImageMap(std::string_view Path, uint64_t Address, bool
|
||||
|
||||
if (!VolatileInstructions.empty() || !VolatileValidRanges.Empty()) {
|
||||
LogMan::Msg::DFmt("Loaded volatile metadata for {:X}: {} entries", Address, VolatileInstructions.size());
|
||||
std::scoped_lock Lock(CTX.GetCodeInvalidationMutex());
|
||||
CTX.AddForceTSOInformation(VolatileValidRanges, std::move(VolatileInstructions));
|
||||
}
|
||||
|
||||
return ImageInfo->SectionInfo;
|
||||
}
|
||||
|
||||
void ImageTracker::HandleImageUnmap(uint64_t Address, uint64_t Size) {
|
||||
std::scoped_lock Lock(CTX.GetCodeInvalidationMutex());
|
||||
CTX.RemoveForceTSOInformation(Address, Size);
|
||||
|
||||
std::unique_lock Lk {ImagesLock};
|
||||
MappedImages.erase(Address);
|
||||
}
|
||||
|
||||
std::optional<FEXCore::ExecutableFileSectionInfo> ImageTracker::LookupExecutableFileSection(uint64_t Address) {
|
||||
std::shared_lock Lk {ImagesLock};
|
||||
auto It = MappedImages.upper_bound(Address);
|
||||
if (It == MappedImages.begin() || std::prev(It)->second.SectionInfo.EndVA <= Address) {
|
||||
return {};
|
||||
}
|
||||
return std::prev(It)->second.SectionInfo;
|
||||
}
|
||||
} // namespace FEX::Windows
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <FEXCore/Utils/CompilerDefs.h>
|
||||
#include <FEXCore/Config/Config.h>
|
||||
#include <FEXCore/Core/CodeCache.h>
|
||||
|
||||
#include "Common/VolatileMetadata.h"
|
||||
#include "Module.h"
|
||||
@@ -30,20 +31,35 @@ using ArchImageNtHeaders = IMAGE_NT_HEADERS32;
|
||||
using ArchImageLoadConfigDirectory = _IMAGE_LOAD_CONFIG_DIRECTORY32;
|
||||
#endif
|
||||
|
||||
FEXCore::CodeMapFileId ComputeCodeMapId(std::string_view FileName, uint32_t TimeDateStamp, uint32_t SizeOfImage);
|
||||
|
||||
/**
|
||||
* @brief Tracks mapped PE code images and handles their volatile metadata
|
||||
*/
|
||||
class ImageTracker {
|
||||
public:
|
||||
ImageTracker(FEXCore::Context::Context& CTX);
|
||||
void HandleImageMap(std::string_view Path, uint64_t Address, bool MainImage);
|
||||
FEXCore::ExecutableFileSectionInfo HandleImageMap(std::string_view Path, uint64_t Address, bool MainImage);
|
||||
void HandleImageUnmap(uint64_t Address, uint64_t Size);
|
||||
|
||||
std::optional<FEXCore::ExecutableFileSectionInfo> LookupExecutableFileSection(uint64_t Address);
|
||||
|
||||
private:
|
||||
struct MappedImageInfo {
|
||||
FEXCore::ExecutableFileInfo Info;
|
||||
FEXCore::ExecutableFileSectionInfo SectionInfo;
|
||||
|
||||
MappedImageInfo(std::string_view Path, uint64_t Address, ArchImageNtHeaders* Nt,
|
||||
fextl::unordered_map<uint32_t, FEXCore::GuestRelocationType> Relocations);
|
||||
};
|
||||
|
||||
FEXCore::Context::Context& CTX;
|
||||
|
||||
FEX_CONFIG_OPT(ExtendedVolatileMetadataConfig, EXTENDEDVOLATILEMETADATA);
|
||||
fextl::unordered_map<fextl::string, FEX::VolatileMetadata::ExtendedVolatileMetadata> ExtendedMetaData;
|
||||
|
||||
std::shared_mutex ImagesLock;
|
||||
std::map<uint64_t, MappedImageInfo> MappedImages;
|
||||
};
|
||||
|
||||
} // namespace FEX::Windows
|
||||
@@ -455,7 +455,7 @@ public:
|
||||
}
|
||||
|
||||
std::optional<FEXCore::ExecutableFileSectionInfo> LookupExecutableFileSection(FEXCore::Core::InternalThreadState*, uint64_t Address) override {
|
||||
return std::nullopt;
|
||||
return ImageTracker->LookupExecutableFileSection(Address);
|
||||
}
|
||||
|
||||
void MarkGuestExecutableRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Start, uint64_t Length) override {
|
||||
|
||||
Reference in new issue
Block a user