mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2024-11-25 14:16:53 +01:00
Rewrite the plugin backend, use smart pointers is possible, don't persist in structs and simplify code
This commit is contained in:
parent
fb6373ec63
commit
cda9c3e055
12
Dockerfile
12
Dockerfile
@ -1,9 +1,9 @@
|
|||||||
FROM wiiuenv/devkitppc:20220213
|
FROM wiiuenv/devkitppc:20220507
|
||||||
|
|
||||||
COPY --from=wiiuenv/wiiumodulesystem:20220127 /artifacts $DEVKITPRO
|
COPY --from=wiiuenv/wiiumodulesystem:20220512 /artifacts $DEVKITPRO
|
||||||
COPY --from=wiiuenv/wiiupluginsystem:20220123 /artifacts $DEVKITPRO
|
COPY --from=wiiuenv/wiiupluginsystem:20220513 /artifacts $DEVKITPRO
|
||||||
COPY --from=wiiuenv/libfunctionpatcher:20210924 /artifacts $DEVKITPRO
|
COPY --from=wiiuenv/libfunctionpatcher:20220507 /artifacts $DEVKITPRO
|
||||||
COPY --from=wiiuenv/libmappedmemory:20210924 /artifacts $DEVKITPRO
|
COPY --from=wiiuenv/libmappedmemory:20220211 /artifacts $DEVKITPRO
|
||||||
COPY --from=wiiuenv/libwupsbackend:20220213 /artifacts $DEVKITPRO
|
COPY --from=wiiuenv/libwupsbackend:20220514 /artifacts $DEVKITPRO
|
||||||
|
|
||||||
WORKDIR project
|
WORKDIR project
|
@ -1,20 +1,19 @@
|
|||||||
#include <coreinit/cache.h>
|
#include "PluginManagement.h"
|
||||||
#include <coreinit/dynload.h>
|
#include "hooks.h"
|
||||||
#include <coreinit/memdefaultheap.h>
|
|
||||||
#include <memory.h>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "patcher/hooks_patcher_static.h"
|
#include "patcher/hooks_patcher_static.h"
|
||||||
#include "plugin/PluginContainer.h"
|
#include "plugin/PluginContainer.h"
|
||||||
#include "plugin/PluginInformationFactory.h"
|
#include "plugin/PluginInformationFactory.h"
|
||||||
#include "plugin/PluginMetaInformationFactory.h"
|
#include "plugin/PluginMetaInformationFactory.h"
|
||||||
|
|
||||||
#include "PluginManagement.h"
|
|
||||||
#include "globals.h"
|
|
||||||
#include "hooks.h"
|
|
||||||
#include "utils/ElfUtils.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;
|
std::map<std::string, OSDynLoad_Module> moduleHandleCache;
|
||||||
for (auto const &cur : relocData) {
|
for (auto const &cur : relocData) {
|
||||||
uint32_t functionAddress = 0;
|
uint32_t functionAddress = 0;
|
||||||
@ -35,7 +34,7 @@ bool PluginManagement::doRelocation(const std::vector<std::shared_ptr<Relocation
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (functionAddress == 0) {
|
if (functionAddress == 0) {
|
||||||
std::string rplName = cur->getImportRPLInformation()->getName();
|
auto rplName = cur->getImportRPLInformation()->getRPLName();
|
||||||
int32_t isData = cur->getImportRPLInformation()->isData();
|
int32_t isData = cur->getImportRPLInformation()->isData();
|
||||||
OSDynLoad_Module rplHandle = nullptr;
|
OSDynLoad_Module rplHandle = nullptr;
|
||||||
if (moduleHandleCache.count(rplName) > 0) {
|
if (moduleHandleCache.count(rplName) > 0) {
|
||||||
@ -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());
|
//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)) {
|
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;
|
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));
|
DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
|
||||||
ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
|
ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
|
||||||
|
OSMemoryBarrier();
|
||||||
return true;
|
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) {
|
for (auto &pluginContainer : plugins) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Doing relocations for plugin: %s", pluginContainer->getMetaInformation()->getName().c_str());
|
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())) {
|
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) {
|
bool PluginManagement::RestoreFunctionPatches(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
|
||||||
for (auto &pluginContainer : plugins) {
|
for (const auto &cur : std::ranges::reverse_view(plugins)) {
|
||||||
auto sbssSection = pluginContainer->getPluginInformation()->getSectionInfo(".sbss");
|
for (const auto &curFunction : std::ranges::reverse_view(cur->getPluginInformation()->getFunctionDataList())) {
|
||||||
if (sbssSection) {
|
if (!curFunction->restore()) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("memset .sbss %08X (%d)", sbssSection.value()->getAddress(), sbssSection.value()->getSize());
|
return false;
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginManagement::RestorePatches(plugin_information_t *pluginInformation, BOOL pluginOnly) {
|
bool PluginManagement::DoFunctionPatches(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
|
||||||
for (int32_t plugin_index = pluginInformation->number_used_plugins - 1; plugin_index >= 0; plugin_index--) {
|
for (const auto &cur : plugins) {
|
||||||
FunctionPatcherRestoreFunctions(pluginInformation->plugin_data[plugin_index].info.functions, pluginInformation->plugin_data[plugin_index].info.number_used_functions);
|
for (const auto &curFunction : cur->getPluginInformation()->getFunctionDataList()) {
|
||||||
|
if (!curFunction->patch()) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (!pluginOnly) {
|
|
||||||
FunctionPatcherRestoreFunctions(method_hooks_hooks_static, method_hooks_size_hooks_static);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginManagement::unloadPlugins(plugin_information_t *pluginInformation, MEMHeapHandle pluginHeap, BOOL freePluginData) {
|
void PluginManagement::callInitHooks(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
|
||||||
|
CallHook(plugins, WUPS_LOADER_HOOK_INIT_STORAGE);
|
||||||
RestorePatches(pluginInformation, true);
|
CallHook(plugins, WUPS_LOADER_HOOK_INIT_PLUGIN);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memset((void *) pluginInformation, 0, sizeof(plugin_information_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginManagement::callInitHooks(plugin_information_t *pluginInformation) {
|
|
||||||
CallHook(pluginInformation, WUPS_LOADER_HOOK_INIT_STORAGE);
|
|
||||||
CallHook(pluginInformation, WUPS_LOADER_HOOK_INIT_PLUGIN);
|
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Done calling init hooks");
|
DEBUG_FUNCTION_LINE_VERBOSE("Done calling init hooks");
|
||||||
}
|
}
|
||||||
|
|
||||||
void module_callback(OSDynLoad_Module module,
|
std::vector<std::unique_ptr<PluginContainer>>
|
||||||
void *userContext,
|
PluginManagement::loadPlugins(const std::forward_list<std::shared_ptr<PluginData>> &pluginList, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length) {
|
||||||
OSDynLoad_NotifyReason reason,
|
std::vector<std::unique_ptr<PluginContainer>> plugins;
|
||||||
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;
|
|
||||||
|
|
||||||
|
uint32_t trampolineID = 0;
|
||||||
for (auto &pluginData : pluginList) {
|
for (auto &pluginData : pluginList) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Load meta information");
|
|
||||||
auto metaInfo = PluginMetaInformationFactory::loadPlugin(pluginData);
|
auto metaInfo = PluginMetaInformationFactory::loadPlugin(pluginData);
|
||||||
if (metaInfo) {
|
if (metaInfo) {
|
||||||
auto container = std::make_shared<PluginContainer>();
|
auto info = PluginInformationFactory::load(pluginData, trampoline_data, trampoline_data_length, trampolineID++);
|
||||||
container->setMetaInformation(metaInfo.value());
|
|
||||||
container->setPluginData(pluginData);
|
|
||||||
plugins.push_back(container);
|
|
||||||
} else {
|
|
||||||
DEBUG_FUNCTION_LINE("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) {
|
if (!info) {
|
||||||
DEBUG_FUNCTION_LINE("Failed to load Plugin %s", pluginContainer->getMetaInformation()->getName().c_str());
|
DEBUG_FUNCTION_LINE_ERR("Failed to load Plugin %s", metaInfo.value()->getName().c_str());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pluginContainer->setPluginInformation(info.value());
|
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_ERR("Failed to get meta information");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PluginManagement::DoFunctionPatches(plugins)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to patch functions");
|
||||||
|
OSFatal("Failed to patch functions");
|
||||||
|
}
|
||||||
|
|
||||||
return plugins;
|
return plugins;
|
||||||
}
|
}
|
@ -1,26 +1,22 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "plugin/PluginContainer.h"
|
#include "plugin/PluginContainer.h"
|
||||||
#include <common/plugin_defines.h>
|
#include <forward_list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <wums/defines/relocation_defines.h>
|
||||||
|
|
||||||
class PluginManagement {
|
class PluginManagement {
|
||||||
public:
|
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 bool RestoreFunctionPatches(const std::vector<std::unique_ptr<PluginContainer>> &plugins);
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
};
|
@ -1,119 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* Copyright (C) 2018-2019 Maschell
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <wums/defines/dynamic_linking_defines.h>
|
|
||||||
#include <wums/defines/export_defines.h>
|
|
||||||
#include <wums/defines/relocation_defines.h>
|
|
||||||
|
|
||||||
#include <function_patcher/function_patching.h>
|
|
||||||
#include <wups/hooks.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MAXIMUM_PLUGIN_SECTION_LENGTH 10
|
|
||||||
#define MAXIMUM_PLUGIN_SECTION_NAME_LENGTH 20
|
|
||||||
|
|
||||||
#define MAXIMUM_PLUGIN_PATH_NAME_LENGTH 256
|
|
||||||
#define MAXIMUM_PLUGIN_NAME_LENGTH 51
|
|
||||||
#define MAXIMUM_PLUGIN_DESCRIPTION_LENGTH 100
|
|
||||||
#define MAXIMUM_PLUGIN_META_FIELD_LENGTH 51
|
|
||||||
|
|
||||||
#define PLUGIN_DYN_LINK_RELOCATION_LIST_LENGTH 1000
|
|
||||||
|
|
||||||
#define MAXIMUM_HOOKS_PER_PLUGIN 25
|
|
||||||
#define MAXIMUM_FUNCTION_PER_PLUGIN 100
|
|
||||||
|
|
||||||
struct plugin_section_info_t {
|
|
||||||
char name[MAXIMUM_PLUGIN_SECTION_NAME_LENGTH] = "";
|
|
||||||
uint32_t addr{};
|
|
||||||
uint32_t size{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct plugin_meta_info_t {
|
|
||||||
char name[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = "";
|
|
||||||
char author[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = "";
|
|
||||||
char version[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = "";
|
|
||||||
char license[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = "";
|
|
||||||
char buildTimestamp[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = "";
|
|
||||||
char descripion[MAXIMUM_PLUGIN_DESCRIPTION_LENGTH] = "";
|
|
||||||
char storageId[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = "";
|
|
||||||
uint32_t size{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct replacement_data_hook_t {
|
|
||||||
void *func_pointer = nullptr; /* [will be filled] */
|
|
||||||
wups_loader_hook_type_t type{}; /* [will be filled] */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct plugin_function_symbol_data_t {
|
|
||||||
char *name;
|
|
||||||
void *address;
|
|
||||||
uint32_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct plugin_info_t {
|
|
||||||
dyn_linking_relocation_entry_t linking_entries[PLUGIN_DYN_LINK_RELOCATION_LIST_LENGTH]{};
|
|
||||||
plugin_section_info_t sectionInfos[MAXIMUM_PLUGIN_SECTION_LENGTH];
|
|
||||||
uint32_t number_used_functions{}; // Number of used function. Maximum is MAXIMUM_FUNCTION_PER_PLUGIN
|
|
||||||
function_replacement_data_t functions[MAXIMUM_FUNCTION_PER_PLUGIN]{}; // Replacement information for each function.
|
|
||||||
uint32_t number_used_hooks{}; // Number of used hooks. Maximum is MAXIMUM_HOOKS_PER_PLUGIN
|
|
||||||
replacement_data_hook_t hooks[MAXIMUM_HOOKS_PER_PLUGIN]; // Replacement information for each function.
|
|
||||||
uint8_t trampolineId{};
|
|
||||||
plugin_function_symbol_data_t *function_symbol_data = nullptr;
|
|
||||||
uint32_t number_function_symbol_data = 0;
|
|
||||||
void *allocatedTextMemoryAddress = nullptr;
|
|
||||||
void *allocatedDataMemoryAddress = nullptr;
|
|
||||||
void *allocatedFuncSymStringTableAddress = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct plugin_data_t {
|
|
||||||
char *buffer = nullptr;
|
|
||||||
size_t bufferLength = 0;
|
|
||||||
int memoryType = 0;
|
|
||||||
int heapHandle = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct plugin_information_single_t {
|
|
||||||
plugin_meta_info_t meta;
|
|
||||||
plugin_info_t info;
|
|
||||||
plugin_data_t data;
|
|
||||||
int32_t priority{}; // Priority of this plugin
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAXIMUM_PLUGINS 32
|
|
||||||
|
|
||||||
struct plugin_information_t {
|
|
||||||
int32_t number_used_plugins = 0; // Number of used plugins. Maximum is MAXIMUM_PLUGINS
|
|
||||||
plugin_information_single_t plugin_data[MAXIMUM_PLUGINS];
|
|
||||||
dyn_linking_relocation_data_t linking_data{}; // RPL and function name list
|
|
||||||
};
|
|
||||||
|
|
||||||
struct plugin_information_on_reload_t {
|
|
||||||
int32_t number_used_plugins = 0; // Number of used plugins. Maximum is MAXIMUM_PLUGINS
|
|
||||||
plugin_data_t plugin_data[MAXIMUM_PLUGINS];
|
|
||||||
bool loadOnReload = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -39,7 +39,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
\return Returns the name of this WUPSConfig
|
\return Returns the name of this WUPSConfig
|
||||||
**/
|
**/
|
||||||
std::string getName() {
|
[[nodiscard]] const std::string &getName() const {
|
||||||
return this->name;
|
return this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ public:
|
|||||||
\return On success, the created and inserted category will be returned.
|
\return On success, the created and inserted category will be returned.
|
||||||
**/
|
**/
|
||||||
std::optional<WUPSConfigCategory *> addCategory(const std::string &categoryName) {
|
std::optional<WUPSConfigCategory *> addCategory(const std::string &categoryName) {
|
||||||
auto curCat = new WUPSConfigCategory(categoryName);
|
auto curCat = new (std::nothrow) WUPSConfigCategory(categoryName);
|
||||||
if (curCat == nullptr) {
|
if (curCat == nullptr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ public:
|
|||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
return buf;
|
return buf;
|
||||||
} else {
|
} else {
|
||||||
return StringTools::strfmt("[ERROR %d]", res);
|
return string_format("[ERROR %d]", res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||||
@ -87,7 +87,7 @@ public:
|
|||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
return buf;
|
return buf;
|
||||||
} else {
|
} else {
|
||||||
return StringTools::strfmt("[ERROR %d]", res);
|
return string_format("[ERROR %d]", res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
MEMHeapHandle gPluginDataHeap __attribute__((section(".data"))) = nullptr;
|
StoredBuffer gStoredTVBuffer __attribute__((section(".data"))) = {};
|
||||||
MEMHeapHandle gPluginInformationHeap __attribute__((section(".data"))) = nullptr;
|
StoredBuffer gStoredDRCBuffer __attribute__((section(".data"))) = {};
|
||||||
plugin_information_t *gPluginInformation __attribute__((section(".data"))) = nullptr;
|
|
||||||
plugin_information_on_reload_t gLinkOnReload __attribute__((section(".data")));
|
|
||||||
module_information_t *gModuleData __attribute__((section(".data"))) = nullptr;
|
|
||||||
relocation_trampoline_entry_t *gTrampolineData __attribute__((section(".data"))) = nullptr;
|
|
||||||
|
|
||||||
uint32_t gPluginDataHeapSize __attribute__((section(".data"))) = 0;
|
std::vector<std::unique_ptr<PluginContainer>> gLoadedPlugins __attribute__((section(".data")));
|
||||||
uint32_t gPluginInformationHeapSize __attribute__((section(".data"))) = 0;
|
relocation_trampoline_entry_t *gTrampData __attribute__((section(".data"))) = nullptr;
|
||||||
uint32_t gTrampolineDataSize __attribute__((section(".data"))) = 0;
|
|
||||||
|
|
||||||
StoredBuffer storedTVBuffer __attribute__((section(".data"))) = {};
|
std::forward_list<std::shared_ptr<PluginData>> gLoadedData __attribute__((section(".data")));
|
||||||
StoredBuffer storedDRCBuffer __attribute__((section(".data"))) = {};
|
std::forward_list<std::shared_ptr<PluginData>> gLoadOnNextLaunch __attribute__((section(".data")));
|
||||||
|
std::mutex gLoadedDataMutex __attribute__((section(".data")));
|
||||||
|
@ -1,22 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <wums.h>
|
|
||||||
|
|
||||||
#include "common/plugin_defines.h"
|
|
||||||
#include "plugin/PluginContainer.h"
|
#include "plugin/PluginContainer.h"
|
||||||
#include "utils/ConfigUtils.h"
|
#include "utils/ConfigUtils.h"
|
||||||
|
#include <forward_list>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
#include <wums/defines/relocation_defines.h>
|
||||||
|
|
||||||
extern plugin_information_t *gPluginInformation;
|
extern StoredBuffer gStoredTVBuffer;
|
||||||
extern MEMHeapHandle gPluginDataHeap;
|
extern StoredBuffer gStoredDRCBuffer;
|
||||||
extern MEMHeapHandle gPluginInformationHeap;
|
|
||||||
extern uint32_t gPluginDataHeapSize;
|
|
||||||
extern uint32_t gPluginInformationHeapSize;
|
|
||||||
extern plugin_information_on_reload_t gLinkOnReload;
|
|
||||||
extern module_information_t *gModuleData;
|
|
||||||
extern relocation_trampoline_entry_t *gTrampolineData;
|
|
||||||
extern uint32_t gTrampolineDataSize;
|
|
||||||
extern StoredBuffer storedTVBuffer;
|
|
||||||
extern StoredBuffer storedDRCBuffer;
|
|
||||||
|
|
||||||
#define PLUGIN_DATA_HEAP_SIZE (8 * 1024 * 1024)
|
#define TRAMP_DATA_SIZE 1024
|
||||||
#define NUMBER_OF_TRAMPS 1024
|
extern relocation_trampoline_entry_t *gTrampData;
|
||||||
|
extern std::vector<std::unique_ptr<PluginContainer>> gLoadedPlugins;
|
||||||
|
|
||||||
|
extern std::forward_list<std::shared_ptr<PluginData>> gLoadedData;
|
||||||
|
extern std::forward_list<std::shared_ptr<PluginData>> gLoadOnNextLaunch;
|
||||||
|
extern std::mutex gLoadedDataMutex;
|
@ -1,24 +1,9 @@
|
|||||||
#include "hooks.h"
|
#include "hooks.h"
|
||||||
|
#include "plugin/PluginContainer.h"
|
||||||
#include "utils/StorageUtils.h"
|
#include "utils/StorageUtils.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
|
#include <memory>
|
||||||
void CallHook(plugin_information_t *pluginInformation, wups_loader_hook_type_t hook_type) {
|
#include <vector>
|
||||||
CallHookEx(pluginInformation, hook_type, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasHookCallHook(plugin_information_t *pluginInformation, wups_loader_hook_type_t hook_type) {
|
|
||||||
for (int32_t plugin_index = 0; plugin_index < pluginInformation->number_used_plugins; plugin_index++) {
|
|
||||||
plugin_information_single_t *plugin_data = &pluginInformation->plugin_data[plugin_index];
|
|
||||||
|
|
||||||
for (uint32_t j = 0; j < plugin_data->info.number_used_hooks; j++) {
|
|
||||||
replacement_data_hook_t *hook_data = &plugin_data->info.hooks[j];
|
|
||||||
if (hook_data->type == hook_type) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char **hook_names = (const char *[]){
|
static const char **hook_names = (const char *[]){
|
||||||
"WUPS_LOADER_HOOK_INIT_WUT_MALLOC",
|
"WUPS_LOADER_HOOK_INIT_WUT_MALLOC",
|
||||||
@ -43,33 +28,27 @@ static const char **hook_names = (const char *[]){
|
|||||||
"WUPS_LOADER_HOOK_INIT_PLUGIN",
|
"WUPS_LOADER_HOOK_INIT_PLUGIN",
|
||||||
"WUPS_LOADER_HOOK_DEINIT_PLUGIN",
|
"WUPS_LOADER_HOOK_DEINIT_PLUGIN",
|
||||||
"WUPS_LOADER_HOOK_APPLICATION_STARTS",
|
"WUPS_LOADER_HOOK_APPLICATION_STARTS",
|
||||||
"WUPS_LOADER_HOOK_FUNCTIONS_PATCHED",
|
|
||||||
"WUPS_LOADER_HOOK_RELEASE_FOREGROUND",
|
"WUPS_LOADER_HOOK_RELEASE_FOREGROUND",
|
||||||
"WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND",
|
"WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND",
|
||||||
"WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT",
|
"WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT",
|
||||||
"WUPS_LOADER_HOOK_APPLICATION_ENDS"};
|
"WUPS_LOADER_HOOK_APPLICATION_ENDS"};
|
||||||
|
|
||||||
void CallHookEx(plugin_information_t *pluginInformation, wups_loader_hook_type_t hook_type, int32_t plugin_index_needed) {
|
void CallHook(const std::vector<std::unique_ptr<PluginContainer>> &plugins, wups_loader_hook_type_t hook_type) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d]", hook_names[hook_type], hook_type);
|
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d]", hook_names[hook_type], hook_type);
|
||||||
for (int32_t plugin_index = 0; plugin_index < pluginInformation->number_used_plugins; plugin_index++) {
|
for (auto &plugin : plugins) {
|
||||||
plugin_information_single_t *plugin_data = &pluginInformation->plugin_data[plugin_index];
|
CallHook(plugin, hook_type);
|
||||||
if (plugin_index_needed != -1 && plugin_index_needed != plugin_index) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//DEBUG_FUNCTION_LINE("Checking hook functions for %s.",plugin_data->plugin_name);
|
void CallHook(const std::unique_ptr<PluginContainer> &plugin, wups_loader_hook_type_t hook_type) {
|
||||||
//DEBUG_FUNCTION_LINE("Found hooks: %d",plugin_data->number_used_hooks);
|
for (const auto &hook : plugin->getPluginInformation()->getHookDataList()) {
|
||||||
for (uint32_t j = 0; j < plugin_data->info.number_used_hooks; j++) {
|
if (hook->getType() == hook_type) {
|
||||||
replacement_data_hook_t *hook_data = &plugin_data->info.hooks[j];
|
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s for plugin %s [%d]", hook_names[hook->getType()], plugin->metaInformation->getName().c_str(), hook_type);
|
||||||
if (hook_data->type == hook_type) {
|
void *func_ptr = hook->getFunctionPointer();
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s for plugin %s [%d]", hook_names[hook_data->type], plugin_data->meta.name, hook_type);
|
|
||||||
void *func_ptr = hook_data->func_pointer;
|
|
||||||
if (func_ptr != nullptr) {
|
if (func_ptr != nullptr) {
|
||||||
//DEBUG_FUNCTION_LINE("function pointer is %08x",func_ptr);
|
|
||||||
if (hook_type == WUPS_LOADER_HOOK_INIT_PLUGIN ||
|
if (hook_type == WUPS_LOADER_HOOK_INIT_PLUGIN ||
|
||||||
hook_type == WUPS_LOADER_HOOK_DEINIT_PLUGIN ||
|
hook_type == WUPS_LOADER_HOOK_DEINIT_PLUGIN ||
|
||||||
hook_type == WUPS_LOADER_HOOK_APPLICATION_STARTS ||
|
hook_type == WUPS_LOADER_HOOK_APPLICATION_STARTS ||
|
||||||
hook_type == WUPS_LOADER_HOOK_FUNCTIONS_PATCHED ||
|
|
||||||
hook_type == WUPS_LOADER_HOOK_APPLICATION_ENDS ||
|
hook_type == WUPS_LOADER_HOOK_APPLICATION_ENDS ||
|
||||||
hook_type == WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT ||
|
hook_type == WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT ||
|
||||||
hook_type == WUPS_LOADER_HOOK_INIT_WUT_MALLOC ||
|
hook_type == WUPS_LOADER_HOOK_INIT_WUT_MALLOC ||
|
||||||
@ -95,7 +74,7 @@ void CallHookEx(plugin_information_t *pluginInformation, wups_loader_hook_type_t
|
|||||||
wups_loader_init_storage_args_t args;
|
wups_loader_init_storage_args_t args;
|
||||||
args.open_storage_ptr = &StorageUtils::OpenStorage;
|
args.open_storage_ptr = &StorageUtils::OpenStorage;
|
||||||
args.close_storage_ptr = &StorageUtils::CloseStorage;
|
args.close_storage_ptr = &StorageUtils::CloseStorage;
|
||||||
args.plugin_id = plugin_data->meta.storageId;
|
args.plugin_id = plugin->getMetaInformation()->getStorageId().c_str();
|
||||||
// clang-format off
|
// clang-format off
|
||||||
((void(*)(wups_loader_init_storage_args_t))((uint32_t *) func_ptr))(args);
|
((void(*)(wups_loader_init_storage_args_t))((uint32_t *) func_ptr))(args);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
@ -109,5 +88,4 @@ void CallHookEx(plugin_information_t *pluginInformation, wups_loader_hook_type_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/plugin_defines.h"
|
#include "plugin/PluginContainer.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
#include <wups/hooks.h>
|
#include <wups/hooks.h>
|
||||||
|
|
||||||
void CallHook(plugin_information_t *pluginInformation, wups_loader_hook_type_t hook_type);
|
void CallHook(const std::vector<std::unique_ptr<PluginContainer>> &plugins, wups_loader_hook_type_t hook_type);
|
||||||
|
|
||||||
void CallHookEx(plugin_information_t *pluginInformation, wups_loader_hook_type_t hook_type, int32_t plugin_index_needed);
|
void CallHook(const std::unique_ptr<PluginContainer> &plugin, wups_loader_hook_type_t hook_type);
|
||||||
|
|
||||||
bool HasHookCallHook(plugin_information_t *pluginInformation, wups_loader_hook_type_t hook_type);
|
|
223
source/main.cpp
223
source/main.cpp
@ -2,55 +2,46 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "hooks.h"
|
#include "hooks.h"
|
||||||
#include "patcher/hooks_patcher_static.h"
|
#include "patcher/hooks_patcher_static.h"
|
||||||
#include "plugin/PluginContainerPersistence.h"
|
|
||||||
#include "plugin/PluginDataFactory.h"
|
#include "plugin/PluginDataFactory.h"
|
||||||
#include "plugin/PluginDataPersistence.h"
|
|
||||||
#include "utils/utils.h"
|
#include "utils/utils.h"
|
||||||
#include <coreinit/cache.h>
|
|
||||||
#include <coreinit/debug.h>
|
#include <coreinit/debug.h>
|
||||||
#include <coreinit/dynload.h>
|
|
||||||
#include <memory>
|
|
||||||
#include <wums.h>
|
#include <wums.h>
|
||||||
|
|
||||||
WUMS_MODULE_EXPORT_NAME("homebrew_wupsbackend");
|
WUMS_MODULE_EXPORT_NAME("homebrew_wupsbackend");
|
||||||
|
|
||||||
WUMS_USE_WUT_DEVOPTAB();
|
WUMS_USE_WUT_DEVOPTAB();
|
||||||
|
|
||||||
WUMS_INITIALIZE(args) {
|
WUMS_INITIALIZE() {
|
||||||
initLogging();
|
initLogging();
|
||||||
|
DEBUG_FUNCTION_LINE("Patching functions");
|
||||||
gModuleData = args.module_information;
|
for (uint32_t i = 0; i < method_hooks_static_size; i++) {
|
||||||
if (gModuleData == nullptr) {
|
if (!FunctionPatcherPatchFunction(&method_hooks_static[i], nullptr)) {
|
||||||
OSFatal("WUPS-Backend: Failed to get gModuleData pointer.");
|
OSFatal("homebrew_wupsbackend: Failed to patch function");
|
||||||
}
|
}
|
||||||
if (gModuleData->version != MODULE_INFORMATION_VERSION) {
|
|
||||||
OSFatal("WUPS-Backend: The module information struct version does not match.");
|
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE("Init successful");
|
|
||||||
deinitLogging();
|
deinitLogging();
|
||||||
}
|
}
|
||||||
|
|
||||||
WUMS_APPLICATION_REQUESTS_EXIT() {
|
WUMS_APPLICATION_REQUESTS_EXIT() {
|
||||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT);
|
uint32_t upid = OSGetUPID();
|
||||||
|
if (upid != 2 && upid != 15) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
WUMS_APPLICATION_ENDS() {
|
WUMS_APPLICATION_ENDS() {
|
||||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_APPLICATION_ENDS);
|
uint32_t upid = OSGetUPID();
|
||||||
if (gLinkOnReload.loadOnReload) {
|
if (upid != 2 && upid != 15) {
|
||||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_FINI_WRAPPER);
|
return;
|
||||||
}
|
}
|
||||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_FINI_WUT_SOCKETS);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_APPLICATION_ENDS);
|
||||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_FINI_WUT_DEVOPTAB);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_FINI_WUT_SOCKETS);
|
||||||
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_FINI_WUT_DEVOPTAB);
|
||||||
|
|
||||||
auto pluginInformation = gPluginInformation;
|
|
||||||
for (int32_t plugin_index = pluginInformation->number_used_plugins - 1; plugin_index >= 0; plugin_index--) {
|
|
||||||
FunctionPatcherRestoreDynamicFunctions(pluginInformation->plugin_data[plugin_index].info.functions, pluginInformation->plugin_data[plugin_index].info.number_used_functions);
|
|
||||||
}
|
|
||||||
FunctionPatcherRestoreDynamicFunctions(method_hooks_hooks_static, method_hooks_size_hooks_static);
|
|
||||||
deinitLogging();
|
deinitLogging();
|
||||||
}
|
}
|
||||||
|
|
||||||
void *allocOnCustomHeap(int alignment, int size);
|
|
||||||
|
|
||||||
WUMS_APPLICATION_STARTS() {
|
WUMS_APPLICATION_STARTS() {
|
||||||
uint32_t upid = OSGetUPID();
|
uint32_t upid = OSGetUPID();
|
||||||
@ -59,179 +50,67 @@ WUMS_APPLICATION_STARTS() {
|
|||||||
}
|
}
|
||||||
initLogging();
|
initLogging();
|
||||||
bool initNeeded = false;
|
bool initNeeded = false;
|
||||||
if (gPluginDataHeap == nullptr) {
|
|
||||||
DCFlushRange((void *) gModuleData, sizeof(module_information_t));
|
std::lock_guard<std::mutex> lock(gLoadedDataMutex);
|
||||||
uint32_t endAddress = 0;
|
|
||||||
for (int i = 0; i < gModuleData->number_used_modules; i++) {
|
if (gTrampData == nullptr) {
|
||||||
uint32_t curEndAddr = gModuleData->module_data[i].endAddress;
|
gTrampData = (relocation_trampoline_entry_t *) memalign(0x4, sizeof(relocation_trampoline_entry_t) * TRAMP_DATA_SIZE);
|
||||||
if (curEndAddr > endAddress) {
|
if (gTrampData == nullptr) {
|
||||||
endAddress = curEndAddr;
|
DEBUG_FUNCTION_LINE_ERR("Failed to allocated the memory for the trampoline data");
|
||||||
|
OSFatal("Failed to allocated the memory for the trampoline data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memset((void *) &gLinkOnReload, 0, sizeof(gLinkOnReload));
|
if (gLoadedPlugins.empty()) {
|
||||||
// If this address is 0, make sure the header common match the one
|
|
||||||
// in the SetupPayload repo. (I know that's a bad idea)
|
|
||||||
endAddress = (endAddress + 0x100) & 0xFFFFFF00;
|
|
||||||
|
|
||||||
gPluginInformationHeapSize = 0x00FFF000 - endAddress;
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Create heap for plugins information");
|
|
||||||
gPluginInformationHeap = MEMCreateExpHeapEx((void *) (endAddress), gPluginInformationHeapSize, 0);
|
|
||||||
|
|
||||||
if (gPluginInformationHeap == nullptr) {
|
|
||||||
OSFatal("PluginBackend: Failed to allocate memory for plugin information");
|
|
||||||
}
|
|
||||||
|
|
||||||
void *pluginHeapMemory = allocOnCustomHeap(0x1000, PLUGIN_DATA_HEAP_SIZE);
|
|
||||||
if (pluginHeapMemory == nullptr) {
|
|
||||||
DEBUG_FUNCTION_LINE("Use plugins information heap as fallback");
|
|
||||||
gPluginDataHeap = gPluginInformationHeap;
|
|
||||||
gPluginDataHeapSize = gPluginInformationHeapSize;
|
|
||||||
} else {
|
|
||||||
gPluginDataHeap = MEMCreateExpHeapEx(pluginHeapMemory, PLUGIN_DATA_HEAP_SIZE, 0);
|
|
||||||
gPluginDataHeapSize = PLUGIN_DATA_HEAP_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gPluginDataHeap != nullptr) {
|
|
||||||
if (gPluginInformation == nullptr) {
|
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocate gPluginInformation on heap %08X (size: %d bytes)", gPluginInformationHeap, sizeof(plugin_information_t));
|
|
||||||
gPluginInformation = (plugin_information_t *) MEMAllocFromExpHeapEx(gPluginInformationHeap, sizeof(plugin_information_t), 4);
|
|
||||||
if (gPluginInformation == nullptr) {
|
|
||||||
OSFatal("PluginBackend: Failed to allocate global plugin information");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memset((void *) gPluginInformation, 0, sizeof(plugin_information_t));
|
|
||||||
}
|
|
||||||
if (gTrampolineData == nullptr) {
|
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocate gTrampolineData on heap %08X (size: %d bytes)", gPluginDataHeap, sizeof(relocation_trampoline_entry_t) * NUMBER_OF_TRAMPS);
|
|
||||||
gTrampolineData = (relocation_trampoline_entry_t *) MEMAllocFromExpHeapEx(gPluginDataHeap, sizeof(relocation_trampoline_entry_t) * NUMBER_OF_TRAMPS, 4);
|
|
||||||
if (gTrampolineData == nullptr) {
|
|
||||||
OSFatal("PluginBackend: Failed to allocate gTrampolineData");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gTrampolineDataSize = NUMBER_OF_TRAMPS;
|
|
||||||
memset((void *) gTrampolineData, 0, sizeof(relocation_trampoline_entry_t) * NUMBER_OF_TRAMPS);
|
|
||||||
}
|
|
||||||
DEBUG_FUNCTION_LINE("Available memory for storing plugins: %d kb", MEMGetAllocatableSizeForExpHeapEx(gPluginDataHeap, 4) / 1024);
|
|
||||||
|
|
||||||
auto pluginPath = getPluginPath();
|
auto pluginPath = getPluginPath();
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Load plugins from %s", pluginPath.c_str());
|
DEBUG_FUNCTION_LINE("Load plugins from %s", pluginPath.c_str());
|
||||||
|
|
||||||
std::vector<std::shared_ptr<PluginData>> pluginList = PluginDataFactory::loadDir(pluginPath, gPluginDataHeap);
|
auto pluginData = PluginDataFactory::loadDir(pluginPath);
|
||||||
DEBUG_FUNCTION_LINE("Loaded data for %d plugins.", pluginList.size());
|
|
||||||
|
|
||||||
auto plugins = PluginManagement::loadPlugins(pluginList, gPluginDataHeap, gTrampolineData, gTrampolineDataSize);
|
gLoadedPlugins = PluginManagement::loadPlugins(pluginData, gTrampData, TRAMP_DATA_SIZE);
|
||||||
for (auto &pluginContainer : plugins) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
for (const auto &kv : pluginContainer->getPluginInformation()->getSectionInfoList()) {
|
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("%s = %s %08X %d", kv.first.c_str(), kv.second->getName().c_str(), kv.second->getAddress(), kv.second->getSize());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!PluginContainerPersistence::savePlugin(gPluginInformation, pluginContainer, gPluginDataHeap)) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to save plugin");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initNeeded = true;
|
initNeeded = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (gLinkOnReload.loadOnReload) {
|
|
||||||
DEBUG_FUNCTION_LINE("Reload with new plugin list.");
|
|
||||||
std::vector<std::shared_ptr<PluginData>> pluginDataList;
|
|
||||||
for (int32_t i = 0; i < gLinkOnReload.number_used_plugins; i++) {
|
|
||||||
auto pluginData = PluginDataPersistence::load(&gLinkOnReload.plugin_data[i]);
|
|
||||||
pluginDataList.push_back(pluginData);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int32_t plugin_index = 0; plugin_index < gPluginInformation->number_used_plugins; plugin_index++) {
|
if (!gLoadOnNextLaunch.empty()) {
|
||||||
plugin_information_single_t *plugin = &(gPluginInformation->plugin_data[plugin_index]);
|
DEBUG_FUNCTION_LINE("Restore function patches of currently loaded plugins.");
|
||||||
BOOL doDelete = true;
|
PluginManagement::RestoreFunctionPatches(gLoadedPlugins);
|
||||||
for (auto &pluginData : pluginDataList) {
|
DEBUG_FUNCTION_LINE("Unload existing plugins.");
|
||||||
if (pluginData->buffer == plugin->data.buffer) {
|
gLoadedPlugins.clear();
|
||||||
doDelete = false;
|
DEBUG_FUNCTION_LINE("Load new plugins");
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (doDelete) {
|
|
||||||
DEBUG_FUNCTION_LINE("We need to delete the plugin data for plugin %s", plugin->meta.name);
|
|
||||||
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 %s has no copy of elf saved in memory, can't free it", plugin->meta.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginManagement::unloadPlugins(gPluginInformation, gPluginDataHeap, false);
|
gLoadedPlugins = PluginManagement::loadPlugins(gLoadOnNextLaunch, gTrampData, TRAMP_DATA_SIZE);
|
||||||
|
|
||||||
auto plugins = PluginManagement::loadPlugins(pluginDataList, gPluginDataHeap, gTrampolineData, gTrampolineDataSize);
|
|
||||||
|
|
||||||
for (auto &pluginContainer : plugins) {
|
|
||||||
DEBUG_FUNCTION_LINE("Stored information for plugin %s ; %s", pluginContainer->getMetaInformation()->getName().c_str(), pluginContainer->getMetaInformation()->getAuthor().c_str());
|
|
||||||
if (!PluginContainerPersistence::savePlugin(gPluginInformation, pluginContainer, gPluginDataHeap)) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to save plugin");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gLinkOnReload.loadOnReload = false;
|
|
||||||
initNeeded = true;
|
initNeeded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gPluginDataHeap != nullptr) {
|
DEBUG_FUNCTION_LINE("Clear plugin data lists.");
|
||||||
auto plugins = PluginContainerPersistence::loadPlugins(gPluginInformation);
|
gLoadOnNextLaunch.clear();
|
||||||
PluginManagement::doRelocations(plugins, gTrampolineData, DYN_LINK_TRAMPOLINE_LIST_LENGTH);
|
gLoadedData.clear();
|
||||||
|
|
||||||
|
if (!gLoadedPlugins.empty()) {
|
||||||
|
if (!PluginManagement::doRelocations(gLoadedPlugins, gTrampData, TRAMP_DATA_SIZE)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Relocations failed");
|
||||||
|
OSFatal("Relocations failed");
|
||||||
|
}
|
||||||
// PluginManagement::memsetBSS(plugins);
|
// PluginManagement::memsetBSS(plugins);
|
||||||
|
|
||||||
DCFlushRange((void *) gPluginDataHeap, gPluginDataHeapSize);
|
|
||||||
ICInvalidateRange((void *) gPluginDataHeap, gPluginDataHeapSize);
|
|
||||||
DCFlushRange((void *) gPluginInformation, sizeof(plugin_information_t));
|
|
||||||
ICInvalidateRange((void *) gPluginInformation, sizeof(plugin_information_t));
|
|
||||||
|
|
||||||
if (initNeeded) {
|
if (initNeeded) {
|
||||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_INIT_WUT_MALLOC);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_INIT_WUT_MALLOC);
|
||||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_INIT_WUT_NEWLIB);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_INIT_WUT_NEWLIB);
|
||||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_INIT_WUT_STDCPP);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_INIT_WUT_STDCPP);
|
||||||
}
|
}
|
||||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_INIT_WUT_DEVOPTAB);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_INIT_WUT_DEVOPTAB);
|
||||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_INIT_WUT_SOCKETS);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_INIT_WUT_SOCKETS);
|
||||||
|
|
||||||
if (initNeeded) {
|
if (initNeeded) {
|
||||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_INIT_WRAPPER);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_INIT_WRAPPER);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initNeeded) {
|
if (initNeeded) {
|
||||||
PluginManagement::callInitHooks(gPluginInformation);
|
PluginManagement::callInitHooks(gLoadedPlugins);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginManagement::PatchFunctionsAndCallHooks(gPluginInformation);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_APPLICATION_STARTS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *allocOnCustomHeap(int alignment, int size) {
|
|
||||||
OSDynLoad_Module module;
|
|
||||||
OSDynLoad_Error dyn_res = OSDynLoad_Acquire("homebrew_memorymapping", &module);
|
|
||||||
if (dyn_res != OS_DYNLOAD_OK) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
uint32_t *custom_memalign;
|
|
||||||
dyn_res = OSDynLoad_FindExport(module, true, "MEMAllocFromMappedMemoryEx", reinterpret_cast<void **>(&custom_memalign));
|
|
||||||
auto *customMEMAllocFromDefaultHeapEx = (void *(*) (uint32_t, int) ) * custom_memalign;
|
|
||||||
|
|
||||||
if (dyn_res != OS_DYNLOAD_OK) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return customMEMAllocFromDefaultHeapEx(size, alignment);
|
|
||||||
}
|
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include "../globals.h"
|
#include "../globals.h"
|
||||||
#include "../hooks.h"
|
#include "../hooks.h"
|
||||||
#include "../utils/ConfigUtils.h"
|
|
||||||
|
|
||||||
uint8_t vpadPressCooldown = 0xFF;
|
uint8_t vpadPressCooldown = 0xFF;
|
||||||
bool configMenuOpened = false;
|
bool configMenuOpened = false;
|
||||||
@ -24,21 +23,21 @@ DECL_FUNCTION(void, GX2SwapScanBuffers, void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DECL_FUNCTION(void, GX2SetTVBuffer, void *buffer, uint32_t buffer_size, int32_t tv_render_mode, GX2SurfaceFormat format, GX2BufferingMode buffering_mode) {
|
DECL_FUNCTION(void, GX2SetTVBuffer, void *buffer, uint32_t buffer_size, int32_t tv_render_mode, GX2SurfaceFormat format, GX2BufferingMode buffering_mode) {
|
||||||
storedTVBuffer.buffer = buffer;
|
gStoredTVBuffer.buffer = buffer;
|
||||||
storedTVBuffer.buffer_size = buffer_size;
|
gStoredTVBuffer.buffer_size = buffer_size;
|
||||||
storedTVBuffer.mode = tv_render_mode;
|
gStoredTVBuffer.mode = tv_render_mode;
|
||||||
storedTVBuffer.surface_format = format;
|
gStoredTVBuffer.surface_format = format;
|
||||||
storedTVBuffer.buffering_mode = buffering_mode;
|
gStoredTVBuffer.buffering_mode = buffering_mode;
|
||||||
|
|
||||||
return real_GX2SetTVBuffer(buffer, buffer_size, tv_render_mode, format, buffering_mode);
|
return real_GX2SetTVBuffer(buffer, buffer_size, tv_render_mode, format, buffering_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
DECL_FUNCTION(void, GX2SetDRCBuffer, void *buffer, uint32_t buffer_size, uint32_t drc_mode, GX2SurfaceFormat surface_format, GX2BufferingMode buffering_mode) {
|
DECL_FUNCTION(void, GX2SetDRCBuffer, void *buffer, uint32_t buffer_size, uint32_t drc_mode, GX2SurfaceFormat surface_format, GX2BufferingMode buffering_mode) {
|
||||||
storedDRCBuffer.buffer = buffer;
|
gStoredDRCBuffer.buffer = buffer;
|
||||||
storedDRCBuffer.buffer_size = buffer_size;
|
gStoredDRCBuffer.buffer_size = buffer_size;
|
||||||
storedDRCBuffer.mode = drc_mode;
|
gStoredDRCBuffer.mode = drc_mode;
|
||||||
storedDRCBuffer.surface_format = surface_format;
|
gStoredDRCBuffer.surface_format = surface_format;
|
||||||
storedDRCBuffer.buffering_mode = buffering_mode;
|
gStoredDRCBuffer.buffering_mode = buffering_mode;
|
||||||
|
|
||||||
return real_GX2SetDRCBuffer(buffer, buffer_size, drc_mode, surface_format, buffering_mode);
|
return real_GX2SetDRCBuffer(buffer, buffer_size, drc_mode, surface_format, buffering_mode);
|
||||||
}
|
}
|
||||||
@ -51,7 +50,7 @@ DECL_FUNCTION(uint32_t, OSReceiveMessage, OSMessageQueue *queue, OSMessage *mess
|
|||||||
if (message != nullptr && res) {
|
if (message != nullptr && res) {
|
||||||
if (lastData0 != message->args[0]) {
|
if (lastData0 != message->args[0]) {
|
||||||
if (message->args[0] == 0xFACEF000) {
|
if (message->args[0] == 0xFACEF000) {
|
||||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND);
|
||||||
} else if (message->args[0] == 0xD1E0D1E0) {
|
} else if (message->args[0] == 0xD1E0D1E0) {
|
||||||
// Implemented via WUMS Hook
|
// Implemented via WUMS Hook
|
||||||
}
|
}
|
||||||
@ -64,7 +63,7 @@ DECL_FUNCTION(uint32_t, OSReceiveMessage, OSMessageQueue *queue, OSMessage *mess
|
|||||||
|
|
||||||
DECL_FUNCTION(void, OSReleaseForeground) {
|
DECL_FUNCTION(void, OSReleaseForeground) {
|
||||||
if (OSGetCoreId() == 1) {
|
if (OSGetCoreId() == 1) {
|
||||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_RELEASE_FOREGROUND);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_RELEASE_FOREGROUND);
|
||||||
}
|
}
|
||||||
real_OSReleaseForeground();
|
real_OSReleaseForeground();
|
||||||
}
|
}
|
||||||
@ -115,45 +114,34 @@ DECL_FUNCTION(uint32_t, SC17_FindClosestSymbol,
|
|||||||
uint32_t symbolNameBufferLength,
|
uint32_t symbolNameBufferLength,
|
||||||
char *moduleNameBuffer,
|
char *moduleNameBuffer,
|
||||||
uint32_t moduleNameBufferLength) {
|
uint32_t moduleNameBufferLength) {
|
||||||
for (int32_t plugin_index = 0; plugin_index < gPluginInformation->number_used_plugins; plugin_index++) {
|
for (auto &plugin : gLoadedPlugins) {
|
||||||
plugin_information_single_t *plugin = &(gPluginInformation->plugin_data[plugin_index]);
|
auto sectionInfoOpt = plugin->getPluginInformation()->getSectionInfo(".text");
|
||||||
plugin_section_info_t *section = nullptr;
|
if (!sectionInfoOpt) {
|
||||||
|
|
||||||
for (auto §ionInfo : plugin->info.sectionInfos) {
|
|
||||||
if (sectionInfo.addr == 0 && sectionInfo.size == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (strncmp(sectionInfo.name, ".text", sizeof(sectionInfo.name)) == 0) {
|
|
||||||
section = §ionInfo;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (section == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (addr < section->addr || addr >= (section->addr + section->size)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(moduleNameBuffer, plugin->meta.name, moduleNameBufferLength);
|
auto §ionInfo = sectionInfoOpt.value();
|
||||||
if (plugin->info.function_symbol_data != nullptr && plugin->info.number_function_symbol_data > 1) {
|
|
||||||
for (uint32_t i = 0; i < plugin->info.number_function_symbol_data - 1; i++) {
|
if (!sectionInfo->isInSection(addr)) {
|
||||||
auto symbolData = &plugin->info.function_symbol_data[i];
|
continue;
|
||||||
auto symbolDataNext = &plugin->info.function_symbol_data[i + 1];
|
}
|
||||||
if (i == plugin->info.number_function_symbol_data - 2 || (addr >= (uint32_t) symbolData->address && addr < (uint32_t) symbolDataNext->address)) {
|
|
||||||
strncpy(symbolNameBuffer, symbolData->name, moduleNameBufferLength);
|
strncpy(moduleNameBuffer, plugin->getMetaInformation()->getName().c_str(), moduleNameBufferLength - 1);
|
||||||
|
auto functionSymbolDataOpt = plugin->getPluginInformation()->getNearestFunctionSymbolData(addr);
|
||||||
|
if (functionSymbolDataOpt) {
|
||||||
|
auto &functionSymbolData = functionSymbolDataOpt.value();
|
||||||
|
|
||||||
|
strncpy(symbolNameBuffer, functionSymbolData->getName().c_str(), moduleNameBufferLength);
|
||||||
if (outDistance) {
|
if (outDistance) {
|
||||||
*outDistance = addr - (uint32_t) symbolData->address;
|
*outDistance = addr - (uint32_t) functionSymbolData->getAddress();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(symbolNameBuffer, ".text", symbolNameBufferLength);
|
strncpy(symbolNameBuffer, ".text", symbolNameBufferLength);
|
||||||
|
|
||||||
if (outDistance) {
|
if (outDistance) {
|
||||||
*outDistance = addr - (uint32_t) section->addr;
|
*outDistance = addr - (uint32_t) sectionInfo->getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -163,48 +151,34 @@ DECL_FUNCTION(uint32_t, SC17_FindClosestSymbol,
|
|||||||
}
|
}
|
||||||
|
|
||||||
DECL_FUNCTION(uint32_t, KiGetAppSymbolName, uint32_t addr, char *buffer, int32_t bufSize) {
|
DECL_FUNCTION(uint32_t, KiGetAppSymbolName, uint32_t addr, char *buffer, int32_t bufSize) {
|
||||||
for (int32_t plugin_index = 0; plugin_index < gPluginInformation->number_used_plugins; plugin_index++) {
|
for (auto &plugin : gLoadedPlugins) {
|
||||||
plugin_information_single_t *plugin = &(gPluginInformation->plugin_data[plugin_index]);
|
auto sectionInfoOpt = plugin->getPluginInformation()->getSectionInfo(".text");
|
||||||
plugin_section_info_t *section = nullptr;
|
if (!sectionInfoOpt) {
|
||||||
|
|
||||||
for (auto §ionInfo : plugin->info.sectionInfos) {
|
|
||||||
if (sectionInfo.addr == 0 && sectionInfo.size == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (strncmp(sectionInfo.name, ".text", sizeof(sectionInfo.name)) == 0) {
|
|
||||||
section = §ionInfo;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (section == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (addr < section->addr || addr >= (section->addr + section->size)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pluginNameLen = strlen(plugin->meta.name);
|
auto §ionInfo = sectionInfoOpt.value();
|
||||||
|
|
||||||
|
if (!sectionInfo->isInSection(addr)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pluginNameLen = strlen(plugin->getMetaInformation()->getName().c_str());
|
||||||
int32_t spaceLeftInBuffer = (int32_t) bufSize - (int32_t) pluginNameLen - 1;
|
int32_t spaceLeftInBuffer = (int32_t) bufSize - (int32_t) pluginNameLen - 1;
|
||||||
if (spaceLeftInBuffer < 0) {
|
if (spaceLeftInBuffer < 0) {
|
||||||
spaceLeftInBuffer = 0;
|
spaceLeftInBuffer = 0;
|
||||||
}
|
}
|
||||||
strncpy(buffer, plugin->meta.name, bufSize);
|
strncpy(buffer, plugin->getMetaInformation()->getName().c_str(), bufSize - 1);
|
||||||
|
|
||||||
if (plugin->info.function_symbol_data != nullptr && plugin->info.number_function_symbol_data > 1) {
|
auto functionSymbolDataOpt = plugin->getPluginInformation()->getNearestFunctionSymbolData(addr);
|
||||||
for (uint32_t i = 0; i < plugin->info.number_function_symbol_data - 1; i++) {
|
if (functionSymbolDataOpt) {
|
||||||
auto symbolData = &plugin->info.function_symbol_data[i];
|
auto &functionSymbolData = functionSymbolDataOpt.value();
|
||||||
auto symbolDataNext = &plugin->info.function_symbol_data[i + 1];
|
|
||||||
if (i == plugin->info.number_function_symbol_data - 2 || (addr >= (uint32_t) symbolData->address && addr < (uint32_t) symbolDataNext->address)) {
|
|
||||||
if (spaceLeftInBuffer > 2) {
|
|
||||||
buffer[pluginNameLen] = '|';
|
buffer[pluginNameLen] = '|';
|
||||||
buffer[pluginNameLen + 1] = '\0';
|
buffer[pluginNameLen + 1] = '\0';
|
||||||
strncpy(buffer + pluginNameLen + 1, symbolData->name, spaceLeftInBuffer - 1);
|
strncpy(buffer + pluginNameLen + 1, functionSymbolData->getName().c_str(), spaceLeftInBuffer - 1);
|
||||||
}
|
}
|
||||||
return (uint32_t) symbolData->address;
|
|
||||||
}
|
return 0;
|
||||||
}
|
|
||||||
}
|
|
||||||
return addr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return real_KiGetAppSymbolName(addr, buffer, bufSize);
|
return real_KiGetAppSymbolName(addr, buffer, bufSize);
|
||||||
@ -212,7 +186,7 @@ DECL_FUNCTION(uint32_t, KiGetAppSymbolName, uint32_t addr, char *buffer, int32_t
|
|||||||
|
|
||||||
#pragma GCC pop_options
|
#pragma GCC pop_options
|
||||||
|
|
||||||
function_replacement_data_t method_hooks_hooks_static[] __attribute__((section(".data"))) = {
|
function_replacement_data_t method_hooks_static[] __attribute__((section(".data"))) = {
|
||||||
REPLACE_FUNCTION(GX2SwapScanBuffers, LIBRARY_GX2, GX2SwapScanBuffers),
|
REPLACE_FUNCTION(GX2SwapScanBuffers, LIBRARY_GX2, GX2SwapScanBuffers),
|
||||||
REPLACE_FUNCTION(GX2SetTVBuffer, LIBRARY_GX2, GX2SetTVBuffer),
|
REPLACE_FUNCTION(GX2SetTVBuffer, LIBRARY_GX2, GX2SetTVBuffer),
|
||||||
REPLACE_FUNCTION(GX2SetDRCBuffer, LIBRARY_GX2, GX2SetDRCBuffer),
|
REPLACE_FUNCTION(GX2SetDRCBuffer, LIBRARY_GX2, GX2SetDRCBuffer),
|
||||||
@ -225,4 +199,4 @@ function_replacement_data_t method_hooks_hooks_static[] __attribute__((section("
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t method_hooks_size_hooks_static __attribute__((section(".data"))) = sizeof(method_hooks_hooks_static) / sizeof(function_replacement_data_t);
|
uint32_t method_hooks_static_size __attribute__((section(".data"))) = sizeof(method_hooks_static) / sizeof(function_replacement_data_t);
|
@ -6,8 +6,8 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern function_replacement_data_t method_hooks_hooks_static[];
|
extern function_replacement_data_t method_hooks_static[];
|
||||||
extern uint32_t method_hooks_size_hooks_static;
|
extern uint32_t method_hooks_static_size;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -1,107 +0,0 @@
|
|||||||
#include "DynamicLinkingHelper.h"
|
|
||||||
#include <cstring>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
dyn_linking_function_t *DynamicLinkingHelper::getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName) {
|
|
||||||
if (data == nullptr) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("data was NULL");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (functionName == nullptr) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("functionName was NULL");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
dyn_linking_function_t *result = nullptr;
|
|
||||||
for (auto &curEntry : data->functions) {
|
|
||||||
if (strlen(curEntry.functionName) == 0) {
|
|
||||||
if (strlen(functionName) > DYN_LINK_FUNCTION_NAME_LENGTH) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to add function name, it's too long.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
strncpy(curEntry.functionName, functionName, DYN_LINK_FUNCTION_NAME_LENGTH);
|
|
||||||
result = &curEntry;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (strncmp(curEntry.functionName, functionName, DYN_LINK_FUNCTION_NAME_LENGTH) == 0) {
|
|
||||||
result = &curEntry;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
dyn_linking_import_t *DynamicLinkingHelper::getOrAddFunctionImportByName(dyn_linking_relocation_data_t *data, const char *importName) {
|
|
||||||
return getOrAddImport(data, importName, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
dyn_linking_import_t *DynamicLinkingHelper::getOrAddDataImportByName(dyn_linking_relocation_data_t *data, const char *importName) {
|
|
||||||
return getOrAddImport(data, importName, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
dyn_linking_import_t *DynamicLinkingHelper::getOrAddImport(dyn_linking_relocation_data_t *data, const char *importName, bool isData) {
|
|
||||||
if (importName == nullptr || data == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
dyn_linking_import_t *result = nullptr;
|
|
||||||
for (auto &curEntry : data->imports) {
|
|
||||||
if (strlen(curEntry.importName) == 0) {
|
|
||||||
if (strlen(importName) > DYN_LINK_IMPORT_NAME_LENGTH) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to add Import, it's too long.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
strncpy(curEntry.importName, importName, DYN_LINK_IMPORT_NAME_LENGTH);
|
|
||||||
curEntry.isData = isData;
|
|
||||||
result = &curEntry;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (strncmp(curEntry.importName, importName, DYN_LINK_IMPORT_NAME_LENGTH) == 0 && (curEntry.isData == isData)) {
|
|
||||||
return &curEntry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DynamicLinkingHelper::addReloationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length,
|
|
||||||
const std::shared_ptr<RelocationData> &relocationData) {
|
|
||||||
return addReloationEntry(linking_data, linking_entries, linking_entry_length, relocationData->getType(), relocationData->getOffset(), relocationData->getAddend(), relocationData->getDestination(),
|
|
||||||
relocationData->getName(),
|
|
||||||
relocationData->getImportRPLInformation());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DynamicLinkingHelper::addReloationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset,
|
|
||||||
int32_t addend, const void *destination,
|
|
||||||
const std::string &name, const std::shared_ptr<ImportRPLInformation> &rplInfo) {
|
|
||||||
dyn_linking_import_t *importInfoGbl = DynamicLinkingHelper::getOrAddImport(linking_data, rplInfo->getName().c_str(), rplInfo->isData());
|
|
||||||
if (importInfoGbl == nullptr) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Getting import info failed. Probably maximum of %d rpl files to import reached.", DYN_LINK_IMPORT_LIST_LENGTH);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
dyn_linking_function_t *functionInfo = DynamicLinkingHelper::getOrAddFunctionEntryByName(linking_data, name.c_str());
|
|
||||||
if (functionInfo == nullptr) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Getting import info failed. Probably maximum of %d function to be relocated reached.", DYN_LINK_FUNCTION_LIST_LENGTH);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return addReloationEntry(linking_entries, linking_entry_length, type, offset, addend, destination, functionInfo, importInfoGbl);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DynamicLinkingHelper::addReloationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, const void *destination,
|
|
||||||
dyn_linking_function_t *functionName,
|
|
||||||
dyn_linking_import_t *importInfo) {
|
|
||||||
for (uint32_t i = 0; i < linking_entry_length; i++) {
|
|
||||||
dyn_linking_relocation_entry_t *curEntry = &(linking_entries[i]);
|
|
||||||
if (curEntry->functionEntry != nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
curEntry->type = type;
|
|
||||||
curEntry->offset = offset;
|
|
||||||
curEntry->addend = addend;
|
|
||||||
curEntry->destination = (void *) destination;
|
|
||||||
curEntry->functionEntry = functionName;
|
|
||||||
curEntry->importEntry = importInfo;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to find empty slot for saving relocations entry. We need more than %d slots.", linking_entry_length);
|
|
||||||
return false;
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "RelocationData.h"
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <wums/defines/dynamic_linking_defines.h>
|
|
||||||
|
|
||||||
class DynamicLinkingHelper {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
Gets the function entry for a given function name. If the function name is not present in the list, it will be added.
|
|
||||||
|
|
||||||
\param functionName Name of the function
|
|
||||||
\return Returns a pointer to the entry which contains the functionName. Null on error or if the list full.
|
|
||||||
**/
|
|
||||||
static dyn_linking_function_t *getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Gets the function import entry for a given function name. If the import is not present in the list, it will be added.
|
|
||||||
This will return entries for _function_ imports.
|
|
||||||
|
|
||||||
\param importName Name of the function
|
|
||||||
\return Returns a pointer to the function import entry which contains the importName. Null on error or if the list full.
|
|
||||||
**/
|
|
||||||
static dyn_linking_import_t *getOrAddFunctionImportByName(dyn_linking_relocation_data_t *data, const char *importName);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Gets the data import entry for a given data name. If the import is not present in the list, it will be added.
|
|
||||||
This will return entries for _data_ imports.
|
|
||||||
|
|
||||||
\param importName Name of the data
|
|
||||||
\return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full.
|
|
||||||
**/
|
|
||||||
static dyn_linking_import_t *getOrAddDataImportByName(dyn_linking_relocation_data_t *data, const char *importName);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Gets the import entry for a given data name and type. If the import is not present in the list, it will be added.
|
|
||||||
This will return entries for _data_ and _function_ imports, depending on the isData parameter.
|
|
||||||
|
|
||||||
\param importName Name of the data
|
|
||||||
\param isData Set this to true to return a data import
|
|
||||||
|
|
||||||
\return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full.
|
|
||||||
**/
|
|
||||||
static dyn_linking_import_t *getOrAddImport(dyn_linking_relocation_data_t *data, const char *importName, bool isData);
|
|
||||||
|
|
||||||
static bool addReloationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length,
|
|
||||||
const std::shared_ptr<RelocationData> &relocationData);
|
|
||||||
|
|
||||||
static bool
|
|
||||||
addReloationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend,
|
|
||||||
const void *destination, const std::string &name,
|
|
||||||
const std::shared_ptr<ImportRPLInformation> &rplInfo);
|
|
||||||
|
|
||||||
static bool addReloationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, const void *destination,
|
|
||||||
dyn_linking_function_t *functionName,
|
|
||||||
dyn_linking_import_t *importInfo);
|
|
||||||
|
|
||||||
private:
|
|
||||||
DynamicLinkingHelper() = default;
|
|
||||||
|
|
||||||
~DynamicLinkingHelper() = default;
|
|
||||||
};
|
|
@ -16,17 +16,19 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "utils/logger.h"
|
||||||
#include <function_patcher/fpatching_defines.h>
|
#include <function_patcher/fpatching_defines.h>
|
||||||
|
#include <function_patcher/function_patching.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class FunctionData {
|
class FunctionData {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FunctionData(void *paddress, void *vaddress, const std::string &name, function_replacement_library_type_t library, void *replaceAddr, void *replaceCall,
|
FunctionData(void *paddress, void *vaddress, std::string name, function_replacement_library_type_t library, void *replaceAddr, void *replaceCall,
|
||||||
FunctionPatcherTargetProcess targetProcess) {
|
FunctionPatcherTargetProcess targetProcess) {
|
||||||
this->paddress = paddress;
|
this->paddress = paddress;
|
||||||
this->vaddress = vaddress;
|
this->vaddress = vaddress;
|
||||||
this->name = name;
|
this->name = std::move(name);
|
||||||
this->library = library;
|
this->library = library;
|
||||||
this->targetProcess = targetProcess;
|
this->targetProcess = targetProcess;
|
||||||
this->replaceAddr = replaceAddr;
|
this->replaceAddr = replaceAddr;
|
||||||
@ -63,6 +65,42 @@ public:
|
|||||||
return targetProcess;
|
return targetProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool patch() {
|
||||||
|
if (handle == 0) {
|
||||||
|
function_replacement_data_t functionData = {
|
||||||
|
.VERSION = FUNCTION_REPLACEMENT_DATA_STRUCT_VERSION,
|
||||||
|
.physicalAddr = reinterpret_cast<uint32_t>(this->paddress),
|
||||||
|
.virtualAddr = reinterpret_cast<uint32_t>(this->vaddress),
|
||||||
|
.replaceAddr = reinterpret_cast<uint32_t>(this->replaceAddr),
|
||||||
|
.replaceCall = static_cast<uint32_t *>(this->replaceCall),
|
||||||
|
.library = this->library,
|
||||||
|
.function_name = this->name.c_str(),
|
||||||
|
.targetProcess = this->targetProcess};
|
||||||
|
|
||||||
|
if (!FunctionPatcherPatchFunction(&functionData, &handle)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to patch function");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE("Function is already patched");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool restore() {
|
||||||
|
if (handle != 0) {
|
||||||
|
if (!FunctionPatcherRestoreFunction(handle)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to restore function patch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
handle = 0;
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE("Was not patched.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void *paddress = nullptr;
|
void *paddress = nullptr;
|
||||||
void *vaddress = nullptr;
|
void *vaddress = nullptr;
|
||||||
@ -71,4 +109,6 @@ private:
|
|||||||
FunctionPatcherTargetProcess targetProcess;
|
FunctionPatcherTargetProcess targetProcess;
|
||||||
void *replaceAddr = nullptr;
|
void *replaceAddr = nullptr;
|
||||||
void *replaceCall = nullptr;
|
void *replaceCall = nullptr;
|
||||||
|
|
||||||
|
PatchedFunctionHandle handle = 0;
|
||||||
};
|
};
|
||||||
|
@ -24,22 +24,24 @@
|
|||||||
class ImportRPLInformation {
|
class ImportRPLInformation {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ImportRPLInformation(std::string name, bool isData = false) {
|
explicit ImportRPLInformation(std::string name) {
|
||||||
this->name = std::move(name);
|
this->name = std::move(name);
|
||||||
this->_isData = isData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~ImportRPLInformation() = default;
|
~ImportRPLInformation() = default;
|
||||||
|
|
||||||
[[nodiscard]] std::string getName() const {
|
[[nodiscard]] const std::string &getName() const {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::string getRPLName() const {
|
||||||
|
return name.substr(strlen(".dimport_"));
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool isData() const {
|
[[nodiscard]] bool isData() const {
|
||||||
return _isData;
|
return name.starts_with(".dimport_");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
bool _isData = false;
|
|
||||||
};
|
};
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Copyright (C) 2020 Maschell
|
* Copyright (C) 2020 Maschell
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
@ -21,42 +21,33 @@
|
|||||||
#include "PluginInformation.h"
|
#include "PluginInformation.h"
|
||||||
#include "PluginMetaInformation.h"
|
#include "PluginMetaInformation.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
class PluginContainer {
|
class PluginContainer {
|
||||||
public:
|
public:
|
||||||
PluginContainer(const PluginContainer &other) {
|
PluginContainer(std::unique_ptr<PluginMetaInformation> metaInformation, std::unique_ptr<PluginInformation> pluginInformation, std::shared_ptr<PluginData> pluginData)
|
||||||
this->pluginData = other.pluginData;
|
: metaInformation(std::move(metaInformation)),
|
||||||
this->pluginInformation = other.pluginInformation;
|
pluginInformation(std::move(pluginInformation)),
|
||||||
this->metaInformation = other.metaInformation;
|
pluginData(std::move(pluginData)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginContainer() = default;
|
[[nodiscard]] const std::unique_ptr<PluginMetaInformation> &getMetaInformation() const {
|
||||||
|
|
||||||
[[nodiscard]] const std::shared_ptr<PluginMetaInformation> &getMetaInformation() const {
|
|
||||||
return this->metaInformation;
|
return this->metaInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMetaInformation(const std::shared_ptr<PluginMetaInformation> &metaInfo) {
|
[[nodiscard]] const std::unique_ptr<PluginInformation> &getPluginInformation() const {
|
||||||
this->metaInformation = metaInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] const std::shared_ptr<PluginInformation> &getPluginInformation() const {
|
|
||||||
return pluginInformation;
|
return pluginInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPluginInformation(const std::shared_ptr<PluginInformation> &_pluginInformation) {
|
|
||||||
this->pluginInformation = _pluginInformation;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] const std::shared_ptr<PluginData> &getPluginData() const {
|
[[nodiscard]] const std::shared_ptr<PluginData> &getPluginData() const {
|
||||||
return pluginData;
|
return pluginData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPluginData(const std::shared_ptr<PluginData> &_pluginData) {
|
uint32_t getHandle() {
|
||||||
this->pluginData = _pluginData;
|
return (uint32_t) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<PluginData> pluginData;
|
const std::unique_ptr<PluginMetaInformation> metaInformation;
|
||||||
std::shared_ptr<PluginMetaInformation> metaInformation;
|
const std::unique_ptr<PluginInformation> pluginInformation;
|
||||||
std::shared_ptr<PluginInformation> pluginInformation;
|
const std::shared_ptr<PluginData> pluginData;
|
||||||
};
|
};
|
||||||
|
@ -1,348 +0,0 @@
|
|||||||
#include <coreinit/cache.h>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "DynamicLinkingHelper.h"
|
|
||||||
#include "PluginContainer.h"
|
|
||||||
#include "PluginContainerPersistence.h"
|
|
||||||
#include "PluginDataPersistence.h"
|
|
||||||
#include "PluginInformationFactory.h"
|
|
||||||
#include "PluginMetaInformationFactory.h"
|
|
||||||
|
|
||||||
bool PluginContainerPersistence::savePlugin(plugin_information_t *pluginInformation, const std::shared_ptr<PluginContainer> &plugin, MEMHeapHandle heapHandle) {
|
|
||||||
int32_t plugin_count = pluginInformation->number_used_plugins;
|
|
||||||
|
|
||||||
auto pluginName = plugin->getMetaInformation()->getName();
|
|
||||||
|
|
||||||
if (plugin_count >= MAXIMUM_PLUGINS - 1) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Maximum of %d plugins reached. %s won't be loaded!", MAXIMUM_PLUGINS, pluginName.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Copy data to global struct.
|
|
||||||
plugin_information_single_t *plugin_data = &(pluginInformation->plugin_data[plugin_count]);
|
|
||||||
|
|
||||||
// Make sure everything is reset.
|
|
||||||
memset((void *) plugin_data, 0, sizeof(plugin_information_single_t));
|
|
||||||
|
|
||||||
const auto &pluginMetaInfo = plugin->getMetaInformation();
|
|
||||||
auto plugin_meta_data = &plugin_data->meta;
|
|
||||||
|
|
||||||
if (pluginMetaInfo->getName().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Warning: name will be truncated.");
|
|
||||||
}
|
|
||||||
strncpy(plugin_meta_data->name, pluginMetaInfo->getName().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
|
||||||
if (pluginMetaInfo->getAuthor().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Warning: author will be truncated.");
|
|
||||||
}
|
|
||||||
strncpy(plugin_meta_data->author, pluginMetaInfo->getAuthor().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
|
||||||
|
|
||||||
if (pluginMetaInfo->getVersion().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Warning: version will be truncated.");
|
|
||||||
}
|
|
||||||
strncpy(plugin_meta_data->version, pluginMetaInfo->getVersion().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
|
||||||
|
|
||||||
if (pluginMetaInfo->getLicense().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Warning: license will be truncated.");
|
|
||||||
}
|
|
||||||
strncpy(plugin_meta_data->license, pluginMetaInfo->getLicense().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
|
||||||
|
|
||||||
if (pluginMetaInfo->getBuildTimestamp().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Warning: build timestamp will be truncated.");
|
|
||||||
}
|
|
||||||
strncpy(plugin_meta_data->buildTimestamp, pluginMetaInfo->getBuildTimestamp().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
|
||||||
|
|
||||||
if (pluginMetaInfo->getDescription().size() >= MAXIMUM_PLUGIN_DESCRIPTION_LENGTH) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Warning: description will be truncated.");
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("%s", pluginMetaInfo->getDescription().c_str());
|
|
||||||
}
|
|
||||||
strncpy(plugin_meta_data->descripion, pluginMetaInfo->getDescription().c_str(), MAXIMUM_PLUGIN_DESCRIPTION_LENGTH - 1);
|
|
||||||
|
|
||||||
if (pluginMetaInfo->getStorageId().length() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Warning: plugin storage id will be truncated.");
|
|
||||||
}
|
|
||||||
strncpy(plugin_meta_data->storageId, pluginMetaInfo->getStorageId().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
|
||||||
|
|
||||||
plugin_meta_data->size = pluginMetaInfo->getSize();
|
|
||||||
|
|
||||||
auto pluginInfo = plugin->getPluginInformation();
|
|
||||||
|
|
||||||
// Relocation
|
|
||||||
auto relocationData = pluginInfo->getRelocationDataList();
|
|
||||||
for (auto &reloc : relocationData) {
|
|
||||||
if (!DynamicLinkingHelper::addReloationEntry(&(pluginInformation->linking_data), plugin_data->info.linking_entries, PLUGIN_DYN_LINK_RELOCATION_LIST_LENGTH, reloc)) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to add a relocation entry");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto function_data_list = pluginInfo->getFunctionDataList();
|
|
||||||
auto hook_data_list = pluginInfo->getHookDataList();
|
|
||||||
|
|
||||||
if (function_data_list.size() > MAXIMUM_FUNCTION_PER_PLUGIN) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Plugin %s would replace to many function (%d, maximum is %d). It won't be loaded.", pluginName.c_str(), function_data_list.size(), MAXIMUM_FUNCTION_PER_PLUGIN);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (hook_data_list.size() > MAXIMUM_HOOKS_PER_PLUGIN) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Plugin %s would set too many hooks (%d, maximum is %d). It won't be loaded.", pluginName.c_str(), hook_data_list.size(), MAXIMUM_HOOKS_PER_PLUGIN);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pluginName.length() > MAXIMUM_PLUGIN_NAME_LENGTH - 1) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Name for plugin %s was too long to be stored.", pluginName.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store function replacement information */
|
|
||||||
uint32_t i = 0;
|
|
||||||
for (auto &curFunction : pluginInfo->getFunctionDataList()) {
|
|
||||||
function_replacement_data_t *function_data = &plugin_data->info.functions[i];
|
|
||||||
if (strlen(curFunction->getName().c_str()) > MAXIMUM_FUNCTION_NAME_LENGTH - 1) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Could not add function \"%s\" for plugin \"%s\" function name is too long.", curFunction->getName().c_str(), pluginName.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Adding function \"%s\" for plugin \"%s\"", curFunction->getName().c_str(), pluginName.c_str());
|
|
||||||
|
|
||||||
strncpy(function_data->function_name, curFunction->getName().c_str(), MAXIMUM_FUNCTION_NAME_LENGTH - 1);
|
|
||||||
|
|
||||||
function_data->VERSION = FUNCTION_REPLACEMENT_DATA_STRUCT_VERSION;
|
|
||||||
function_data->library = (function_replacement_library_type_t) curFunction->getLibrary();
|
|
||||||
function_data->replaceAddr = (uint32_t) curFunction->getReplaceAddress();
|
|
||||||
function_data->replaceCall = (uint32_t) curFunction->getReplaceCall();
|
|
||||||
function_data->physicalAddr = (uint32_t) curFunction->getPhysicalAddress();
|
|
||||||
function_data->virtualAddr = (uint32_t) curFunction->getVirtualAddress();
|
|
||||||
function_data->targetProcess = curFunction->getTargetProcess();
|
|
||||||
|
|
||||||
plugin_data->info.number_used_functions++;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
for (auto &curHook : pluginInfo->getHookDataList()) {
|
|
||||||
replacement_data_hook_t *hook_data = &plugin_data->info.hooks[i];
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Set hook for plugin \"%s\" of type %08X to target %08X", plugin_data->meta.name, curHook->getType(), (void *) curHook->getFunctionPointer());
|
|
||||||
|
|
||||||
hook_data->func_pointer = (void *) curHook->getFunctionPointer();
|
|
||||||
hook_data->type = curHook->getType();
|
|
||||||
|
|
||||||
plugin_data->info.number_used_hooks++;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Saving SectionInfos */
|
|
||||||
for (auto &curSection : pluginInfo->getSectionInfoList()) {
|
|
||||||
bool foundFreeSlot = false;
|
|
||||||
uint32_t slot = 0;
|
|
||||||
for (uint32_t j = 0; j < MAXIMUM_PLUGIN_SECTION_LENGTH; j++) {
|
|
||||||
auto *sectionInfo = &(plugin_data->info.sectionInfos[j]);
|
|
||||||
if (sectionInfo->addr == 0 && sectionInfo->size == 0) {
|
|
||||||
foundFreeSlot = true;
|
|
||||||
slot = j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (foundFreeSlot) {
|
|
||||||
auto *sectionInfo = &(plugin_data->info.sectionInfos[slot]);
|
|
||||||
if (curSection.first.length() > MAXIMUM_PLUGIN_SECTION_NAME_LENGTH - 1) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Could not add section info \"%s\" for plugin \"%s\" section name is too long.", curSection.first.c_str(), pluginName.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
strncpy(sectionInfo->name, curSection.first.c_str(), MAXIMUM_PLUGIN_SECTION_NAME_LENGTH - 1);
|
|
||||||
sectionInfo->addr = curSection.second->getAddress();
|
|
||||||
sectionInfo->size = curSection.second->getSize();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to store SectionInfos");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
plugin_data->info.trampolineId = pluginInfo->getTrampolineId();
|
|
||||||
plugin_data->info.allocatedTextMemoryAddress = pluginInfo->allocatedTextMemoryAddress;
|
|
||||||
plugin_data->info.allocatedDataMemoryAddress = pluginInfo->allocatedDataMemoryAddress;
|
|
||||||
|
|
||||||
uint32_t entryCount = pluginInfo->getFunctionSymbolDataList().size();
|
|
||||||
if (entryCount > 0) {
|
|
||||||
// Saving SectionInfos
|
|
||||||
uint32_t funcSymStringLen = 1;
|
|
||||||
for (auto &curFuncSym : pluginInfo->getFunctionSymbolDataList()) {
|
|
||||||
funcSymStringLen += curFuncSym->getName().length() + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *stringTable = (char *) MEMAllocFromExpHeapEx(heapHandle, funcSymStringLen, 0x4);
|
|
||||||
if (stringTable == nullptr) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed alloc memory to store string table for function symbol data");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
memset(stringTable, 0, funcSymStringLen);
|
|
||||||
DEBUG_FUNCTION_LINE("Allocated %d for the function symbol string table", funcSymStringLen);
|
|
||||||
auto *entryTable = (plugin_function_symbol_data_t *) MEMAllocFromExpHeapEx(heapHandle, entryCount * sizeof(plugin_function_symbol_data_t), 0x4);
|
|
||||||
if (entryTable == nullptr) {
|
|
||||||
MEMFreeToExpHeap((MEMHeapHandle) heapHandle, stringTable);
|
|
||||||
free(stringTable);
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed alloc memory to store function symbol data");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
DEBUG_FUNCTION_LINE("Allocated %d for the function symbol data", entryCount * sizeof(plugin_function_symbol_data_t));
|
|
||||||
|
|
||||||
uint32_t curStringOffset = 0;
|
|
||||||
uint32_t curEntryIndex = 0;
|
|
||||||
for (auto &curFuncSym : pluginInfo->getFunctionSymbolDataList()) {
|
|
||||||
entryTable[curEntryIndex].address = curFuncSym->getAddress();
|
|
||||||
entryTable[curEntryIndex].name = &stringTable[curStringOffset];
|
|
||||||
entryTable[curEntryIndex].size = curFuncSym->getSize();
|
|
||||||
auto len = curFuncSym->getName().length() + 1;
|
|
||||||
memcpy(stringTable + curStringOffset, curFuncSym->getName().c_str(), len);
|
|
||||||
curStringOffset += len;
|
|
||||||
curEntryIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin_data->info.allocatedFuncSymStringTableAddress = stringTable;
|
|
||||||
plugin_data->info.function_symbol_data = entryTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin_data->info.number_function_symbol_data = entryCount;
|
|
||||||
|
|
||||||
/* Copy plugin data */
|
|
||||||
auto pluginData = plugin->getPluginData();
|
|
||||||
auto plugin_data_data = &plugin_data->data;
|
|
||||||
|
|
||||||
PluginDataPersistence::save(plugin_data_data, pluginData);
|
|
||||||
|
|
||||||
pluginInformation->number_used_plugins++;
|
|
||||||
|
|
||||||
DCFlushRange((void *) pluginInformation, sizeof(plugin_information_t));
|
|
||||||
ICInvalidateRange((void *) pluginInformation, sizeof(plugin_information_t));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<PluginContainer>> PluginContainerPersistence::loadPlugins(plugin_information_t *pluginInformation) {
|
|
||||||
std::vector<std::shared_ptr<PluginContainer>> result;
|
|
||||||
if (pluginInformation == nullptr) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("pluginInformation == nullptr");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
DCFlushRange((void *) pluginInformation, sizeof(plugin_information_t));
|
|
||||||
ICInvalidateRange((void *) pluginInformation, sizeof(plugin_information_t));
|
|
||||||
|
|
||||||
int32_t plugin_count = pluginInformation->number_used_plugins;
|
|
||||||
if (plugin_count > MAXIMUM_PLUGINS) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("pluginInformation->plugin_count was bigger then allowed. %d > %d. Limiting to %d", plugin_count, MAXIMUM_PLUGINS, MAXIMUM_PLUGINS);
|
|
||||||
plugin_count = MAXIMUM_PLUGINS;
|
|
||||||
}
|
|
||||||
for (int32_t i = 0; i < plugin_count; i++) {
|
|
||||||
// Copy data from struct.
|
|
||||||
plugin_information_single_t *plugin_data = &(pluginInformation->plugin_data[i]);
|
|
||||||
|
|
||||||
auto metaInformation = std::shared_ptr<PluginMetaInformation>(new PluginMetaInformation);
|
|
||||||
|
|
||||||
plugin_meta_info_t *meta = &(plugin_data->meta);
|
|
||||||
metaInformation->setAuthor(meta->author);
|
|
||||||
metaInformation->setVersion(meta->version);
|
|
||||||
metaInformation->setBuildTimestamp(meta->buildTimestamp);
|
|
||||||
metaInformation->setLicense(meta->license);
|
|
||||||
metaInformation->setDescription(meta->descripion);
|
|
||||||
metaInformation->setSize(meta->size);
|
|
||||||
metaInformation->setName(meta->name);
|
|
||||||
metaInformation->setStorageId(meta->storageId);
|
|
||||||
|
|
||||||
plugin_data_t *data = &(plugin_data->data);
|
|
||||||
|
|
||||||
auto pluginData = PluginDataPersistence::load(data);
|
|
||||||
|
|
||||||
auto curPluginInformation = std::make_shared<PluginInformation>();
|
|
||||||
|
|
||||||
curPluginInformation->setTrampolineId(plugin_data->info.trampolineId);
|
|
||||||
curPluginInformation->allocatedTextMemoryAddress = plugin_data->info.allocatedTextMemoryAddress;
|
|
||||||
curPluginInformation->allocatedDataMemoryAddress = plugin_data->info.allocatedDataMemoryAddress;
|
|
||||||
|
|
||||||
for (auto &curItem : plugin_data->info.sectionInfos) {
|
|
||||||
plugin_section_info_t *sectionInfo = &curItem;
|
|
||||||
if (sectionInfo->addr == 0 && sectionInfo->size == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Add SectionInfo %s", sectionInfo->name);
|
|
||||||
std::string name(sectionInfo->name);
|
|
||||||
curPluginInformation->addSectionInfo(std::make_shared<SectionInfo>(name, sectionInfo->addr, sectionInfo->size));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* load hook data */
|
|
||||||
uint32_t hookCount = plugin_data->info.number_used_hooks;
|
|
||||||
|
|
||||||
if (hookCount > MAXIMUM_HOOKS_PER_PLUGIN) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("number_used_hooks was bigger then allowed. %d > %d. Limiting to %d", hookCount, MAXIMUM_HOOKS_PER_PLUGIN, MAXIMUM_HOOKS_PER_PLUGIN);
|
|
||||||
hookCount = MAXIMUM_HOOKS_PER_PLUGIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t j = 0; j < hookCount; j++) {
|
|
||||||
replacement_data_hook_t *hook_entry = &(plugin_data->info.hooks[j]);
|
|
||||||
curPluginInformation->addHookData(std::make_shared<HookData>(hook_entry->func_pointer, hook_entry->type));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool storageHasId = true;
|
|
||||||
for (auto const &value : curPluginInformation->getHookDataList()) {
|
|
||||||
if (value->getType() == WUPS_LOADER_HOOK_INIT_STORAGE &&
|
|
||||||
metaInformation->getStorageId().empty()) {
|
|
||||||
storageHasId = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!storageHasId) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Plugin is using the storage API but has not set an ID");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* load function replacement data */
|
|
||||||
uint32_t functionReplaceCount = plugin_data->info.number_used_functions;
|
|
||||||
|
|
||||||
if (functionReplaceCount > MAXIMUM_FUNCTION_PER_PLUGIN) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("number_used_functions was bigger then allowed. %d > %d. Limiting to %d", functionReplaceCount, MAXIMUM_FUNCTION_PER_PLUGIN, MAXIMUM_FUNCTION_PER_PLUGIN);
|
|
||||||
functionReplaceCount = MAXIMUM_FUNCTION_PER_PLUGIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t j = 0; j < functionReplaceCount; j++) {
|
|
||||||
function_replacement_data_t *entry = &(plugin_data->info.functions[j]);
|
|
||||||
auto func = std::make_shared<FunctionData>((void *) entry->physicalAddr, (void *) entry->virtualAddr, entry->function_name, (function_replacement_library_type_t) entry->library,
|
|
||||||
(void *) entry->replaceAddr,
|
|
||||||
(void *) entry->replaceCall, entry->targetProcess);
|
|
||||||
curPluginInformation->addFunctionData(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* load relocation data */
|
|
||||||
for (auto &linking_entry : plugin_data->info.linking_entries) {
|
|
||||||
if (linking_entry.destination == nullptr) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dyn_linking_import_t *importEntry = linking_entry.importEntry;
|
|
||||||
if (importEntry == nullptr) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("importEntry was nullptr, skipping relocation entry");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
dyn_linking_function_t *functionEntry = linking_entry.functionEntry;
|
|
||||||
|
|
||||||
if (functionEntry == nullptr) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("functionEntry was nullptr, skipping relocation entry");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto rplInfo = std::make_shared<ImportRPLInformation>(importEntry->importName, importEntry->isData);
|
|
||||||
std::string functionName(functionEntry->functionName);
|
|
||||||
auto reloc = std::make_shared<RelocationData>(linking_entry.type, linking_entry.offset, linking_entry.addend, linking_entry.destination, functionName, rplInfo);
|
|
||||||
curPluginInformation->addRelocationData(reloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* load function symbol data */
|
|
||||||
for (uint32_t j = 0; j < plugin_data->info.number_function_symbol_data; j++) {
|
|
||||||
auto symbol_data = &plugin_data->info.function_symbol_data[j];
|
|
||||||
std::string symbol_name = symbol_data->name;
|
|
||||||
auto funSymbolData = std::make_shared<FunctionSymbolData>(symbol_name, (void *) symbol_data->address, symbol_data->size);
|
|
||||||
curPluginInformation->addFunctionSymbolData(funSymbolData);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto container = std::make_shared<PluginContainer>();
|
|
||||||
container->setMetaInformation(metaInformation);
|
|
||||||
container->setPluginData(pluginData);
|
|
||||||
container->setPluginInformation(curPluginInformation);
|
|
||||||
result.push_back(container);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../common/plugin_defines.h"
|
|
||||||
#include "PluginContainer.h"
|
|
||||||
|
|
||||||
class PluginContainerPersistence {
|
|
||||||
public:
|
|
||||||
static bool savePlugin(plugin_information_t *pluginInformation, const std::shared_ptr<PluginContainer> &plugin, MEMHeapHandle heapHandle);
|
|
||||||
|
|
||||||
static std::vector<std::shared_ptr<PluginContainer>> loadPlugins(plugin_information_t *pluginInformation);
|
|
||||||
};
|
|
@ -1,63 +1,15 @@
|
|||||||
#include "PluginData.h"
|
#include "PluginData.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include "utils/utils.h"
|
||||||
|
|
||||||
#include "../utils/logger.h"
|
PluginData::PluginData(const std::vector<uint8_t> &input) : length(input.size()) {
|
||||||
#include <malloc.h>
|
auto data_copy = make_unique_nothrow<uint8_t[]>(length);
|
||||||
|
if (!data_copy) {
|
||||||
PluginData::PluginData(const PluginData &obj) {
|
|
||||||
this->buffer = obj.buffer;
|
|
||||||
this->heapHandle = obj.heapHandle;
|
|
||||||
this->memoryType = obj.memoryType;
|
|
||||||
this->length = obj.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginData::freeMemory() {
|
|
||||||
if (buffer == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (memoryType) {
|
|
||||||
default:
|
|
||||||
case eMemTypeExpHeap:
|
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Free PluginData buffer %08X on heap %08X", buffer, this->heapHandle);
|
|
||||||
MEMFreeToExpHeap(this->heapHandle, buffer);
|
|
||||||
this->buffer = nullptr;
|
|
||||||
break;
|
|
||||||
case eMemTypeMEM2:
|
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Free PluginData buffer %08X on default heap", buffer);
|
|
||||||
free(this->buffer);
|
|
||||||
this->buffer = nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginData::PluginData(const std::vector<uint8_t> &buffer) : PluginData(buffer, nullptr, eMemTypeMEM2) {
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginData::PluginData(const std::vector<uint8_t> &input, MEMHeapHandle heapHandle, eMemoryTypes memoryType) : heapHandle(heapHandle),
|
|
||||||
memoryType(memoryType),
|
|
||||||
length(input.size()) {
|
|
||||||
void *data_copy = nullptr;
|
|
||||||
switch (memoryType) {
|
|
||||||
default:
|
|
||||||
case eMemTypeExpHeap:
|
|
||||||
data_copy = MEMAllocFromExpHeapEx(heapHandle, length, 4);
|
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb on ExpHeap", length / 1024);
|
|
||||||
if (data_copy == nullptr) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate space on exp heap");
|
|
||||||
} else {
|
|
||||||
memcpy(data_copy, &input[0], length);
|
|
||||||
}
|
|
||||||
this->buffer = data_copy;
|
|
||||||
break;
|
|
||||||
case eMemTypeMEM2:
|
|
||||||
data_copy = memalign(4, length);
|
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb on default heap", length / 1024);
|
|
||||||
if (data_copy == nullptr) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate space on default heap");
|
DEBUG_FUNCTION_LINE_ERR("Failed to allocate space on default heap");
|
||||||
|
this->length = 0;
|
||||||
} else {
|
} else {
|
||||||
memcpy(data_copy, &input[0], length);
|
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb on default heap", length / 1024);
|
||||||
}
|
memcpy(data_copy.get(), &input[0], length);
|
||||||
this->buffer = data_copy;
|
this->buffer = std::move(data_copy);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,41 +19,18 @@
|
|||||||
|
|
||||||
#include <coreinit/memexpheap.h>
|
#include <coreinit/memexpheap.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../elfio/elfio.hpp"
|
|
||||||
|
|
||||||
using namespace ELFIO;
|
|
||||||
|
|
||||||
enum eMemoryTypes {
|
|
||||||
eMemTypeMEM2,
|
|
||||||
eMemTypeExpHeap
|
|
||||||
};
|
|
||||||
|
|
||||||
class PluginData {
|
class PluginData {
|
||||||
public:
|
public:
|
||||||
~PluginData() = default;
|
|
||||||
|
|
||||||
void freeMemory();
|
|
||||||
|
|
||||||
PluginData(const PluginData &obj);
|
|
||||||
|
|
||||||
PluginData() = default;
|
|
||||||
|
|
||||||
void *buffer = nullptr;
|
|
||||||
MEMHeapHandle heapHandle{};
|
|
||||||
eMemoryTypes memoryType{};
|
|
||||||
size_t length = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
explicit PluginData(const std::vector<uint8_t> &buffer);
|
explicit PluginData(const std::vector<uint8_t> &buffer);
|
||||||
|
|
||||||
PluginData(const std::vector<uint8_t> &input, MEMHeapHandle heapHandle, eMemoryTypes memoryType);
|
uint32_t getHandle() {
|
||||||
|
return (uint32_t) this;
|
||||||
|
}
|
||||||
|
|
||||||
friend class PluginDataFactory;
|
size_t length = 0;
|
||||||
|
std::unique_ptr<uint8_t[]> buffer;
|
||||||
friend class PluginContainer;
|
|
||||||
|
|
||||||
friend class PluginDataPersistence;
|
|
||||||
};
|
};
|
||||||
|
@ -15,33 +15,35 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "PluginDataFactory.h"
|
#include "PluginDataFactory.h"
|
||||||
#include "../fs/FSUtils.h"
|
#include "fs/FSUtils.h"
|
||||||
#include "../utils/StringTools.h"
|
#include "utils/StringTools.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include "utils/utils.h"
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <forward_list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
std::vector<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const std::string &path, MEMHeapHandle heapHandle) {
|
std::forward_list<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const std::string &path) {
|
||||||
std::vector<std::shared_ptr<PluginData>> result;
|
std::forward_list<std::shared_ptr<PluginData>> result;
|
||||||
struct dirent *dp;
|
struct dirent *dp;
|
||||||
DIR *dfd;
|
DIR *dfd;
|
||||||
|
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Path was empty");
|
DEBUG_FUNCTION_LINE_ERR("Failed to load Plugins from dir: Path was empty");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dfd = opendir(path.c_str())) == nullptr) {
|
if ((dfd = opendir(path.c_str())) == nullptr) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Couldn't open dir %s", path.c_str());
|
DEBUG_FUNCTION_LINE_ERR("Couldn't open dir %s", path.c_str());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((dp = readdir(dfd)) != nullptr) {
|
while ((dp = readdir(dfd)) != nullptr) {
|
||||||
struct stat stbuf {};
|
struct stat stbuf {};
|
||||||
std::string full_file_path = StringTools::strfmt("%s/%s", path.c_str(), dp->d_name);
|
auto full_file_path = string_format("%s/%s", path.c_str(), dp->d_name);
|
||||||
StringTools::RemoveDoubleSlashs(full_file_path);
|
|
||||||
if (stat(full_file_path.c_str(), &stbuf) == -1) {
|
if (stat(full_file_path.c_str(), &stbuf) == -1) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Unable to stat file: %s", full_file_path.c_str());
|
DEBUG_FUNCTION_LINE_ERR("Unable to stat file: %s", full_file_path.c_str());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,24 +51,25 @@ std::vector<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const std::s
|
|||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE("Loading plugin: %s", full_file_path.c_str());
|
DEBUG_FUNCTION_LINE("Loading plugin: %s", full_file_path.c_str());
|
||||||
auto pluginData = load(full_file_path, heapHandle);
|
auto pluginData = load(full_file_path);
|
||||||
if (pluginData) {
|
if (pluginData) {
|
||||||
result.push_back(pluginData.value());
|
result.push_front(std::move(pluginData.value()));
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to load plugin: %s", full_file_path.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dfd != nullptr) {
|
|
||||||
closedir(dfd);
|
closedir(dfd);
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::shared_ptr<PluginData>> PluginDataFactory::load(const std::string &filename, MEMHeapHandle heapHandle) {
|
std::optional<std::unique_ptr<PluginData>> PluginDataFactory::load(const std::string &filename) {
|
||||||
uint8_t *buffer = nullptr;
|
uint8_t *buffer = nullptr;
|
||||||
uint32_t fsize = 0;
|
uint32_t fsize = 0;
|
||||||
if (FSUtils::LoadFileToMem(filename.c_str(), &buffer, &fsize) < 0) {
|
if (FSUtils::LoadFileToMem(filename.c_str(), &buffer, &fsize) < 0) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Failed to load file");
|
DEBUG_FUNCTION_LINE_ERR("Failed to load %s into memory", filename.c_str());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,13 +80,18 @@ std::optional<std::shared_ptr<PluginData>> PluginDataFactory::load(const std::st
|
|||||||
|
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Loaded file!");
|
DEBUG_FUNCTION_LINE_VERBOSE("Loaded file!");
|
||||||
|
|
||||||
return load(result, heapHandle);
|
return load(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::shared_ptr<PluginData>> PluginDataFactory::load(std::vector<uint8_t> &buffer, MEMHeapHandle heapHandle) {
|
std::optional<std::unique_ptr<PluginData>> PluginDataFactory::load(const std::vector<uint8_t> &buffer) {
|
||||||
if (buffer.empty()) {
|
if (buffer.empty()) {
|
||||||
return std::nullopt;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::shared_ptr<PluginData>(new PluginData(buffer, heapHandle, eMemoryTypes::eMemTypeMEM2));
|
auto res = make_unique_nothrow<PluginData>(buffer);
|
||||||
|
if (!res) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "PluginData.h"
|
#include "PluginData.h"
|
||||||
#include <coreinit/memexpheap.h>
|
#include <coreinit/memexpheap.h>
|
||||||
|
#include <forward_list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -26,9 +27,9 @@
|
|||||||
|
|
||||||
class PluginDataFactory {
|
class PluginDataFactory {
|
||||||
public:
|
public:
|
||||||
static std::vector<std::shared_ptr<PluginData>> loadDir(const std::string &path, MEMHeapHandle heapHandle);
|
static std::forward_list<std::shared_ptr<PluginData>> loadDir(const std::string &path);
|
||||||
|
|
||||||
static std::optional<std::shared_ptr<PluginData>> load(const std::string &path, MEMHeapHandle heapHandle);
|
static std::optional<std::unique_ptr<PluginData>> load(const std::string &path);
|
||||||
|
|
||||||
static std::optional<std::shared_ptr<PluginData>> load(std::vector<uint8_t> &buffer, MEMHeapHandle heapHandle);
|
static std::optional<std::unique_ptr<PluginData>> load(const std::vector<uint8_t> &buffer);
|
||||||
};
|
};
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
#include "PluginDataPersistence.h"
|
|
||||||
#include "../common/plugin_defines.h"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
bool PluginDataPersistence::save(plugin_data_t *pluginDataStruct, const std::shared_ptr<PluginData> &plugin) {
|
|
||||||
if (pluginDataStruct == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
pluginDataStruct->buffer = (char *) plugin->buffer;
|
|
||||||
pluginDataStruct->bufferLength = plugin->length;
|
|
||||||
pluginDataStruct->memoryType = plugin->memoryType;
|
|
||||||
pluginDataStruct->heapHandle = (int) plugin->heapHandle;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PluginDataPersistence::save(plugin_data_t *pluginDataStruct, PluginData *plugin) {
|
|
||||||
if (pluginDataStruct == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
pluginDataStruct->buffer = (char *) plugin->buffer;
|
|
||||||
pluginDataStruct->bufferLength = plugin->length;
|
|
||||||
pluginDataStruct->memoryType = plugin->memoryType;
|
|
||||||
pluginDataStruct->heapHandle = (int) plugin->heapHandle;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<PluginData> PluginDataPersistence::load(plugin_data_t *pluginDataStruct) {
|
|
||||||
auto pluginData = std::make_shared<PluginData>();
|
|
||||||
|
|
||||||
pluginData->buffer = pluginDataStruct->buffer;
|
|
||||||
pluginData->length = pluginDataStruct->bufferLength;
|
|
||||||
pluginData->memoryType = (eMemoryTypes) pluginDataStruct->memoryType;
|
|
||||||
pluginData->heapHandle = (MEMHeapHandle) pluginDataStruct->heapHandle;
|
|
||||||
return pluginData;
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../common/plugin_defines.h"
|
|
||||||
#include "PluginData.h"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class PluginDataPersistence {
|
|
||||||
|
|
||||||
public:
|
|
||||||
static bool save(plugin_data_t *pluginDataStruct, const std::shared_ptr<PluginData> &plugin);
|
|
||||||
|
|
||||||
static bool save(plugin_data_t *pluginDataStruct, PluginData *plugin);
|
|
||||||
|
|
||||||
static std::shared_ptr<PluginData> load(plugin_data_t *pluginDataStruct);
|
|
||||||
};
|
|
@ -1,20 +0,0 @@
|
|||||||
#include "PluginInformation.h"
|
|
||||||
|
|
||||||
PluginInformation::PluginInformation(const PluginInformation &other) {
|
|
||||||
for (const auto &i : other.hook_data_list) {
|
|
||||||
hook_data_list.push_back(i);
|
|
||||||
}
|
|
||||||
for (const auto &i : other.function_data_list) {
|
|
||||||
function_data_list.push_back(i);
|
|
||||||
}
|
|
||||||
for (const auto &i : other.relocation_data_list) {
|
|
||||||
relocation_data_list.push_back(i);
|
|
||||||
}
|
|
||||||
for (const auto &i : other.symbol_data_list) {
|
|
||||||
symbol_data_list.insert(i);
|
|
||||||
}
|
|
||||||
section_info_list = other.section_info_list;
|
|
||||||
trampolineId = other.trampolineId;
|
|
||||||
allocatedTextMemoryAddress = other.allocatedTextMemoryAddress;
|
|
||||||
allocatedDataMemoryAddress = other.allocatedDataMemoryAddress;
|
|
||||||
}
|
|
@ -26,6 +26,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <ranges>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -39,47 +40,41 @@ struct FunctionSymbolDataComparator {
|
|||||||
|
|
||||||
class PluginInformation {
|
class PluginInformation {
|
||||||
public:
|
public:
|
||||||
PluginInformation(const PluginInformation &other);
|
void addHookData(std::unique_ptr<HookData> hook_data) {
|
||||||
|
hook_data_list.push_back(std::move(hook_data));
|
||||||
PluginInformation() = default;
|
|
||||||
|
|
||||||
virtual ~PluginInformation() = default;
|
|
||||||
|
|
||||||
void addHookData(const std::shared_ptr<HookData> &hook_data) {
|
|
||||||
hook_data_list.push_back(hook_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const std::vector<std::shared_ptr<HookData>> &getHookDataList() const {
|
[[nodiscard]] const std::vector<std::unique_ptr<HookData>> &getHookDataList() const {
|
||||||
return hook_data_list;
|
return hook_data_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addFunctionData(const std::shared_ptr<FunctionData> &function_data) {
|
void addFunctionData(std::unique_ptr<FunctionData> function_data) {
|
||||||
function_data_list.push_back(function_data);
|
function_data_list.push_back(std::move(function_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const std::vector<std::shared_ptr<FunctionData>> &getFunctionDataList() const {
|
[[nodiscard]] const std::vector<std::unique_ptr<FunctionData>> &getFunctionDataList() const {
|
||||||
return function_data_list;
|
return function_data_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addRelocationData(const std::shared_ptr<RelocationData> &relocation_data) {
|
void addRelocationData(std::unique_ptr<RelocationData> relocation_data) {
|
||||||
relocation_data_list.push_back(relocation_data);
|
relocation_data_list.push_back(std::move(relocation_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const std::vector<std::shared_ptr<RelocationData>> &getRelocationDataList() const {
|
[[nodiscard]] const std::vector<std::unique_ptr<RelocationData>> &getRelocationDataList() const {
|
||||||
return relocation_data_list;
|
return relocation_data_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void addFunctionSymbolData(const std::shared_ptr<FunctionSymbolData> &symbol_data) {
|
void addFunctionSymbolData(std::shared_ptr<FunctionSymbolData> symbol_data) {
|
||||||
symbol_data_list.insert(symbol_data);
|
symbol_data_list.insert(std::move(symbol_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> &getFunctionSymbolDataList() const {
|
[[nodiscard]] const std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> &getFunctionSymbolDataList() const {
|
||||||
return symbol_data_list;
|
return symbol_data_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addSectionInfo(const std::shared_ptr<SectionInfo> §ionInfo) {
|
void addSectionInfo(std::shared_ptr<SectionInfo> sectionInfo) {
|
||||||
section_info_list[sectionInfo->getName()] = sectionInfo;
|
section_info_list[sectionInfo->getName()] = std::move(sectionInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const std::map<std::string, std::shared_ptr<SectionInfo>> &getSectionInfoList() const {
|
[[nodiscard]] const std::map<std::string, std::shared_ptr<SectionInfo>> &getSectionInfoList() const {
|
||||||
@ -87,7 +82,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::optional<std::shared_ptr<SectionInfo>> getSectionInfo(const std::string §ionName) const {
|
[[nodiscard]] std::optional<std::shared_ptr<SectionInfo>> getSectionInfo(const std::string §ionName) const {
|
||||||
if (getSectionInfoList().count(sectionName) > 0) {
|
if (getSectionInfoList().contains(sectionName)) {
|
||||||
return section_info_list.at(sectionName);
|
return section_info_list.at(sectionName);
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@ -101,19 +96,37 @@ public:
|
|||||||
return trampolineId;
|
return trampolineId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::optional<std::shared_ptr<FunctionSymbolData>> getNearestFunctionSymbolData(uint32_t address) const {
|
||||||
|
std::shared_ptr<FunctionSymbolData> result;
|
||||||
|
|
||||||
|
bool foundHit = false;
|
||||||
|
for (auto &cur : symbol_data_list) {
|
||||||
|
if (foundHit && address < (uint32_t) cur->getAddress()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (address >= (uint32_t) cur->getAddress()) {
|
||||||
|
result = cur;
|
||||||
|
foundHit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::shared_ptr<HookData>> hook_data_list;
|
std::vector<std::unique_ptr<HookData>> hook_data_list;
|
||||||
std::vector<std::shared_ptr<FunctionData>> function_data_list;
|
std::vector<std::unique_ptr<FunctionData>> function_data_list;
|
||||||
std::vector<std::shared_ptr<RelocationData>> relocation_data_list;
|
std::vector<std::unique_ptr<RelocationData>> relocation_data_list;
|
||||||
std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> symbol_data_list;
|
std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> symbol_data_list;
|
||||||
std::map<std::string, std::shared_ptr<SectionInfo>> section_info_list;
|
std::map<std::string, std::shared_ptr<SectionInfo>> section_info_list;
|
||||||
|
|
||||||
uint8_t trampolineId = 0;
|
uint8_t trampolineId = 0;
|
||||||
|
|
||||||
void *allocatedTextMemoryAddress = nullptr;
|
std::unique_ptr<uint8_t[]> allocatedTextMemoryAddress;
|
||||||
void *allocatedDataMemoryAddress = nullptr;
|
std::unique_ptr<uint8_t[]> allocatedDataMemoryAddress;
|
||||||
|
|
||||||
friend class PluginInformationFactory;
|
friend class PluginInformationFactory;
|
||||||
|
|
||||||
friend class PluginContainerPersistence;
|
|
||||||
};
|
};
|
||||||
|
@ -22,28 +22,36 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
#include <wups/function_patching.h>
|
#include <wups/function_patching.h>
|
||||||
|
|
||||||
using namespace ELFIO;
|
using namespace ELFIO;
|
||||||
|
|
||||||
std::optional<std::shared_ptr<PluginInformation>>
|
std::optional<std::unique_ptr<PluginInformation>>
|
||||||
PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, MEMHeapHandle heapHandle, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
|
PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
|
||||||
uint8_t trampolineId) {
|
uint8_t trampolineId) {
|
||||||
if (pluginData->buffer == nullptr) {
|
if (!pluginData->buffer) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Buffer was nullptr");
|
DEBUG_FUNCTION_LINE_ERR("Buffer was nullptr");
|
||||||
return std::nullopt;
|
return {};
|
||||||
}
|
}
|
||||||
elfio reader;
|
elfio reader;
|
||||||
if (!reader.load((char *) pluginData->buffer, pluginData->length)) {
|
if (!reader.load((char *) pluginData->buffer.get(), pluginData->length)) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
|
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
|
||||||
return std::nullopt;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pluginInfo = std::make_shared<PluginInformation>();
|
auto pluginInfo = make_unique_nothrow<PluginInformation>();
|
||||||
|
if (!pluginInfo) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to allocate PluginInformation");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t sec_num = reader.sections.size();
|
uint32_t sec_num = reader.sections.size();
|
||||||
auto **destinations = (uint8_t **) malloc(sizeof(uint8_t *) * sec_num);
|
|
||||||
|
auto destinations = make_unique_nothrow<uint8_t *[]>(sec_num);
|
||||||
|
if (!destinations) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed alloc memory for destinations array");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t totalSize = 0;
|
uint32_t totalSize = 0;
|
||||||
|
|
||||||
@ -69,21 +77,22 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void *text_data = MEMAllocFromExpHeapEx(heapHandle, text_size, 0x1000);
|
|
||||||
if (text_data == nullptr) {
|
auto text_data = make_unique_nothrow<uint8_t[]>(text_size);
|
||||||
|
if (!text_data) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes)", text_size);
|
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes)", text_size);
|
||||||
|
return {};
|
||||||
return std::nullopt;
|
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb from ExpHeap", text_size / 1024);
|
|
||||||
void *data_data = MEMAllocFromExpHeapEx(heapHandle, data_size, 0x1000);
|
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb", text_size / 1024);
|
||||||
if (data_data == nullptr) {
|
|
||||||
|
auto data_data = make_unique_nothrow<uint8_t[]>(data_size);
|
||||||
|
if (!data_data) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .data section (%d bytes)", data_size);
|
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .data section (%d bytes)", data_size);
|
||||||
|
return {};
|
||||||
MEMFreeToExpHeap(heapHandle, text_data);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb from ExpHeap", data_size / 1024);
|
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb", data_size / 1024);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
section *psec = reader.sections[i];
|
section *psec = reader.sections[i];
|
||||||
@ -97,23 +106,20 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
|||||||
|
|
||||||
uint32_t destination = address;
|
uint32_t destination = address;
|
||||||
if ((address >= 0x02000000) && address < 0x10000000) {
|
if ((address >= 0x02000000) && address < 0x10000000) {
|
||||||
destination += (uint32_t) text_data;
|
destination += (uint32_t) text_data.get();
|
||||||
destination -= 0x02000000;
|
destination -= 0x02000000;
|
||||||
destinations[psec->get_index()] = (uint8_t *) text_data;
|
destinations[psec->get_index()] = (uint8_t *) text_data.get();
|
||||||
} else if ((address >= 0x10000000) && address < 0xC0000000) {
|
} else if ((address >= 0x10000000) && address < 0xC0000000) {
|
||||||
destination += (uint32_t) data_data;
|
destination += (uint32_t) data_data.get();
|
||||||
destination -= 0x10000000;
|
destination -= 0x10000000;
|
||||||
destinations[psec->get_index()] = (uint8_t *) data_data;
|
destinations[psec->get_index()] = (uint8_t *) data_data.get();
|
||||||
} else if (address >= 0xC0000000) {
|
} else if (address >= 0xC0000000) {
|
||||||
destination += (uint32_t) data_data;
|
destination += (uint32_t) data_data.get();
|
||||||
destination -= 0xC0000000;
|
destination -= 0xC0000000;
|
||||||
//destinations[psec->get_index()] = (uint8_t *) data_data;
|
//destinations[psec->get_index()] = (uint8_t *) data_data;
|
||||||
//destinations[psec->get_index()] -= 0xC0000000;
|
//destinations[psec->get_index()] -= 0xC0000000;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Unhandled case");
|
DEBUG_FUNCTION_LINE_ERR("Unhandled case");
|
||||||
free(destinations);
|
|
||||||
MEMFreeToExpHeap(heapHandle, text_data);
|
|
||||||
MEMFreeToExpHeap(heapHandle, data_data);
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,8 +133,13 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
|||||||
memcpy((void *) destination, p, sectionSize);
|
memcpy((void *) destination, p, sectionSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sectionName(psec->get_name());
|
auto sectionInfo = make_unique_nothrow<SectionInfo>(psec->get_name(), destination, sectionSize);
|
||||||
pluginInfo->addSectionInfo(std::make_shared<SectionInfo>(sectionName, destination, sectionSize));
|
if (!sectionInfo) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to allocat SectionInfo");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginInfo->addSectionInfo(std::move(sectionInfo));
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Saved %s section info. Location: %08X size: %08X", psec->get_name().c_str(), destination, sectionSize);
|
DEBUG_FUNCTION_LINE_VERBOSE("Saved %s section info. Location: %08X size: %08X", psec->get_name().c_str(), destination, sectionSize);
|
||||||
|
|
||||||
totalSize += sectionSize;
|
totalSize += sectionSize;
|
||||||
@ -142,29 +153,23 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
|||||||
section *psec = reader.sections[i];
|
section *psec = reader.sections[i];
|
||||||
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
|
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Linking (%d)... %s at %08X", i, psec->get_name().c_str(), destinations[psec->get_index()]);
|
DEBUG_FUNCTION_LINE_VERBOSE("Linking (%d)... %s at %08X", i, psec->get_name().c_str(), destinations[psec->get_index()]);
|
||||||
|
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], (uint32_t) text_data.get(), (uint32_t) data_data.get(), trampoline_data, trampoline_data_length,
|
||||||
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], (uint32_t) text_data, (uint32_t) data_data, trampoline_data, trampoline_data_length,
|
|
||||||
trampolineId)) {
|
trampolineId)) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("elfLink failed");
|
DEBUG_FUNCTION_LINE_ERR("linkSection failed");
|
||||||
free(destinations);
|
return {};
|
||||||
MEMFreeToExpHeap(heapHandle, text_data);
|
|
||||||
MEMFreeToExpHeap(heapHandle, data_data);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto relocationData = getImportRelocationData(reader, destinations);
|
|
||||||
|
|
||||||
for (auto const &reloc : relocationData) {
|
|
||||||
pluginInfo->addRelocationData(reloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
DCFlushRange((void *) text_data, text_size);
|
if (!PluginInformationFactory::addImportRelocationData(pluginInfo, reader, destinations)) {
|
||||||
ICInvalidateRange((void *) text_data, text_size);
|
DEBUG_FUNCTION_LINE_ERR("addImportRelocationData failed");
|
||||||
DCFlushRange((void *) data_data, data_size);
|
return {};
|
||||||
ICInvalidateRange((void *) data_data, data_size);
|
}
|
||||||
|
|
||||||
free(destinations);
|
DCFlushRange((void *) text_data.get(), text_size);
|
||||||
|
ICInvalidateRange((void *) text_data.get(), text_size);
|
||||||
|
DCFlushRange((void *) data_data.get(), data_size);
|
||||||
|
ICInvalidateRange((void *) data_data.get(), data_size);
|
||||||
|
|
||||||
pluginInfo->setTrampolineId(trampolineId);
|
pluginInfo->setTrampolineId(trampolineId);
|
||||||
|
|
||||||
@ -175,9 +180,13 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
|||||||
if (entries != nullptr) {
|
if (entries != nullptr) {
|
||||||
for (size_t j = 0; j < entries_count; j++) {
|
for (size_t j = 0; j < entries_count; j++) {
|
||||||
wups_loader_hook_t *hook = &entries[j];
|
wups_loader_hook_t *hook = &entries[j];
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Saving hook of plugin Type: %08X, target: %08X" /*,pluginData->getPluginInformation()->getName().c_str()*/, hook->type, (void *) hook->target);
|
DEBUG_FUNCTION_LINE_VERBOSE("Saving hook of plugin Type: %08X, target: %08X", hook->type, (void *) hook->target);
|
||||||
auto hook_data = std::make_shared<HookData>((void *) hook->target, hook->type);
|
auto hookData = make_unique_nothrow<HookData>((void *) hook->target, hook->type);
|
||||||
pluginInfo->addHookData(hook_data);
|
if (!hookData) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to allocate HookData");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
pluginInfo->addHookData(std::move(hookData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,11 +202,19 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
|||||||
cur_function->_function.name /*,pluginData->getPluginInformation()->getName().c_str()*/,
|
cur_function->_function.name /*,pluginData->getPluginInformation()->getName().c_str()*/,
|
||||||
cur_function->_function.physical_address, cur_function->_function.virtual_address, cur_function->_function.library, cur_function->_function.target,
|
cur_function->_function.physical_address, cur_function->_function.virtual_address, cur_function->_function.library, cur_function->_function.target,
|
||||||
(void *) cur_function->_function.call_addr);
|
(void *) cur_function->_function.call_addr);
|
||||||
auto function_data = std::make_shared<FunctionData>((void *) cur_function->_function.physical_address, (void *) cur_function->_function.virtual_address, cur_function->_function.name,
|
|
||||||
|
auto functionData = make_unique_nothrow<FunctionData>((void *) cur_function->_function.physical_address,
|
||||||
|
(void *) cur_function->_function.virtual_address,
|
||||||
|
cur_function->_function.name,
|
||||||
(function_replacement_library_type_t) cur_function->_function.library,
|
(function_replacement_library_type_t) cur_function->_function.library,
|
||||||
(void *) cur_function->_function.target, (void *) cur_function->_function.call_addr,
|
(void *) cur_function->_function.target,
|
||||||
|
(void *) cur_function->_function.call_addr,
|
||||||
(FunctionPatcherTargetProcess) cur_function->_function.targetProcess);
|
(FunctionPatcherTargetProcess) cur_function->_function.targetProcess);
|
||||||
pluginInfo->addFunctionData(function_data);
|
if (!functionData) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to allocate FunctionData");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
pluginInfo->addFunctionData(std::move(functionData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,7 +246,12 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto finalAddress = offsetVal + sectionOpt.value()->getAddress();
|
auto finalAddress = offsetVal + sectionOpt.value()->getAddress();
|
||||||
pluginInfo->addFunctionSymbolData(std::make_shared<FunctionSymbolData>(name, (void *) finalAddress, (uint32_t) size));
|
auto functionSymbolData = make_unique_nothrow<FunctionSymbolData>(name, (void *) finalAddress, (uint32_t) size);
|
||||||
|
if (!functionSymbolData) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to allocate FunctionSymbolData");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
pluginInfo->addFunctionSymbolData(std::move(functionSymbolData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,24 +260,31 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (totalSize > text_size + data_size) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("We didn't allocate enough memory!!");
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
// Save the addresses for the allocated memory. This way we can free it again :)
|
// Save the addresses for the allocated memory. This way we can free it again :)
|
||||||
pluginInfo->allocatedDataMemoryAddress = data_data;
|
pluginInfo->allocatedDataMemoryAddress = std::move(data_data);
|
||||||
pluginInfo->allocatedTextMemoryAddress = text_data;
|
pluginInfo->allocatedTextMemoryAddress = std::move(text_data);
|
||||||
|
|
||||||
return pluginInfo;
|
return pluginInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<RelocationData>> PluginInformationFactory::getImportRelocationData(const elfio &reader, uint8_t **destinations) {
|
bool PluginInformationFactory::addImportRelocationData(const std::unique_ptr<PluginInformation> &pluginInfo, const elfio &reader, const std::unique_ptr<uint8_t *[]> &destinations) {
|
||||||
std::vector<std::shared_ptr<RelocationData>> result;
|
std::map<uint32_t, std::shared_ptr<ImportRPLInformation>> infoMap;
|
||||||
|
|
||||||
std::map<uint32_t, std::string> infoMap;
|
|
||||||
|
|
||||||
uint32_t sec_num = reader.sections.size();
|
uint32_t sec_num = reader.sections.size();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
section *psec = reader.sections[i];
|
auto *psec = reader.sections[i];
|
||||||
if (psec->get_type() == 0x80000002) {
|
if (psec->get_type() == 0x80000002) {
|
||||||
infoMap[i] = psec->get_name();
|
auto info = make_shared_nothrow<ImportRPLInformation>(psec->get_name());
|
||||||
|
if (!info) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
infoMap[i] = std::move(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +303,7 @@ std::vector<std::shared_ptr<RelocationData>> PluginInformationFactory::getImport
|
|||||||
|
|
||||||
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
|
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto adjusted_sym_value = (uint32_t) sym_value;
|
auto adjusted_sym_value = (uint32_t) sym_value;
|
||||||
@ -282,35 +311,28 @@ std::vector<std::shared_ptr<RelocationData>> PluginInformationFactory::getImport
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string fimport = ".fimport_";
|
|
||||||
std::string dimport = ".dimport_";
|
|
||||||
|
|
||||||
bool isData = false;
|
|
||||||
|
|
||||||
std::string rplName;
|
|
||||||
std::string rawSectionName = infoMap[sym_section_index];
|
|
||||||
|
|
||||||
if (rawSectionName.size() < fimport.size()) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Section name was shorter than expected, skipping this relocation");
|
|
||||||
continue;
|
|
||||||
} else if (std::equal(fimport.begin(), fimport.end(), rawSectionName.begin())) {
|
|
||||||
rplName = rawSectionName.substr(fimport.size());
|
|
||||||
} else if (std::equal(dimport.begin(), dimport.end(), rawSectionName.begin())) {
|
|
||||||
rplName = rawSectionName.substr(dimport.size());
|
|
||||||
isData = true;
|
|
||||||
} else {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("invalid section name");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rplInfo = std::make_shared<ImportRPLInformation>(rplName, isData);
|
|
||||||
|
|
||||||
uint32_t section_index = psec->get_info();
|
uint32_t section_index = psec->get_info();
|
||||||
result.push_back(std::make_shared<RelocationData>(type, offset - 0x02000000, addend, (void *) (destinations[section_index]), sym_name, rplInfo));
|
if (!infoMap.contains(sym_section_index)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Relocation is referencing a unknown section. %d destination: %08X sym_name %s", section_index, destinations[section_index], sym_name.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto relocationData = make_unique_nothrow<RelocationData>(type,
|
||||||
|
offset - 0x02000000,
|
||||||
|
addend,
|
||||||
|
(void *) (destinations[section_index]),
|
||||||
|
sym_name,
|
||||||
|
infoMap[sym_section_index]);
|
||||||
|
if (!relocationData) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to allocate RelocationData");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginInfo->addRelocationData(std::move(relocationData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PluginInformationFactory::linkSection(const elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
|
bool PluginInformationFactory::linkSection(const elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
|
||||||
@ -380,6 +402,5 @@ bool PluginInformationFactory::linkSection(const elfio &reader, uint32_t section
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to find relocation section");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -27,15 +27,17 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <wums/defines/relocation_defines.h>
|
#include <wums/defines/relocation_defines.h>
|
||||||
|
|
||||||
|
|
||||||
class PluginInformationFactory {
|
class PluginInformationFactory {
|
||||||
public:
|
public:
|
||||||
static std::optional<std::shared_ptr<PluginInformation>>
|
static std::optional<std::unique_ptr<PluginInformation>>
|
||||||
load(const std::shared_ptr<PluginData> &pluginData, MEMHeapHandle heaphandle, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length, uint8_t trampolineId);
|
load(const std::shared_ptr<PluginData> &pluginData, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
|
||||||
|
uint8_t trampolineId);
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
linkSection(const elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
|
linkSection(const ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
|
||||||
uint32_t trampoline_data_length,
|
uint32_t trampoline_data_length,
|
||||||
uint8_t trampolineId);
|
uint8_t trampolineId);
|
||||||
|
|
||||||
static std::vector<std::shared_ptr<RelocationData>> getImportRelocationData(const elfio &reader, uint8_t **destinations);
|
static bool addImportRelocationData(const std::unique_ptr<PluginInformation> &pluginInfo, const ELFIO::elfio &reader, const std::unique_ptr<uint8_t *[]> &destinations);
|
||||||
};
|
};
|
||||||
|
@ -59,36 +59,36 @@ public:
|
|||||||
private:
|
private:
|
||||||
PluginMetaInformation() = default;
|
PluginMetaInformation() = default;
|
||||||
|
|
||||||
void setName(const std::string &_name) {
|
void setName(std::string _name) {
|
||||||
this->name = _name;
|
this->name = std::move(_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAuthor(const std::string &_author) {
|
void setAuthor(std::string _author) {
|
||||||
this->author = _author;
|
this->author = std::move(_author);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setVersion(const std::string &_version) {
|
void setVersion(std::string _version) {
|
||||||
this->version = _version;
|
this->version = std::move(_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLicense(const std::string &_license) {
|
void setLicense(std::string _license) {
|
||||||
this->license = _license;
|
this->license = std::move(_license);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBuildTimestamp(const std::string &_buildtimestamp) {
|
void setBuildTimestamp(std::string _buildtimestamp) {
|
||||||
this->buildtimestamp = _buildtimestamp;
|
this->buildtimestamp = std::move(_buildtimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDescription(const std::string &_description) {
|
void setDescription(std::string _description) {
|
||||||
this->description = _description;
|
this->description = std::move(_description);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSize(size_t _size) {
|
void setSize(size_t _size) {
|
||||||
this->size = _size;
|
this->size = _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStorageId(const std::string &_storageId) {
|
void setStorageId(std::string _storageId) {
|
||||||
this->storageId = _storageId;
|
this->storageId = std::move(_storageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
@ -102,7 +102,5 @@ private:
|
|||||||
|
|
||||||
friend class PluginMetaInformationFactory;
|
friend class PluginMetaInformationFactory;
|
||||||
|
|
||||||
friend class PluginContainerPersistence;
|
|
||||||
|
|
||||||
friend class PluginContainer;
|
friend class PluginContainer;
|
||||||
};
|
};
|
||||||
|
@ -16,27 +16,25 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "PluginMetaInformationFactory.h"
|
#include "PluginMetaInformationFactory.h"
|
||||||
#include "../fs/FSUtils.h"
|
#include "elfio/elfio.hpp"
|
||||||
#include "../utils/StringTools.h"
|
#include "fs/FSUtils.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
using namespace ELFIO;
|
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const std::shared_ptr<PluginData> &pluginData) {
|
||||||
|
if (!pluginData->buffer) {
|
||||||
std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const std::shared_ptr<PluginData> &pluginData) {
|
DEBUG_FUNCTION_LINE_ERR("Buffer is empty");
|
||||||
if (pluginData->buffer == nullptr) {
|
return {};
|
||||||
DEBUG_FUNCTION_LINE_ERR("Buffer was nullptr");
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
}
|
||||||
elfio reader;
|
ELFIO::elfio reader;
|
||||||
if (!reader.load((char *) pluginData->buffer, pluginData->length)) {
|
if (!reader.load((char *) pluginData->buffer.get(), pluginData->length)) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
|
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return loadPlugin(reader);
|
return loadPlugin(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(std::string &filePath) {
|
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const std::string &filePath) {
|
||||||
elfio reader;
|
ELFIO::elfio reader;
|
||||||
|
|
||||||
uint8_t *buffer = nullptr;
|
uint8_t *buffer = nullptr;
|
||||||
uint32_t length = 0;
|
uint32_t length = 0;
|
||||||
@ -54,8 +52,8 @@ std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFacto
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(char *buffer, size_t size) {
|
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(char *buffer, size_t size) {
|
||||||
elfio reader;
|
ELFIO::elfio reader;
|
||||||
if (!reader.load(buffer, size)) {
|
if (!reader.load(buffer, size)) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Can't find or process ELF file");
|
DEBUG_FUNCTION_LINE_ERR("Can't find or process ELF file");
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@ -64,15 +62,15 @@ std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFacto
|
|||||||
return loadPlugin(reader);
|
return loadPlugin(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const elfio &reader) {
|
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const ELFIO::elfio &reader) {
|
||||||
size_t pluginSize = 0;
|
size_t pluginSize = 0;
|
||||||
|
|
||||||
auto pluginInfo = std::shared_ptr<PluginMetaInformation>(new PluginMetaInformation);
|
auto pluginInfo = std::unique_ptr<PluginMetaInformation>(new PluginMetaInformation);
|
||||||
|
|
||||||
uint32_t sec_num = reader.sections.size();
|
uint32_t sec_num = reader.sections.size();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
section *psec = reader.sections[i];
|
ELFIO::section *psec = reader.sections[i];
|
||||||
|
|
||||||
// Calculate total size:
|
// Calculate total size:
|
||||||
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
|
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
|
||||||
@ -118,7 +116,7 @@ std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFacto
|
|||||||
} else if (key == "storage_id") {
|
} else if (key == "storage_id") {
|
||||||
pluginInfo->setStorageId(value);
|
pluginInfo->setStorageId(value);
|
||||||
} else if (key == "wups") {
|
} else if (key == "wups") {
|
||||||
if (value != "0.7.0") {
|
if (value != "0.7.1") {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring plugin - Unsupported WUPS version: %s.", value.c_str());
|
DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring plugin - Unsupported WUPS version: %s.", value.c_str());
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "PluginData.h"
|
#include "PluginData.h"
|
||||||
#include "PluginMetaInformation.h"
|
#include "PluginMetaInformation.h"
|
||||||
|
#include "elfio/elfio.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -26,11 +27,11 @@
|
|||||||
|
|
||||||
class PluginMetaInformationFactory {
|
class PluginMetaInformationFactory {
|
||||||
public:
|
public:
|
||||||
static std::optional<std::shared_ptr<PluginMetaInformation>> loadPlugin(const std::shared_ptr<PluginData> &pluginData);
|
static std::optional<std::unique_ptr<PluginMetaInformation>> loadPlugin(const std::shared_ptr<PluginData> &pluginData);
|
||||||
|
|
||||||
static std::optional<std::shared_ptr<PluginMetaInformation>> loadPlugin(std::string &filePath);
|
static std::optional<std::unique_ptr<PluginMetaInformation>> loadPlugin(const std::string &filePath);
|
||||||
|
|
||||||
static std::optional<std::shared_ptr<PluginMetaInformation>> loadPlugin(char *buffer, size_t size);
|
static std::optional<std::unique_ptr<PluginMetaInformation>> loadPlugin(char *buffer, size_t size);
|
||||||
|
|
||||||
static std::optional<std::shared_ptr<PluginMetaInformation>> loadPlugin(const elfio &reader);
|
static std::optional<std::unique_ptr<PluginMetaInformation>> loadPlugin(const ELFIO::elfio &reader);
|
||||||
};
|
};
|
||||||
|
@ -25,11 +25,11 @@
|
|||||||
class RelocationData {
|
class RelocationData {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RelocationData(const char type, size_t offset, int32_t addend, void *destination, std::string &name, std::shared_ptr<ImportRPLInformation> rplInfo) : type(type),
|
RelocationData(const char type, size_t offset, int32_t addend, void *destination, std::string name, std::shared_ptr<ImportRPLInformation> rplInfo) : type(type),
|
||||||
offset(offset),
|
offset(offset),
|
||||||
addend(addend),
|
addend(addend),
|
||||||
destination(destination),
|
destination(destination),
|
||||||
name(name),
|
name(std::move(name)),
|
||||||
rplInfo(std::move(rplInfo)) {
|
rplInfo(std::move(rplInfo)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,18 +22,11 @@
|
|||||||
class SectionInfo {
|
class SectionInfo {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SectionInfo(std::string &name, uint32_t address, uint32_t sectionSize) : name(name),
|
SectionInfo(std::string name, uint32_t address, uint32_t sectionSize) : name(std::move(name)),
|
||||||
address(address),
|
address(address),
|
||||||
sectionSize(sectionSize) {
|
sectionSize(sectionSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionInfo() = default;
|
|
||||||
|
|
||||||
SectionInfo(const SectionInfo &o2) = default;
|
|
||||||
|
|
||||||
|
|
||||||
virtual ~SectionInfo() = default;
|
|
||||||
|
|
||||||
[[nodiscard]] const std::string &getName() const {
|
[[nodiscard]] const std::string &getName() const {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@ -46,6 +39,10 @@ public:
|
|||||||
return sectionSize;
|
return sectionSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] uint32_t isInSection(uint32_t addr) const {
|
||||||
|
return addr >= address && addr < address + sectionSize;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
uint32_t address{};
|
uint32_t address{};
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "../config/WUPSConfig.h"
|
#include "../config/WUPSConfig.h"
|
||||||
#include "../globals.h"
|
#include "../globals.h"
|
||||||
#include "DrawUtils.h"
|
#include "DrawUtils.h"
|
||||||
|
#include "hooks.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
#include <coreinit/screen.h>
|
#include <coreinit/screen.h>
|
||||||
@ -118,24 +119,20 @@ static uint32_t remapClassicButtons(uint32_t buttons) {
|
|||||||
|
|
||||||
void ConfigUtils::displayMenu() {
|
void ConfigUtils::displayMenu() {
|
||||||
std::vector<ConfigDisplayItem> configs;
|
std::vector<ConfigDisplayItem> configs;
|
||||||
for (int32_t plugin_index = 0; plugin_index < gPluginInformation->number_used_plugins; plugin_index++) {
|
for (auto &plugin : gLoadedPlugins) {
|
||||||
plugin_information_single_t *plugin_data = &gPluginInformation->plugin_data[plugin_index];
|
|
||||||
if (plugin_data == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ConfigDisplayItem cfg;
|
ConfigDisplayItem cfg;
|
||||||
cfg.name = std::string(plugin_data->meta.name);
|
cfg.name = plugin->metaInformation->getName();
|
||||||
cfg.author = std::string(plugin_data->meta.author);
|
cfg.author = plugin->metaInformation->getAuthor();
|
||||||
cfg.version = std::string(plugin_data->meta.version);
|
cfg.version = plugin->metaInformation->getVersion();
|
||||||
cfg.enabled = true;
|
cfg.enabled = true;
|
||||||
|
|
||||||
for (uint32_t j = 0; j < plugin_data->info.number_used_hooks; j++) {
|
for (auto &hook : plugin->getPluginInformation()->getHookDataList()) {
|
||||||
replacement_data_hook_t *hook_data = &plugin_data->info.hooks[j];
|
|
||||||
if (hook_data->type == WUPS_LOADER_HOOK_GET_CONFIG /*WUPS_LOADER_HOOK_GET_CONFIG*/) {
|
if (hook->getType() == WUPS_LOADER_HOOK_GET_CONFIG /*WUPS_LOADER_HOOK_GET_CONFIG*/) {
|
||||||
if (hook_data->func_pointer == nullptr) {
|
if (hook->getFunctionPointer() == nullptr) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
auto *cur_config = reinterpret_cast<WUPSConfig *>(((WUPSConfigHandle(*)())((uint32_t *) hook_data->func_pointer))());
|
auto *cur_config = reinterpret_cast<WUPSConfig *>(((WUPSConfigHandle(*)())((uint32_t *) hook->getFunctionPointer()))());
|
||||||
if (cur_config == nullptr) {
|
if (cur_config == nullptr) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -509,8 +506,7 @@ void ConfigUtils::displayMenu() {
|
|||||||
|
|
||||||
DrawUtils::setFontColor(COLOR_TEXT);
|
DrawUtils::setFontColor(COLOR_TEXT);
|
||||||
|
|
||||||
std::string headline;
|
auto headline = string_format("%s - %s", currentConfig->config->getName().c_str(), currentCategory->getName().c_str());
|
||||||
StringTools::strprintf(headline, "%s - %s", currentConfig->config->getName().c_str(), currentCategory->getName().c_str());
|
|
||||||
// draw top bar
|
// draw top bar
|
||||||
DrawUtils::setFontSize(24);
|
DrawUtils::setFontSize(24);
|
||||||
DrawUtils::print(16, 6 + 24, headline.c_str());
|
DrawUtils::print(16, 6 + 24, headline.c_str());
|
||||||
@ -553,25 +549,7 @@ void ConfigUtils::displayMenu() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int32_t plugin_index = 0; plugin_index < gPluginInformation->number_used_plugins; plugin_index++) {
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_CONFIG_CLOSED);
|
||||||
plugin_information_single_t *plugin_data = &gPluginInformation->plugin_data[plugin_index];
|
|
||||||
if (plugin_data == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t j = 0; j < plugin_data->info.number_used_hooks; j++) {
|
|
||||||
replacement_data_hook_t *hook_data = &plugin_data->info.hooks[j];
|
|
||||||
if (hook_data->type == WUPS_LOADER_HOOK_CONFIG_CLOSED) {
|
|
||||||
if (hook_data->func_pointer == nullptr) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// clang-format off
|
|
||||||
((void(*)())((uint32_t *) hook_data->func_pointer))();
|
|
||||||
// clang-format on
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &element : configs) {
|
for (const auto &element : configs) {
|
||||||
DEBUG_FUNCTION_LINE("Delete %08X", element.config);
|
DEBUG_FUNCTION_LINE("Delete %08X", element.config);
|
||||||
@ -594,15 +572,15 @@ void ConfigUtils::openConfigMenu() {
|
|||||||
|
|
||||||
if (!screenbuffer0 || !screenbuffer1) {
|
if (!screenbuffer0 || !screenbuffer1) {
|
||||||
if (screenbuffer0 == nullptr) {
|
if (screenbuffer0 == nullptr) {
|
||||||
if (storedTVBuffer.buffer_size >= screen_buf0_size) {
|
if (gStoredTVBuffer.buffer_size >= screen_buf0_size) {
|
||||||
screenbuffer0 = storedTVBuffer.buffer;
|
screenbuffer0 = gStoredTVBuffer.buffer;
|
||||||
skipScreen0Free = true;
|
skipScreen0Free = true;
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Use storedTVBuffer");
|
DEBUG_FUNCTION_LINE_VERBOSE("Use storedTVBuffer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (screenbuffer1 == nullptr) {
|
if (screenbuffer1 == nullptr) {
|
||||||
if (storedDRCBuffer.buffer_size >= screen_buf1_size) {
|
if (gStoredDRCBuffer.buffer_size >= screen_buf1_size) {
|
||||||
screenbuffer1 = storedDRCBuffer.buffer;
|
screenbuffer1 = gStoredDRCBuffer.buffer;
|
||||||
skipScreen1Free = true;
|
skipScreen1Free = true;
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Use storedDRCBuffer");
|
DEBUG_FUNCTION_LINE_VERBOSE("Use storedDRCBuffer");
|
||||||
}
|
}
|
||||||
@ -641,14 +619,14 @@ void ConfigUtils::openConfigMenu() {
|
|||||||
|
|
||||||
error_exit:
|
error_exit:
|
||||||
|
|
||||||
if (storedTVBuffer.buffer != nullptr) {
|
if (gStoredTVBuffer.buffer != nullptr) {
|
||||||
GX2SetTVBuffer(storedTVBuffer.buffer, storedTVBuffer.buffer_size, static_cast<GX2TVRenderMode>(storedTVBuffer.mode),
|
GX2SetTVBuffer(gStoredTVBuffer.buffer, gStoredTVBuffer.buffer_size, static_cast<GX2TVRenderMode>(gStoredTVBuffer.mode),
|
||||||
storedTVBuffer.surface_format, storedTVBuffer.buffering_mode);
|
gStoredTVBuffer.surface_format, gStoredTVBuffer.buffering_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (storedDRCBuffer.buffer != nullptr) {
|
if (gStoredDRCBuffer.buffer != nullptr) {
|
||||||
GX2SetDRCBuffer(storedDRCBuffer.buffer, storedDRCBuffer.buffer_size, static_cast<GX2DrcRenderMode>(storedDRCBuffer.mode),
|
GX2SetDRCBuffer(gStoredDRCBuffer.buffer, gStoredDRCBuffer.buffer_size, static_cast<GX2DrcRenderMode>(gStoredDRCBuffer.mode),
|
||||||
storedDRCBuffer.surface_format, storedDRCBuffer.buffering_mode);
|
gStoredDRCBuffer.surface_format, gStoredDRCBuffer.buffering_mode);
|
||||||
}
|
}
|
||||||
if (!skipScreen0Free && screenbuffer0) {
|
if (!skipScreen0Free && screenbuffer0) {
|
||||||
MEMFreeToMappedMemory(screenbuffer0);
|
MEMFreeToMappedMemory(screenbuffer0);
|
||||||
|
@ -1,157 +1,35 @@
|
|||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2010
|
* Copyright (C) 2010
|
||||||
* by Dimok
|
* by Dimok
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any
|
* warranty. In no event will the authors be held liable for any
|
||||||
* damages arising from the use of this software.
|
* damages arising from the use of this software.
|
||||||
*
|
*
|
||||||
* Permission is granted to anyone to use this software for any
|
* Permission is granted to anyone to use this software for any
|
||||||
* purpose, including commercial applications, and to alter it and
|
* purpose, including commercial applications, and to alter it and
|
||||||
* redistribute it freely, subject to the following restrictions:
|
* redistribute it freely, subject to the following restrictions:
|
||||||
*
|
*
|
||||||
* 1. The origin of this software must not be misrepresented; you
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
* must not claim that you wrote the original software. If you use
|
* must not claim that you wrote the original software. If you use
|
||||||
* this software in a product, an acknowledgment in the product
|
* this software in a product, an acknowledgment in the product
|
||||||
* documentation would be appreciated but is not required.
|
* documentation would be appreciated but is not required.
|
||||||
*
|
*
|
||||||
* 2. Altered source versions must be plainly marked as such, and
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
* must not be misrepresented as being the original software.
|
* must not be misrepresented as being the original software.
|
||||||
*
|
*
|
||||||
* 3. This notice may not be removed or altered from any source
|
* 3. This notice may not be removed or altered from any source
|
||||||
* distribution.
|
* distribution.
|
||||||
*
|
*
|
||||||
* for WiiXplorer 2010
|
* for WiiXplorer 2010
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include <cstdarg>
|
|
||||||
#include <cstdio>
|
#include <cstring>
|
||||||
#include <cstdlib>
|
|
||||||
#include <string.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <strings.h>
|
||||||
#include <utils/StringTools.h>
|
#include <utils/StringTools.h>
|
||||||
#include <vector>
|
|
||||||
#include <wut_types.h>
|
#include <wut_types.h>
|
||||||
|
|
||||||
|
|
||||||
BOOL StringTools::EndsWith(const std::string &a, const std::string &b) {
|
|
||||||
if (b.size() > a.size())
|
|
||||||
return false;
|
|
||||||
return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *StringTools::byte_to_binary(int32_t x) {
|
|
||||||
static char b[9];
|
|
||||||
b[0] = '\0';
|
|
||||||
|
|
||||||
int32_t z;
|
|
||||||
for (z = 128; z > 0; z >>= 1) {
|
|
||||||
strcat(b, ((x & z) == z) ? "1" : "0");
|
|
||||||
}
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string StringTools::removeCharFromString(std::string &input, char toBeRemoved) {
|
|
||||||
std::string output = input;
|
|
||||||
size_t position;
|
|
||||||
while (1) {
|
|
||||||
position = output.find(toBeRemoved);
|
|
||||||
if (position == std::string::npos)
|
|
||||||
break;
|
|
||||||
output.erase(position, 1);
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *StringTools::fmt(const char *format, ...) {
|
|
||||||
static char strChar[512];
|
|
||||||
strChar[0] = 0;
|
|
||||||
|
|
||||||
va_list va;
|
|
||||||
va_start(va, format);
|
|
||||||
if ((vsprintf(strChar, format, va) >= 0)) {
|
|
||||||
va_end(va);
|
|
||||||
return (const char *) strChar;
|
|
||||||
}
|
|
||||||
va_end(va);
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wchar_t *StringTools::wfmt(const char *format, ...) {
|
|
||||||
static char tmp[512];
|
|
||||||
static wchar_t strWChar[512];
|
|
||||||
strWChar[0] = 0;
|
|
||||||
tmp[0] = 0;
|
|
||||||
|
|
||||||
if (!format)
|
|
||||||
return (const wchar_t *) strWChar;
|
|
||||||
|
|
||||||
if (strcmp(format, "") == 0)
|
|
||||||
return (const wchar_t *) strWChar;
|
|
||||||
|
|
||||||
va_list va;
|
|
||||||
va_start(va, format);
|
|
||||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
|
||||||
int bt;
|
|
||||||
int32_t strlength = strlen(tmp);
|
|
||||||
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512);
|
|
||||||
|
|
||||||
if (bt > 0) {
|
|
||||||
strWChar[bt] = 0;
|
|
||||||
return (const wchar_t *) strWChar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
va_end(va);
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t StringTools::strprintf(std::string &str, const char *format, ...) {
|
|
||||||
static char tmp[512];
|
|
||||||
tmp[0] = 0;
|
|
||||||
int32_t result = 0;
|
|
||||||
|
|
||||||
va_list va;
|
|
||||||
va_start(va, format);
|
|
||||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
|
||||||
str = tmp;
|
|
||||||
result = str.size();
|
|
||||||
}
|
|
||||||
va_end(va);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string StringTools::strfmt(const char *format, ...) {
|
|
||||||
std::string str;
|
|
||||||
static char tmp[512];
|
|
||||||
tmp[0] = 0;
|
|
||||||
|
|
||||||
va_list va;
|
|
||||||
va_start(va, format);
|
|
||||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
|
||||||
str = tmp;
|
|
||||||
}
|
|
||||||
va_end(va);
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL StringTools::char2wchar_t(const char *strChar, wchar_t *dest) {
|
|
||||||
if (!strChar || !dest)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int bt;
|
|
||||||
bt = mbstowcs(dest, strChar, strlen(strChar));
|
|
||||||
if (bt > 0) {
|
|
||||||
dest[bt] = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
|
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
|
||||||
if (!string || !compare)
|
if (!string || !compare)
|
||||||
return -1;
|
return -1;
|
||||||
@ -171,38 +49,3 @@ int32_t StringTools::strtokcmp(const char *string, const char *compare, const ch
|
|||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t StringTools::strextcmp(const char *string, const char *extension, char seperator) {
|
|
||||||
if (!string || !extension)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
char *ptr = strrchr(string, seperator);
|
|
||||||
if (!ptr)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return strcasecmp(ptr + 1, extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::string> StringTools::stringSplit(const std::string &inValue, const std::string &splitter) {
|
|
||||||
std::string value = inValue;
|
|
||||||
std::vector<std::string> result;
|
|
||||||
while (true) {
|
|
||||||
uint32_t index = value.find(splitter);
|
|
||||||
if (index == std::string::npos) {
|
|
||||||
result.push_back(value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
std::string first = value.substr(0, index);
|
|
||||||
result.push_back(first);
|
|
||||||
if (index + splitter.size() == value.length()) {
|
|
||||||
result.push_back("");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (index + splitter.size() > value.length()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
value = value.substr(index + splitter.size(), value.length());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
@ -23,34 +23,35 @@
|
|||||||
*
|
*
|
||||||
* for WiiXplorer 2010
|
* for WiiXplorer 2010
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#ifndef __STRING_TOOLS_H
|
#pragma once
|
||||||
#define __STRING_TOOLS_H
|
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include <coreinit/debug.h>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <wut_types.h>
|
#include <wut_types.h>
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
std::string string_format(const std::string &format, Args... args) {
|
||||||
|
int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
|
||||||
|
auto size = static_cast<size_t>(size_s);
|
||||||
|
auto buf = make_unique_nothrow<char[]>(size);
|
||||||
|
if (!buf) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("string_format failed, not enough memory");
|
||||||
|
OSFatal("string_format failed, not enough memory");
|
||||||
|
return std::string("");
|
||||||
|
}
|
||||||
|
std::snprintf(buf.get(), size, format.c_str(), args...);
|
||||||
|
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class StringTools {
|
class StringTools {
|
||||||
public:
|
public:
|
||||||
static BOOL EndsWith(const std::string &a, const std::string &b);
|
|
||||||
|
|
||||||
static const char *byte_to_binary(int32_t x);
|
|
||||||
|
|
||||||
static std::string removeCharFromString(std::string &input, char toBeRemoved);
|
|
||||||
|
|
||||||
static const char *fmt(const char *format, ...);
|
|
||||||
|
|
||||||
static const wchar_t *wfmt(const char *format, ...);
|
|
||||||
|
|
||||||
static int32_t strprintf(std::string &str, const char *format, ...);
|
|
||||||
|
|
||||||
static std::string strfmt(const char *format, ...);
|
|
||||||
|
|
||||||
static BOOL char2wchar_t(const char *src, wchar_t *dest);
|
|
||||||
|
|
||||||
static int32_t strtokcmp(const char *string, const char *compare, const char *separator);
|
static int32_t strtokcmp(const char *string, const char *compare, const char *separator);
|
||||||
|
|
||||||
static int32_t strextcmp(const char *string, const char *extension, char seperator);
|
|
||||||
|
|
||||||
static const char *FullpathToFilename(const char *path) {
|
static const char *FullpathToFilename(const char *path) {
|
||||||
if (!path)
|
if (!path)
|
||||||
@ -81,8 +82,4 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::string> stringSplit(const std::string &value, const std::string &splitter);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __STRING_TOOLS_H */
|
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
#include "exports.h"
|
#include "exports.h"
|
||||||
#include "../PluginManagement.h"
|
#include "../PluginManagement.h"
|
||||||
#include "../globals.h"
|
#include "../globals.h"
|
||||||
#include "../plugin/PluginContainer.h"
|
|
||||||
#include "../plugin/PluginContainerPersistence.h"
|
|
||||||
#include "../plugin/PluginDataFactory.h"
|
#include "../plugin/PluginDataFactory.h"
|
||||||
#include "../plugin/PluginDataPersistence.h"
|
|
||||||
#include "../plugin/PluginMetaInformationFactory.h"
|
#include "../plugin/PluginMetaInformationFactory.h"
|
||||||
#include <coreinit/cache.h>
|
#include "utils.h"
|
||||||
#include <wums.h>
|
#include <wums.h>
|
||||||
|
|
||||||
static void fillPluginInformation(plugin_information *out, const std::shared_ptr<PluginMetaInformation> &metaInformation) {
|
static void fillPluginInformation(plugin_information *out, const std::unique_ptr<PluginMetaInformation> &metaInformation) {
|
||||||
out->plugin_information_version = PLUGIN_INFORMATION_VERSION;
|
out->plugin_information_version = PLUGIN_INFORMATION_VERSION;
|
||||||
strncpy(out->author, metaInformation->getAuthor().c_str(), sizeof(out->author) - 1);
|
strncpy(out->author, metaInformation->getAuthor().c_str(), sizeof(out->author) - 1);
|
||||||
strncpy(out->buildTimestamp, metaInformation->getBuildTimestamp().c_str(), sizeof(out->buildTimestamp) - 1);
|
strncpy(out->buildTimestamp, metaInformation->getBuildTimestamp().c_str(), sizeof(out->buildTimestamp) - 1);
|
||||||
@ -22,34 +19,27 @@ static void fillPluginInformation(plugin_information *out, const std::shared_ptr
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" PluginBackendApiErrorType WUPSLoadAndLinkByDataHandle(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size) {
|
extern "C" PluginBackendApiErrorType WUPSLoadAndLinkByDataHandle(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size) {
|
||||||
gLinkOnReload.number_used_plugins = 0;
|
if (plugin_data_handle_list == nullptr || plugin_data_handle_list_size == 0) {
|
||||||
if (plugin_data_handle_list != nullptr && plugin_data_handle_list_size != 0) {
|
|
||||||
for (uint32_t i = 0; i < plugin_data_handle_list_size; i++) {
|
|
||||||
plugin_data_handle handle = plugin_data_handle_list[i];
|
|
||||||
auto *pluginData = (PluginData *) handle;
|
|
||||||
PluginDataPersistence::save(&gLinkOnReload.plugin_data[gLinkOnReload.number_used_plugins], pluginData);
|
|
||||||
|
|
||||||
gLinkOnReload.number_used_plugins++;
|
|
||||||
}
|
|
||||||
if (gLinkOnReload.number_used_plugins > 0) {
|
|
||||||
gLinkOnReload.loadOnReload = true;
|
|
||||||
}
|
|
||||||
DCFlushRange(&gLinkOnReload, sizeof(gLinkOnReload));
|
|
||||||
} else {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_INVALID_ARG");
|
|
||||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
return PLUGIN_BACKEND_API_ERROR_NONE;
|
std::lock_guard<std::mutex> lock(gLoadedDataMutex);
|
||||||
}
|
for (uint32_t i = 0; i < plugin_data_handle_list_size; i++) {
|
||||||
|
auto handle = plugin_data_handle_list[i];
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
extern "C" PluginBackendApiErrorType WUPSDeletePluginContainer(const plugin_container_handle *handle_list, uint32_t handle_list_size) {
|
for (auto &pluginData : gLoadedData) {
|
||||||
if (handle_list != nullptr && handle_list_size != 0) {
|
if (pluginData->getHandle() == handle) {
|
||||||
for (uint32_t i = 0; i < handle_list_size; i++) {
|
gLoadOnNextLaunch.push_front(pluginData);
|
||||||
auto handle = handle_list[i];
|
found = true;
|
||||||
auto *pluginContainer = (PluginContainer *) handle;
|
break;
|
||||||
delete pluginContainer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!found) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to get plugin data for handle %08X. Skipping it.", handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return PLUGIN_BACKEND_API_ERROR_NONE;
|
return PLUGIN_BACKEND_API_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,21 +47,27 @@ extern "C" PluginBackendApiErrorType WUPSDeletePluginData(const plugin_data_hand
|
|||||||
if (plugin_data_handle_list != nullptr && plugin_data_handle_list_size != 0) {
|
if (plugin_data_handle_list != nullptr && plugin_data_handle_list_size != 0) {
|
||||||
for (uint32_t i = 0; i < plugin_data_handle_list_size; i++) {
|
for (uint32_t i = 0; i < plugin_data_handle_list_size; i++) {
|
||||||
auto handle = plugin_data_handle_list[i];
|
auto handle = plugin_data_handle_list[i];
|
||||||
auto *pluginData = (PluginData *) handle;
|
|
||||||
delete pluginData;
|
if (!remove_locked_first_if(gLoadedDataMutex, gLoadedData, [handle](auto &cur) { return cur->getHandle() == handle; })) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to delete plugin data by handle %08X", handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PLUGIN_BACKEND_API_ERROR_NONE;
|
return PLUGIN_BACKEND_API_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" PluginBackendApiErrorType WUPSLoadPluginAsData(GetPluginInformationInputType inputType, const char *path, char *buffer, size_t size, plugin_data_handle *out) {
|
extern "C" PluginBackendApiErrorType WUPSLoadPluginAsData(GetPluginInformationInputType inputType, const char *path, char *buffer, size_t size, plugin_data_handle *out) {
|
||||||
std::optional<std::shared_ptr<PluginData>> pluginData;
|
if (out == nullptr) {
|
||||||
|
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::unique_ptr<PluginData>> pluginData;
|
||||||
if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) {
|
if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) {
|
||||||
pluginData = PluginDataFactory::load(path, gPluginDataHeap);
|
pluginData = PluginDataFactory::load(path);
|
||||||
} else if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_BUFFER && buffer != nullptr && size > 0) {
|
} else if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_BUFFER && buffer != nullptr && size > 0) {
|
||||||
std::vector<uint8_t> data(size);
|
std::vector<uint8_t> data(size);
|
||||||
memcpy(&data[0], buffer, size);
|
memcpy(&data[0], buffer, size);
|
||||||
pluginData = PluginDataFactory::load(data, gPluginDataHeap);
|
pluginData = PluginDataFactory::load(data);
|
||||||
} else {
|
} else {
|
||||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
@ -81,12 +77,9 @@ extern "C" PluginBackendApiErrorType WUPSLoadPluginAsData(GetPluginInformationIn
|
|||||||
return PLUGIN_BACKEND_API_ERROR_FAILED_ALLOC;
|
return PLUGIN_BACKEND_API_ERROR_FAILED_ALLOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out == nullptr) {
|
else {
|
||||||
DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_INVALID_ARG");
|
*out = pluginData.value()->getHandle();
|
||||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
gLoadedData.push_front(std::move(pluginData.value()));
|
||||||
} else {
|
|
||||||
auto *pluginDataHandle = new PluginData(*pluginData.value());
|
|
||||||
*out = (uint32_t) pluginDataHandle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return PLUGIN_BACKEND_API_ERROR_NONE;
|
return PLUGIN_BACKEND_API_ERROR_NONE;
|
||||||
@ -101,7 +94,7 @@ extern "C" PluginBackendApiErrorType WUPSLoadPluginAsDataByBuffer(plugin_data_ha
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" PluginBackendApiErrorType WUPSGetPluginMetaInformation(GetPluginInformationInputType inputType, const char *path, char *buffer, size_t size, plugin_information *output) {
|
extern "C" PluginBackendApiErrorType WUPSGetPluginMetaInformation(GetPluginInformationInputType inputType, const char *path, char *buffer, size_t size, plugin_information *output) {
|
||||||
std::optional<std::shared_ptr<PluginMetaInformation>> pluginInfo;
|
std::optional<std::unique_ptr<PluginMetaInformation>> pluginInfo;
|
||||||
if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) {
|
if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) {
|
||||||
std::string pathStr(path);
|
std::string pathStr(path);
|
||||||
pluginInfo = PluginMetaInformationFactory::loadPlugin(pathStr);
|
pluginInfo = PluginMetaInformationFactory::loadPlugin(pathStr);
|
||||||
@ -136,17 +129,29 @@ extern "C" PluginBackendApiErrorType WUPSGetPluginMetaInformationByBuffer(plugin
|
|||||||
|
|
||||||
extern "C" PluginBackendApiErrorType WUPSGetPluginDataForContainerHandles(const plugin_container_handle *plugin_container_handle_list, plugin_data_handle *plugin_data_list, uint32_t buffer_size) {
|
extern "C" PluginBackendApiErrorType WUPSGetPluginDataForContainerHandles(const plugin_container_handle *plugin_container_handle_list, plugin_data_handle *plugin_data_list, uint32_t buffer_size) {
|
||||||
PluginBackendApiErrorType res = PLUGIN_BACKEND_API_ERROR_NONE;
|
PluginBackendApiErrorType res = PLUGIN_BACKEND_API_ERROR_NONE;
|
||||||
if (plugin_container_handle_list != nullptr && buffer_size != 0) {
|
if (plugin_container_handle_list == nullptr || buffer_size == 0) {
|
||||||
for (uint32_t i = 0; i < buffer_size; i++) {
|
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(gLoadedDataMutex);
|
||||||
|
for (uint32_t i = 0; i < buffer_size; /* only increase on success*/) {
|
||||||
auto handle = plugin_container_handle_list[i];
|
auto handle = plugin_container_handle_list[i];
|
||||||
auto *container = (PluginContainer *) handle;
|
bool found = false;
|
||||||
auto *pluginData = new PluginData(*container->getPluginData());
|
for (auto &curContainer : gLoadedPlugins) {
|
||||||
plugin_data_list[i] = (uint32_t) pluginData;
|
if (curContainer->getHandle() == handle) {
|
||||||
|
auto &pluginData = curContainer->getPluginData();
|
||||||
|
plugin_data_list[i] = (uint32_t) pluginData->getHandle();
|
||||||
|
gLoadedData.push_front(pluginData);
|
||||||
|
found = true;
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_INVALID_ARG");
|
|
||||||
res = PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
|
||||||
}
|
}
|
||||||
|
if (!found) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to get container for handle %08X", handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,17 +160,28 @@ extern "C" PluginBackendApiErrorType WUPSGetMetaInformation(const plugin_contain
|
|||||||
if (plugin_container_handle_list != nullptr && buffer_size != 0) {
|
if (plugin_container_handle_list != nullptr && buffer_size != 0) {
|
||||||
for (uint32_t i = 0; i < buffer_size; i++) {
|
for (uint32_t i = 0; i < buffer_size; i++) {
|
||||||
auto handle = plugin_container_handle_list[i];
|
auto handle = plugin_container_handle_list[i];
|
||||||
auto *container = (PluginContainer *) handle;
|
bool found = false;
|
||||||
|
for (auto &curContainer : gLoadedPlugins) {
|
||||||
|
if (curContainer->getHandle() == handle) {
|
||||||
|
auto &metaInfo = curContainer->getMetaInformation();
|
||||||
|
|
||||||
plugin_information_list[i].plugin_information_version = PLUGIN_INFORMATION_VERSION;
|
plugin_information_list[i].plugin_information_version = PLUGIN_INFORMATION_VERSION;
|
||||||
strncpy(plugin_information_list[i].storageId, container->metaInformation->getStorageId().c_str(), sizeof(plugin_information_list[i].storageId) - 1);
|
strncpy(plugin_information_list[i].storageId, metaInfo->getStorageId().c_str(), sizeof(plugin_information_list[i].storageId) - 1);
|
||||||
strncpy(plugin_information_list[i].author, container->metaInformation->getAuthor().c_str(), sizeof(plugin_information_list[i].author) - 1);
|
strncpy(plugin_information_list[i].author, metaInfo->getAuthor().c_str(), sizeof(plugin_information_list[i].author) - 1);
|
||||||
strncpy(plugin_information_list[i].buildTimestamp, container->metaInformation->getBuildTimestamp().c_str(), sizeof(plugin_information_list[i].buildTimestamp) - 1);
|
strncpy(plugin_information_list[i].buildTimestamp, metaInfo->getBuildTimestamp().c_str(), sizeof(plugin_information_list[i].buildTimestamp) - 1);
|
||||||
strncpy(plugin_information_list[i].description, container->metaInformation->getDescription().c_str(), sizeof(plugin_information_list[i].description) - 1);
|
strncpy(plugin_information_list[i].description, metaInfo->getDescription().c_str(), sizeof(plugin_information_list[i].description) - 1);
|
||||||
strncpy(plugin_information_list[i].name, container->metaInformation->getName().c_str(), sizeof(plugin_information_list[i].name) - 1);
|
strncpy(plugin_information_list[i].name, metaInfo->getName().c_str(), sizeof(plugin_information_list[i].name) - 1);
|
||||||
strncpy(plugin_information_list[i].license, container->metaInformation->getLicense().c_str(), sizeof(plugin_information_list[i].license) - 1);
|
strncpy(plugin_information_list[i].license, metaInfo->getLicense().c_str(), sizeof(plugin_information_list[i].license) - 1);
|
||||||
strncpy(plugin_information_list[i].version, container->metaInformation->getVersion().c_str(), sizeof(plugin_information_list[i].version) - 1);
|
strncpy(plugin_information_list[i].version, metaInfo->getVersion().c_str(), sizeof(plugin_information_list[i].version) - 1);
|
||||||
plugin_information_list[i].size = container->metaInformation->getSize();
|
plugin_information_list[i].size = metaInfo->getSize();
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("FAILED TO FIND CONTAINER FOR HANDLE %08X", handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_INVALID_ARG");
|
DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_INVALID_ARG");
|
||||||
@ -175,17 +191,15 @@ extern "C" PluginBackendApiErrorType WUPSGetMetaInformation(const plugin_contain
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" PluginBackendApiErrorType WUPSGetLoadedPlugins(plugin_container_handle *io_handles, uint32_t buffer_size, uint32_t *outSize, uint32_t *plugin_information_version) {
|
extern "C" PluginBackendApiErrorType WUPSGetLoadedPlugins(plugin_container_handle *io_handles, uint32_t buffer_size, uint32_t *outSize, uint32_t *plugin_information_version) {
|
||||||
DEBUG_FUNCTION_LINE();
|
|
||||||
if (plugin_information_version == nullptr) {
|
if (plugin_information_version == nullptr) {
|
||||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
*plugin_information_version = PLUGIN_INFORMATION_VERSION;
|
*plugin_information_version = PLUGIN_INFORMATION_VERSION;
|
||||||
auto plugins = PluginContainerPersistence::loadPlugins(gPluginInformation);
|
auto &plugins = gLoadedPlugins;
|
||||||
uint32_t counter = 0;
|
uint32_t counter = 0;
|
||||||
for (auto &plugin : plugins) {
|
for (auto &plugin : plugins) {
|
||||||
if (counter < buffer_size) {
|
if (counter < buffer_size) {
|
||||||
auto *container = new PluginContainer(*plugin);
|
io_handles[counter] = plugin->getHandle();
|
||||||
io_handles[counter] = (uint32_t) container;
|
|
||||||
counter++;
|
counter++;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -201,7 +215,6 @@ WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsDataByPath);
|
|||||||
WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsDataByBuffer);
|
WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsDataByBuffer);
|
||||||
WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsData);
|
WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsData);
|
||||||
WUMS_EXPORT_FUNCTION(WUPSLoadAndLinkByDataHandle);
|
WUMS_EXPORT_FUNCTION(WUPSLoadAndLinkByDataHandle);
|
||||||
WUMS_EXPORT_FUNCTION(WUPSDeletePluginContainer);
|
|
||||||
WUMS_EXPORT_FUNCTION(WUPSDeletePluginData);
|
WUMS_EXPORT_FUNCTION(WUPSDeletePluginData);
|
||||||
WUMS_EXPORT_FUNCTION(WUPSGetPluginMetaInformation);
|
WUMS_EXPORT_FUNCTION(WUPSGetPluginMetaInformation);
|
||||||
WUMS_EXPORT_FUNCTION(WUPSGetPluginMetaInformationByPath);
|
WUMS_EXPORT_FUNCTION(WUPSGetPluginMetaInformationByPath);
|
||||||
|
@ -17,7 +17,7 @@ std::string getPluginPath() {
|
|||||||
|
|
||||||
IOS_Close(handle);
|
IOS_Close(handle);
|
||||||
}
|
}
|
||||||
return std::string(environmentPath) + "/plugins";
|
return std::string(environmentPath).append("/plugins");
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://gist.github.com/ccbrown/9722406
|
// https://gist.github.com/ccbrown/9722406
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <forward_list>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <string>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -41,4 +44,33 @@ void dumpHex(const void *data, size_t size);
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template<class T, class... Args>
|
||||||
|
std::unique_ptr<T> make_unique_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
|
||||||
|
return std::unique_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline typename std::_MakeUniq<T>::__array make_unique_nothrow(size_t num) noexcept {
|
||||||
|
return std::unique_ptr<T>(new (std::nothrow) std::remove_extent_t<T>[num]());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class... Args>
|
||||||
|
std::shared_ptr<T> make_shared_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
|
||||||
|
return std::shared_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, class Allocator, class Predicate>
|
||||||
|
bool remove_locked_first_if(std::mutex &mutex, std::forward_list<T, Allocator> &list, Predicate pred) {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
auto oit = list.before_begin(), it = std::next(oit);
|
||||||
|
while (it != list.end()) {
|
||||||
|
if (pred(*it)) {
|
||||||
|
list.erase_after(oit);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
oit = it++;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::string getPluginPath();
|
std::string getPluginPath();
|
Loading…
Reference in New Issue
Block a user