Skip to content

Commit

Permalink
Rewrite the plugin backend, use smart pointers is possible, don't per…
Browse files Browse the repository at this point in the history
…sist in structs and simplify code
  • Loading branch information
Maschell committed May 14, 2022
1 parent fb6373e commit cda9c3e
Show file tree
Hide file tree
Showing 41 changed files with 783 additions and 1,881 deletions.
12 changes: 6 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
FROM wiiuenv/devkitppc:20220213
FROM wiiuenv/devkitppc:20220507

COPY --from=wiiuenv/wiiumodulesystem:20220127 /artifacts $DEVKITPRO
COPY --from=wiiuenv/wiiupluginsystem:20220123 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libfunctionpatcher:20210924 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libmappedmemory:20210924 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libwupsbackend:20220213 /artifacts $DEVKITPRO
COPY --from=wiiuenv/wiiumodulesystem:20220512 /artifacts $DEVKITPRO
COPY --from=wiiuenv/wiiupluginsystem:20220513 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libfunctionpatcher:20220507 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libmappedmemory:20220211 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libwupsbackend:20220514 /artifacts $DEVKITPRO

WORKDIR project
187 changes: 63 additions & 124 deletions source/PluginManagement.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
#include <coreinit/cache.h>
#include <coreinit/dynload.h>
#include <coreinit/memdefaultheap.h>
#include <memory.h>
#include <memory>

#include "PluginManagement.h"
#include "hooks.h"
#include "patcher/hooks_patcher_static.h"
#include "plugin/PluginContainer.h"
#include "plugin/PluginInformationFactory.h"
#include "plugin/PluginMetaInformationFactory.h"

#include "PluginManagement.h"
#include "globals.h"
#include "hooks.h"
#include "utils/ElfUtils.h"
#include "utils/utils.h"
#include <coreinit/cache.h>
#include <coreinit/dynload.h>
#include <forward_list>
#include <memory.h>
#include <memory>
#include <ranges>

bool PluginManagement::doRelocation(const std::vector<std::shared_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, uint32_t trampolineID) {
bool PluginManagement::doRelocation(const std::vector<std::unique_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, uint32_t trampolineID) {
std::map<std::string, OSDynLoad_Module> moduleHandleCache;
for (auto const &cur : relocData) {
uint32_t functionAddress = 0;
Expand All @@ -35,7 +34,7 @@ bool PluginManagement::doRelocation(const std::vector<std::shared_ptr<Relocation
}

if (functionAddress == 0) {
std::string rplName = cur->getImportRPLInformation()->getName();
auto rplName = cur->getImportRPLInformation()->getRPLName();
int32_t isData = cur->getImportRPLInformation()->isData();
OSDynLoad_Module rplHandle = nullptr;
if (moduleHandleCache.count(rplName) > 0) {
Expand All @@ -54,153 +53,93 @@ bool PluginManagement::doRelocation(const std::vector<std::shared_ptr<Relocation
//DEBUG_FUNCTION_LINE("Found export for %s %s", rplName.c_str(), functionName.c_str());
}
if (!ElfUtils::elfLinkOne(cur->getType(), cur->getOffset(), cur->getAddend(), (uint32_t) cur->getDestination(), functionAddress, tramp_data, tramp_length, RELOC_TYPE_IMPORT, trampolineID)) {
DEBUG_FUNCTION_LINE_ERR("Relocation failed");
DEBUG_FUNCTION_LINE_ERR("elfLinkOne failed");
return false;
}
}

// Unloading RPLs which you want to use is stupid.
// Never uncomment this again.
/* for (auto &cur : moduleHandleCache) {
// Release handle if they are not from DynLoadPatchModule
if (((uint32_t) cur.second & 0xFFFF0000) != 0x13370000) {
OSDynLoad_Release(cur.second);
}
} */

DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
OSMemoryBarrier();
return true;
}


void PluginManagement::doRelocations(const std::vector<std::shared_ptr<PluginContainer>> &plugins, relocation_trampoline_entry_t *trampData, uint32_t tramp_size) {
bool PluginManagement::doRelocations(const std::vector<std::unique_ptr<PluginContainer>> &plugins, relocation_trampoline_entry_t *trampData, uint32_t tramp_size) {
for (auto &pluginContainer : plugins) {
DEBUG_FUNCTION_LINE_VERBOSE("Doing relocations for plugin: %s", pluginContainer->getMetaInformation()->getName().c_str());

if (!PluginManagement::doRelocation(pluginContainer->getPluginInformation()->getRelocationDataList(), trampData, tramp_size, pluginContainer->getPluginInformation()->getTrampolineId())) {
DEBUG_FUNCTION_LINE_ERR("Relocation failed");
return false;
}
}
return true;
}

void PluginManagement::memsetBSS(const std::vector<std::shared_ptr<PluginContainer>> &plugins) {
for (auto &pluginContainer : plugins) {
auto sbssSection = pluginContainer->getPluginInformation()->getSectionInfo(".sbss");
if (sbssSection) {
DEBUG_FUNCTION_LINE_VERBOSE("memset .sbss %08X (%d)", sbssSection.value()->getAddress(), sbssSection.value()->getSize());
memset((void *) sbssSection.value()->getAddress(), 0, sbssSection.value()->getSize());
}
auto bssSection = pluginContainer->getPluginInformation()->getSectionInfo(".bss");
if (bssSection) {
DEBUG_FUNCTION_LINE_VERBOSE("memset .bss %08X (%d)", bssSection.value()->getAddress(), bssSection.value()->getSize());
memset((void *) bssSection.value()->getAddress(), 0, bssSection.value()->getSize());
bool PluginManagement::RestoreFunctionPatches(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
for (const auto &cur : std::ranges::reverse_view(plugins)) {
for (const auto &curFunction : std::ranges::reverse_view(cur->getPluginInformation()->getFunctionDataList())) {
if (!curFunction->restore()) {
return false;
}
}
}
return true;
}

void PluginManagement::RestorePatches(plugin_information_t *pluginInformation, BOOL pluginOnly) {
for (int32_t plugin_index = pluginInformation->number_used_plugins - 1; plugin_index >= 0; plugin_index--) {
FunctionPatcherRestoreFunctions(pluginInformation->plugin_data[plugin_index].info.functions, pluginInformation->plugin_data[plugin_index].info.number_used_functions);
}
if (!pluginOnly) {
FunctionPatcherRestoreFunctions(method_hooks_hooks_static, method_hooks_size_hooks_static);
}
}

void PluginManagement::unloadPlugins(plugin_information_t *pluginInformation, MEMHeapHandle pluginHeap, BOOL freePluginData) {

RestorePatches(pluginInformation, true);
for (int32_t plugin_index = 0; plugin_index < pluginInformation->number_used_plugins; plugin_index++) {
plugin_information_single_t *plugin = &(pluginInformation->plugin_data[plugin_index]);
if (freePluginData) {
if (plugin->data.buffer != nullptr) {
if (plugin->data.memoryType == eMemTypeMEM2) {
DEBUG_FUNCTION_LINE_VERBOSE("Free plugin data buffer for %s [%08X]", plugin->meta.name, plugin->data.buffer);
free(plugin->data.buffer);
} else if (plugin->data.memoryType == eMemTypeExpHeap) {
DEBUG_FUNCTION_LINE_VERBOSE("Free plugin data buffer for %s [%08X on heap %08X]", plugin->meta.name, plugin->data.buffer, plugin->data.heapHandle);
MEMFreeToExpHeap((MEMHeapHandle) plugin->data.heapHandle, plugin->data.buffer);
} else {
DEBUG_FUNCTION_LINE_ERR("########################");
DEBUG_FUNCTION_LINE_ERR("Failed to free memory from plugin");
DEBUG_FUNCTION_LINE_ERR("########################");
}
plugin->data.buffer = nullptr;
plugin->data.bufferLength = 0;
} else {
DEBUG_FUNCTION_LINE_ERR("Plugin has no copy of elf saved in memory, can't free it");
}
}
if (plugin->info.allocatedTextMemoryAddress != nullptr) {
MEMFreeToExpHeap((MEMHeapHandle) pluginHeap, plugin->info.allocatedTextMemoryAddress);
DEBUG_FUNCTION_LINE_VERBOSE("Deleted allocated .text section for plugin %s [%08X]", plugin->meta.name, plugin->info.allocatedTextMemoryAddress);
}
if (plugin->info.allocatedDataMemoryAddress != nullptr) {
MEMFreeToExpHeap((MEMHeapHandle) pluginHeap, plugin->info.allocatedDataMemoryAddress);
DEBUG_FUNCTION_LINE_VERBOSE("Deleted allocated .data section for plugin %s [%08X]", plugin->meta.name, plugin->info.allocatedDataMemoryAddress);
}

for (uint32_t i = 0; i < gTrampolineDataSize; i++) {
auto trampoline = &(gTrampolineData[i]);
if (trampoline->id == plugin->info.trampolineId) {
trampoline->id = 0;
trampoline->status = RELOC_TRAMP_FREE;
bool PluginManagement::DoFunctionPatches(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
for (const auto &cur : plugins) {
for (const auto &curFunction : cur->getPluginInformation()->getFunctionDataList()) {
if (!curFunction->patch()) {
return false;
}
}
}

memset((void *) pluginInformation, 0, sizeof(plugin_information_t));
return true;
}

void PluginManagement::callInitHooks(plugin_information_t *pluginInformation) {
CallHook(pluginInformation, WUPS_LOADER_HOOK_INIT_STORAGE);
CallHook(pluginInformation, WUPS_LOADER_HOOK_INIT_PLUGIN);
void PluginManagement::callInitHooks(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
CallHook(plugins, WUPS_LOADER_HOOK_INIT_STORAGE);
CallHook(plugins, WUPS_LOADER_HOOK_INIT_PLUGIN);
DEBUG_FUNCTION_LINE_VERBOSE("Done calling init hooks");
}

void module_callback(OSDynLoad_Module module,
void *userContext,
OSDynLoad_NotifyReason reason,
OSDynLoad_NotifyData *infos) {
if (reason == OS_DYNLOAD_NOTIFY_LOADED) {
auto *pluginInformation = (plugin_information_t *) userContext;
for (int32_t plugin_index = 0; plugin_index < pluginInformation->number_used_plugins; plugin_index++) {
FunctionPatcherPatchFunction(pluginInformation->plugin_data[plugin_index].info.functions, pluginInformation->plugin_data[plugin_index].info.number_used_functions);
}
}
}

void PluginManagement::PatchFunctionsAndCallHooks(plugin_information_t *pluginInformation) {
DEBUG_FUNCTION_LINE_VERBOSE("Patching functions");
FunctionPatcherPatchFunction(method_hooks_hooks_static, method_hooks_size_hooks_static);

DCFlushRange((void *) 0x00800000, 0x00800000);
ICInvalidateRange((void *) 0x00800000, 0x00800000);

for (int32_t plugin_index = 0; plugin_index < pluginInformation->number_used_plugins; plugin_index++) {
CallHookEx(pluginInformation, WUPS_LOADER_HOOK_APPLICATION_STARTS, plugin_index);
FunctionPatcherPatchFunction(pluginInformation->plugin_data[plugin_index].info.functions, pluginInformation->plugin_data[plugin_index].info.number_used_functions);
CallHookEx(pluginInformation, WUPS_LOADER_HOOK_FUNCTIONS_PATCHED, plugin_index);
}
OSDynLoad_AddNotifyCallback(module_callback, pluginInformation);
}

std::vector<std::shared_ptr<PluginContainer>>
PluginManagement::loadPlugins(const std::vector<std::shared_ptr<PluginData>> &pluginList, MEMHeapHandle heapHandle, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length) {
std::vector<std::shared_ptr<PluginContainer>> plugins;
std::vector<std::unique_ptr<PluginContainer>>
PluginManagement::loadPlugins(const std::forward_list<std::shared_ptr<PluginData>> &pluginList, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length) {
std::vector<std::unique_ptr<PluginContainer>> plugins;

uint32_t trampolineID = 0;
for (auto &pluginData : pluginList) {
DEBUG_FUNCTION_LINE_VERBOSE("Load meta information");
auto metaInfo = PluginMetaInformationFactory::loadPlugin(pluginData);
if (metaInfo) {
auto container = std::make_shared<PluginContainer>();
container->setMetaInformation(metaInfo.value());
container->setPluginData(pluginData);
plugins.push_back(container);
auto info = PluginInformationFactory::load(pluginData, trampoline_data, trampoline_data_length, trampolineID++);
if (!info) {
DEBUG_FUNCTION_LINE_ERR("Failed to load Plugin %s", metaInfo.value()->getName().c_str());
continue;
}
auto container = make_unique_nothrow<PluginContainer>(std::move(metaInfo.value()), std::move(info.value()), pluginData);
if (!container) {
DEBUG_FUNCTION_LINE_ERR("Failed to create PluginContainer, skipping %s", metaInfo.value()->getName().c_str());
continue;
}
plugins.push_back(std::move(container));
} else {
DEBUG_FUNCTION_LINE("Failed to get meta information");
DEBUG_FUNCTION_LINE_ERR("Failed to get meta information");
}
}
uint32_t trampolineID = 0;
for (auto &pluginContainer : plugins) {
auto info = PluginInformationFactory::load(pluginContainer->getPluginData(), heapHandle, trampoline_data, trampoline_data_length, trampolineID++);
if (!info) {
DEBUG_FUNCTION_LINE("Failed to load Plugin %s", pluginContainer->getMetaInformation()->getName().c_str());
continue;
}
pluginContainer->setPluginInformation(info.value());

if (!PluginManagement::DoFunctionPatches(plugins)) {
DEBUG_FUNCTION_LINE_ERR("Failed to patch functions");
OSFatal("Failed to patch functions");
}

return plugins;
}
}
20 changes: 8 additions & 12 deletions source/PluginManagement.h
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
#pragma once

#include "plugin/PluginContainer.h"
#include <common/plugin_defines.h>
#include <forward_list>
#include <memory>
#include <vector>
#include <wums/defines/relocation_defines.h>

class PluginManagement {
public:
static void doRelocations(const std::vector<std::shared_ptr<PluginContainer>> &plugins, relocation_trampoline_entry_t *trampData, uint32_t tramp_size);
static std::vector<std::unique_ptr<PluginContainer>> loadPlugins(const std::forward_list<std::shared_ptr<PluginData>> &pluginList, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length);

static void memsetBSS(const std::vector<std::shared_ptr<PluginContainer>> &plugins);
static void callInitHooks(const std::vector<std::unique_ptr<PluginContainer>> &plugins);

static void callInitHooks(plugin_information_t *pluginInformation);
static bool doRelocations(const std::vector<std::unique_ptr<PluginContainer>> &plugins, relocation_trampoline_entry_t *trampData, uint32_t tramp_size);

static void PatchFunctionsAndCallHooks(plugin_information_t *gPluginInformation);
static bool doRelocation(const std::vector<std::unique_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, uint32_t trampolineID);

static bool doRelocation(const std::vector<std::shared_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, uint32_t trampolineID);
static bool DoFunctionPatches(const std::vector<std::unique_ptr<PluginContainer>> &plugins);

static void unloadPlugins(plugin_information_t *pluginInformation, MEMHeapHandle pluginHeap, BOOL freePluginData);

static std::vector<std::shared_ptr<PluginContainer>>
loadPlugins(const std::vector<std::shared_ptr<PluginData>> &pluginList, MEMHeapHandle pHeader, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length);

static void RestorePatches(plugin_information_t *pluginInformation, BOOL pluginOnly);
static bool RestoreFunctionPatches(const std::vector<std::unique_ptr<PluginContainer>> &plugins);
};
Loading

0 comments on commit cda9c3e

Please sign in to comment.