AuroraRuntime/Source/Process/AuProcessMap.cpp

282 lines
7.0 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuProcessMap.cpp
Date: 2022-1-23
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuProcessMap.hpp"
#if defined(AURORA_PLATFORM_WIN32)
#include "AuProcessMap.Win32.hpp"
#endif
#if defined(AURORA_IS_MODERNNT_DERIVED)
#include "AuProcessMap.NT.hpp"
#endif
#if defined(AURORA_IS_LINUX_DERIVED)
#include "AuProcessMap.Linux.hpp"
#endif
namespace Aurora::Process
{
struct ModuleBasePairHash
{
AuUInt operator()(const ModuleBasePair &in) const
{
return in.modBase;
}
};
struct ModuleBasePairEq
{
AU_CONSTEXPR_20 bool operator()(const ModuleBasePair &lhs, const AuString &rhs) const
{
return lhs.module == rhs;
}
AU_CONSTEXPR_20 bool operator()(const ModuleBasePair &lhs, const AuUInt &rhs) const
{
return lhs.modBase == rhs;
}
AU_CONSTEXPR_20 bool operator()(const ModuleBasePair &lhs, const ModuleBasePair &rhs) const
{
return rhs.modBase ? lhs.modBase == rhs.modBase : (rhs.module.size() ? rhs.module == rhs.module : false);
}
};
struct ModuleLookup : Section
{
ModuleLookup()
{}
ModuleLookup(const Section &s) : Section(s)
{}
};
static AuBST<AuUInt, ModuleLookup> gModulePtrMap;
static const auto kMinPageAlignment = 4096;
static const auto kPageBufferPad = 20;
static AuThreadPrimitives::Mutex gMutexUnique;
static AuHashMap<ModuleBasePair,
AuSPtr<PublicModule>,
ModuleBasePairHash, // TODO: this precede auhashcode
ModuleBasePairEq>
gModuleMap;
static AuList<Section> gOtherSections;
static AuUInt ToLowestPageAlignment(AuUInt in)
{
return in & ~(kMinPageAlignment - 1);
}
static AuSPtr<PublicModule> GetModuleFromSectionCache(AuUInt pointer)
{
AU_LOCK_GLOBAL_GUARD(gMutexUnique);
auto itr = gModulePtrMap.find(pointer);
if (itr == gModulePtrMap.end()) return {};
return itr->second.moduleMeta.lock();
}
static AuOptional<Section> GetSectionCache(AuUInt pointer)
{
AU_LOCK_GLOBAL_GUARD(gMutexUnique);
auto itr = gModulePtrMap.find(pointer);
if (itr == gModulePtrMap.end()) return {};
return itr->second;
}
bool IsInModuleCache(const ModuleBasePair &pair)
{
AU_LOCK_GLOBAL_GUARD(gMutexUnique);
return gModuleMap.find(pair) != gModuleMap.end();
}
void InsertModuleCache(const ModuleBasePair &pair, const AuSPtr<PublicModule> &mod)
{
for (auto &section : mod->sections)
{
AU_LOCK_GLOBAL_GUARD(gMutexUnique);
section.moduleMeta = mod;
if (!section.baseVa)
{
continue;
}
for (AuUInt i = section.baseVa; i < section.baseVa + section.size; i += (kMinPageAlignment * kPageBufferPad))
{
ModuleLookup a(section);
gModulePtrMap[ToLowestPageAlignment(i)] = a;
}
}
{
AU_LOCK_GLOBAL_GUARD(gMutexUnique);
gModuleMap[pair] = mod;
}
}
void RemoveModuleCache(const ModuleBasePair &eitherOr)
{
AU_LOCK_GLOBAL_GUARD(gMutexUnique);
auto itr = gModuleMap.find(eitherOr);
if (itr == gModuleMap.end()) return;
auto mod = itr->second;
for (const auto &section : mod->sections)
{
if (!section.baseVa)
{
continue;
}
for (AuUInt i = section.baseVa; i < section.baseVa + section.size; i += (kMinPageAlignment * kPageBufferPad))
{
auto itr = gModulePtrMap.find(ToLowestPageAlignment(i));
if (itr != gModulePtrMap.end())
{
gModulePtrMap.erase(itr);
}
}
}
gModuleMap.erase(itr);
}
PublicModule GetFromModuleCache(AuUInt handle)
{
AU_LOCK_GLOBAL_GUARD(gMutexUnique);
auto itr = gModuleMap.find({"", handle});
if (itr == gModuleMap.end()) return {};
return *itr->second;
}
static AuOptional<Section> FindInCache(AuUInt pointer)
{
auto curPtr = ToLowestPageAlignment(pointer);
auto temp = GetSectionCache(curPtr);
if (temp.has_value()) return temp;
for (int i = 0; i < kPageBufferPad + 1; i++)
{
curPtr -= kMinPageAlignment;
temp = GetSectionCache(curPtr); // TODO: i dont want to start from the top of the tree, thats stupid
if (temp.has_value()) return temp;
}
return AuOptional<Section>{};
}
void InitProcessMap()
{
#if defined(AURORA_IS_MODERNNT_DERIVED)
InitProcessMapNt();
#endif
#if defined(AURORA_IS_LINUX_DERIVED)
InitProcessMapLinux();
#endif
TryRescanSlow();
}
AUKN_SYM void TryRescanSlow()
{
#if defined(AURORA_PLATFORM_WIN32)
MakeToolHelp32Snapshot();
#endif
#if defined(AURORA_IS_LINUX_DERIVED)
RescanMaps();
#endif
}
void DeinitProcessMap()
{
#if defined(AURORA_IS_MODERNNT_DERIVED)
DeinitProcessMapNt();
#endif
#if defined(AURORA_IS_LINUX_DERIVED)
DeinitProcessMapLinux();
#endif
}
void BorrowOtherSectionArray(const AuConsumer<AuList<Section>&> &callback)
{
AU_LOCK_GLOBAL_GUARD(gMutexUnique);
callback(gOtherSections);
}
AUKN_SYM AuOptional<Section> GetSection(AuUInt pointer)
{
try
{
auto ceg = FindInCache(pointer);
if (ceg.has_value())
{
return ceg;
}
#if defined(AURORA_IS_MODERNNT_DERIVED)
if (MakeAwarePtr(pointer))
{
return FindInCache(pointer);
}
else
{
return LookupArbitrarySection(pointer);
}
#endif
return {};
}
catch (...)
{
return {};
}
}
AUKN_SYM PublicModule DumpExecutableRoot()
{
try
{
#if defined(AURORA_IS_MODERNNT_DERIVED)
return GetExecutableRoot();
#endif
return {};
}
catch (...)
{
return {};
}
}
AUKN_SYM Sections DumpExecutableAll()
{
AU_LOCK_GLOBAL_GUARD(gMutexUnique);
try
{
Sections ret;
for (const auto &[meta, ptr] : gModuleMap)
{
ret.insert(ret.end(), ptr->sections.begin(), ptr->sections.end());
}
ret.insert(ret.end(), gOtherSections.begin(), gOtherSections.end());
return ret;
}
catch (...)
{
return {};
}
}
}