Acquire all RPLs modules are using (once) to prevent them from getting unloaded while using them

This commit is contained in:
Maschell 2022-10-05 18:16:42 +02:00
parent 7919e7184d
commit d943bd4c67
5 changed files with 29 additions and 33 deletions

View File

@ -41,19 +41,19 @@ extern "C" int _start(int argc, char **argv) {
}
void SaveLoadedRPLsInGlobalInformation(module_information_t *globalInformation,
std::vector<OSDynLoad_Module> loadedRPLs) {
std::map<std::string, OSDynLoad_Module> &usedRPls) {
// free previous allocations.
if (globalInformation->acquired_rpls) {
free(globalInformation->acquired_rpls);
}
globalInformation->number_acquired_rpls = loadedRPLs.size();
globalInformation->acquired_rpls = (uint32_t *) malloc(loadedRPLs.size() * sizeof(uint32_t));
globalInformation->number_acquired_rpls = usedRPls.size();
globalInformation->acquired_rpls = (uint32_t *) malloc(usedRPls.size() * sizeof(uint32_t));
if (!globalInformation->acquired_rpls) {
OSFatal("Failed to allocate memory");
}
uint32_t i = 0;
for (auto &rpl : loadedRPLs) {
globalInformation->acquired_rpls[i] = (uint32_t) rpl;
for (auto &rpl : usedRPls) {
globalInformation->acquired_rpls[i] = (uint32_t) rpl.second;
++i;
}
}
@ -62,7 +62,7 @@ void doStart(int argc, char **argv) {
init_wut();
initLogging();
gLoadedRPLs.clear();
gUsedRPLs.clear();
// If an allocated rpl was not released properly (e.g. if something else calls OSDynload_Acquire without releasing it)
// memory gets leaked. Let's clean this up!
for (auto &addr : gAllocatedAddresses) {
@ -135,7 +135,7 @@ void doStart(int argc, char **argv) {
}
DEBUG_FUNCTION_LINE_VERBOSE("Resolve relocations without replacing alloc functions");
ResolveRelocations(gLoadedModules, true, gLoadedRPLs);
ResolveRelocations(gLoadedModules, true, gUsedRPLs);
for (auto &curModule : gLoadedModules) {
if (curModule->isInitBeforeRelocationDoneHook()) {
@ -153,11 +153,11 @@ void doStart(int argc, char **argv) {
}
} else {
DEBUG_FUNCTION_LINE("Resolve relocations and replace alloc functions");
ResolveRelocations(gLoadedModules, false, gLoadedRPLs);
ResolveRelocations(gLoadedModules, false, gUsedRPLs);
CallHook(gLoadedModules, WUMS_HOOK_RELOCATIONS_DONE);
}
SaveLoadedRPLsInGlobalInformation(&gModuleInformation, gLoadedRPLs);
SaveLoadedRPLsInGlobalInformation(&gModuleInformation, gUsedRPLs);
CallHook(gLoadedModules, WUMS_HOOK_INIT_WUT_DEVOPTAB);
CallHook(gLoadedModules, WUMS_HOOK_INIT_WUT_SOCKETS);

View File

@ -6,5 +6,5 @@ module_information_t gModuleInformation __attribute__((section(".data")));
std::vector<std::shared_ptr<ModuleData>> gLoadedModules __attribute__((section(".data")));
std::unique_ptr<module_information_single_t[]> gModuleDataInfo __attribute__((section(".data")));
std::vector<OSDynLoad_Module> gLoadedRPLs __attribute__((section(".data")));
std::map<std::string, OSDynLoad_Module> gUsedRPLs __attribute__((section(".data")));
std::vector<void *> gAllocatedAddresses __attribute__((section(".data")));

View File

@ -11,7 +11,7 @@ extern MEMHeapHandle gHeapHandle;
extern module_information_t gModuleInformation;
extern std::vector<std::shared_ptr<ModuleData>> gLoadedModules;
extern std::unique_ptr<module_information_single_t[]> gModuleDataInfo;
extern std::vector<OSDynLoad_Module> gLoadedRPLs;
extern std::map<std::string, OSDynLoad_Module> gUsedRPLs;
extern std::vector<void *> gAllocatedAddresses;
#define MEMORY_REGION_START 0x00800000

View File

@ -40,7 +40,7 @@ static void CustomDynLoadFree(void *addr) {
}
}
bool ResolveRelocations(std::vector<std::shared_ptr<ModuleData>> &loadedModules, bool skipMemoryMappingModule, std::vector<OSDynLoad_Module> &loadedRPLs) {
bool ResolveRelocations(std::vector<std::shared_ptr<ModuleData>> &loadedModules, bool skipMemoryMappingModule, std::map<std::string, OSDynLoad_Module> &usedRPls) {
bool wasSuccessful = true;
OSDynLoadAllocFn prevDynLoadAlloc = nullptr;
@ -60,7 +60,7 @@ bool ResolveRelocations(std::vector<std::shared_ptr<ModuleData>> &loadedModules,
// Afterwards we can just rely on the custom heap.
bool skipAllocFunction = skipMemoryMappingModule && (std::string_view(curModule->getExportName()) == "homebrew_memorymapping");
DEBUG_FUNCTION_LINE_VERBOSE("Skip alloc replace? %d", skipAllocFunction);
if (!doRelocation(gLoadedModules, relocData, nullptr, 0, skipAllocFunction, loadedRPLs)) {
if (!doRelocation(gLoadedModules, relocData, nullptr, 0, skipAllocFunction, usedRPls)) {
wasSuccessful = false;
DEBUG_FUNCTION_LINE_ERR("Failed to do Relocations for %s", curModule->getExportName().c_str());
OSFatal("Failed to do Relocations");
@ -79,8 +79,7 @@ bool doRelocation(const std::vector<std::shared_ptr<ModuleData>> &moduleList,
relocation_trampoline_entry_t *tramp_data,
uint32_t tramp_length,
bool skipAllocReplacement,
std::vector<OSDynLoad_Module> &loadedRPLs) {
std::map<std::string, OSDynLoad_Module> moduleCache;
std::map<std::string, OSDynLoad_Module> &usedRPls) {
for (auto const &curReloc : relocData) {
auto &functionName = curReloc->getName();
std::string rplName = curReloc->getImportRPLInformation()->getRPLName();
@ -109,26 +108,22 @@ bool doRelocation(const std::vector<std::shared_ptr<ModuleData>> &moduleList,
if (functionAddress == 0) {
int32_t isData = curReloc->getImportRPLInformation()->isData();
OSDynLoad_Module rplHandle = nullptr;
if (moduleCache.count(rplName) == 0) {
OSDynLoad_Error err = OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle);
if (err != OS_DYNLOAD_OK || rplHandle == nullptr) {
DEBUG_FUNCTION_LINE_VERBOSE("%s is not yet loaded", rplName.c_str());
// only acquire if not already loaded.
err = OSDynLoad_Acquire(rplName.c_str(), &rplHandle);
if (err != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to acquire %s", rplName.c_str());
return false;
}
// Keep track RPLs we have acquired, they will be released on exit (see: AromaBaseModule)
loadedRPLs.push_back(rplHandle);
}
moduleCache[rplName] = rplHandle;
if (!usedRPls.contains(rplName)) {
DEBUG_FUNCTION_LINE_VERBOSE("Acquire %s", rplName.c_str());
// Always acquire to increase refcount and make sure it won't get unloaded while we're using it.
OSDynLoad_Acquire(rplName.c_str(), &rplHandle);
// Keep track RPLs we are using.
// They will be released on exit in the AromaBaseModule
usedRPls[rplName] = rplHandle;
} else {
DEBUG_FUNCTION_LINE_VERBOSE("Use from usedRPLs cache! %s", rplName.c_str());
}
rplHandle = moduleCache.at(rplName);
rplHandle = usedRPls[rplName];
OSDynLoad_FindExport(rplHandle, isData, functionName.c_str(), (void **) &functionAddress);
if (functionAddress == 0) {
DEBUG_FUNCTION_LINE_ERR("Failed to find export %s of %s", functionName.begin(), rplName.c_str());
DEBUG_FUNCTION_LINE_ERR("Failed to find export %s of %s", functionName.c_str(), rplName.c_str());
OSFatal("Failed to find export");
return false;
}

View File

@ -1,15 +1,16 @@
#pragma once
#include "module/ModuleData.h"
#include <coreinit/dynload.h>
#include <map>
#include <vector>
bool ResolveRelocations(std::vector<std::shared_ptr<ModuleData>> &loadedModules,
bool skipMemoryMappingModule,
std::vector<OSDynLoad_Module> &loadedRPLs);
std::map<std::string, OSDynLoad_Module> &usedRPls);
bool doRelocation(const std::vector<std::shared_ptr<ModuleData>> &moduleList,
const std::vector<std::unique_ptr<RelocationData>> &relocData,
relocation_trampoline_entry_t *tramp_data,
uint32_t tramp_length,
bool skipAllocReplacement,
std::vector<OSDynLoad_Module> &loadedRPLs);
std::map<std::string, OSDynLoad_Module> &usedRPls);