mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2024-11-22 04:39:17 +01:00
- use const auto& where possible
- avoid using const std::unique_ptr& and const std::shared_ptr& - avoid wrapping results in std::optional - prefer std::string_view over const std::string& - update FSUtils::LoadFileToMem to write into std::vector<uint8_t> - use std::span when possible - Avoid unnessecary copies in PluginDataFactory - allocate plugins as HeapMemoryFixedSize which bascially is a std::unique_ptr with fixed size
This commit is contained in:
parent
baee1afda3
commit
cc5acd0980
@ -57,7 +57,7 @@ void NotificationMainLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
bool DisplayNotificationMessage(std::string &text, NotificationModuleNotificationType type, float duration) {
|
||||
bool DisplayNotificationMessage(std::string_view text, NotificationModuleNotificationType type, float duration) {
|
||||
if (!gNotificationModuleLoaded) {
|
||||
return false;
|
||||
}
|
||||
@ -68,7 +68,7 @@ bool DisplayNotificationMessage(std::string &text, NotificationModuleNotificatio
|
||||
if (!param) {
|
||||
return false;
|
||||
}
|
||||
strncpy(param->text, text.c_str(), sizeof(param->text) - 1);
|
||||
strncpy(param->text, text.data(), sizeof(param->text) - 1);
|
||||
param->type = type;
|
||||
param->duration = duration;
|
||||
|
||||
@ -84,11 +84,11 @@ bool DisplayNotificationMessage(std::string &text, NotificationModuleNotificatio
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DisplayInfoNotificationMessage(std::string &text, float duration) {
|
||||
bool DisplayInfoNotificationMessage(std::string_view text, float duration) {
|
||||
return DisplayNotificationMessage(text, NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, duration);
|
||||
}
|
||||
|
||||
bool DisplayErrorNotificationMessage(std::string &text, float duration) {
|
||||
bool DisplayErrorNotificationMessage(std::string_view text, float duration) {
|
||||
return DisplayNotificationMessage(text, NOTIFICATION_MODULE_NOTIFICATION_TYPE_ERROR, duration);
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ void StartNotificationThread() {
|
||||
|
||||
constexpr int32_t messageSize = sizeof(sNotificationMessages) / sizeof(sNotificationMessages[0]);
|
||||
OSInitMessageQueue(&sNotificationQueue, sNotificationMessages, messageSize);
|
||||
sNotificationsThread = std::make_unique<std::thread>(NotificationMainLoop);
|
||||
sNotificationsThread = make_unique_nothrow<std::thread>(NotificationMainLoop);
|
||||
}
|
||||
|
||||
void StopNotificationThread() {
|
||||
|
@ -6,6 +6,6 @@ void StartNotificationThread();
|
||||
|
||||
void StopNotificationThread();
|
||||
|
||||
bool DisplayInfoNotificationMessage(std::string &text, float duration);
|
||||
bool DisplayInfoNotificationMessage(std::string_view text, float duration);
|
||||
|
||||
bool DisplayErrorNotificationMessage(std::string &text, float duration);
|
||||
bool DisplayErrorNotificationMessage(std::string_view text, float duration);
|
@ -1,7 +1,6 @@
|
||||
#include "PluginManagement.h"
|
||||
#include "NotificationsUtils.h"
|
||||
#include "hooks.h"
|
||||
#include "patcher/hooks_patcher_static.h"
|
||||
#include "plugin/PluginContainer.h"
|
||||
#include "plugin/PluginInformationFactory.h"
|
||||
#include "plugin/PluginMetaInformationFactory.h"
|
||||
@ -10,19 +9,58 @@
|
||||
#include "utils/utils.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/dynload.h>
|
||||
#include <forward_list>
|
||||
#include <memory.h>
|
||||
#include <memory>
|
||||
#include <ranges>
|
||||
|
||||
std::vector<std::unique_ptr<PluginContainer>>
|
||||
PluginManagement::loadPlugins(const std::set<std::shared_ptr<PluginData>> &pluginDataList, std::vector<relocation_trampoline_entry_t> &trampolineData) {
|
||||
std::vector<std::unique_ptr<PluginContainer>> plugins;
|
||||
|
||||
uint32_t trampolineID = 0;
|
||||
for (const auto &pluginData : pluginDataList) {
|
||||
PluginParseErrors error = PLUGIN_PARSE_ERROR_UNKNOWN;
|
||||
|
||||
auto metaInfo = PluginMetaInformationFactory::loadPlugin(*pluginData, error);
|
||||
if (metaInfo && error == PLUGIN_PARSE_ERROR_NONE) {
|
||||
auto info = PluginInformationFactory::load(*pluginData, trampolineData, trampolineID++);
|
||||
if (!info) {
|
||||
auto errMsg = string_format("Failed to load plugin: %s", metaInfo->getName().c_str());
|
||||
DEBUG_FUNCTION_LINE_ERR("%s", errMsg.c_str());
|
||||
DisplayErrorNotificationMessage(errMsg, 15.0f);
|
||||
continue;
|
||||
}
|
||||
std::string nameCpy = metaInfo->getName();
|
||||
auto container = make_unique_nothrow<PluginContainer>(std::move(metaInfo), std::move(info), pluginData);
|
||||
if (!container) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to create PluginContainer, skipping %s", nameCpy.c_str());
|
||||
continue;
|
||||
}
|
||||
plugins.push_back(std::move(container));
|
||||
} else {
|
||||
auto errMsg = string_format("Failed to load plugin: %s", pluginData->getSource().c_str());
|
||||
if (error == PLUGIN_PARSE_ERROR_INCOMPATIBLE_VERSION) {
|
||||
errMsg += ". Incompatible version.";
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("%s", errMsg.c_str());
|
||||
DisplayErrorNotificationMessage(errMsg, 15.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (!PluginManagement::DoFunctionPatches(plugins)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to patch functions");
|
||||
OSFatal("Failed to patch functions");
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
bool PluginManagement::doRelocation(const std::vector<std::unique_ptr<RelocationData>> &relocData,
|
||||
relocation_trampoline_entry_t *tramp_data,
|
||||
uint32_t tramp_length,
|
||||
std::vector<relocation_trampoline_entry_t> &trampData,
|
||||
uint32_t trampolineID,
|
||||
std::map<std::string, OSDynLoad_Module> &usedRPls) {
|
||||
for (auto const &cur : relocData) {
|
||||
uint32_t functionAddress = 0;
|
||||
const std::string &functionName = cur->getName();
|
||||
uint32_t functionAddress = 0;
|
||||
auto &functionName = cur->getName();
|
||||
|
||||
if (functionName == "MEMAllocFromDefaultHeap") {
|
||||
OSDynLoad_Module rplHandle;
|
||||
@ -39,8 +77,8 @@ bool PluginManagement::doRelocation(const std::vector<std::unique_ptr<Relocation
|
||||
}
|
||||
|
||||
if (functionAddress == 0) {
|
||||
auto rplName = cur->getImportRPLInformation()->getRPLName();
|
||||
int32_t isData = cur->getImportRPLInformation()->isData();
|
||||
auto rplName = cur->getImportRPLInformation().getRPLName();
|
||||
int32_t isData = cur->getImportRPLInformation().isData();
|
||||
OSDynLoad_Module rplHandle = nullptr;
|
||||
|
||||
if (!usedRPls.contains(rplName)) {
|
||||
@ -68,7 +106,7 @@ bool PluginManagement::doRelocation(const std::vector<std::unique_ptr<Relocation
|
||||
//DEBUG_FUNCTION_LINE("Found export for %s %s", rplName.c_str(), functionName.c_str());
|
||||
}
|
||||
|
||||
if (!ElfUtils::elfLinkOne(cur->getType(), cur->getOffset(), cur->getAddend(), (uint32_t) cur->getDestination(), functionAddress, tramp_data, tramp_length, RELOC_TYPE_IMPORT, trampolineID)) {
|
||||
if (!ElfUtils::elfLinkOne(cur->getType(), cur->getOffset(), cur->getAddend(), (uint32_t) cur->getDestination(), functionAddress, trampData, RELOC_TYPE_IMPORT, trampolineID)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("elfLinkOne failed");
|
||||
return false;
|
||||
}
|
||||
@ -83,18 +121,18 @@ bool PluginManagement::doRelocation(const std::vector<std::unique_ptr<Relocation
|
||||
}
|
||||
} */
|
||||
|
||||
DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
|
||||
ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
|
||||
DCFlushRange((void *) trampData.data(), trampData.size() * sizeof(relocation_trampoline_entry_t));
|
||||
ICInvalidateRange((void *) trampData.data(), trampData.size() * sizeof(relocation_trampoline_entry_t));
|
||||
OSMemoryBarrier();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PluginManagement::doRelocations(const std::vector<std::unique_ptr<PluginContainer>> &plugins,
|
||||
relocation_trampoline_entry_t *trampData, uint32_t tramp_size,
|
||||
std::vector<relocation_trampoline_entry_t> &trampData,
|
||||
std::map<std::string, OSDynLoad_Module> &usedRPls) {
|
||||
for (uint32_t i = 0; i < tramp_size; i++) {
|
||||
if (trampData[i].status == RELOC_TRAMP_IMPORT_DONE) {
|
||||
trampData[i].status = RELOC_TRAMP_FREE;
|
||||
for (auto &cur : trampData) {
|
||||
if (cur.status == RELOC_TRAMP_IMPORT_DONE) {
|
||||
cur.status = RELOC_TRAMP_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,12 +142,11 @@ bool PluginManagement::doRelocations(const std::vector<std::unique_ptr<PluginCon
|
||||
OSDynLoad_GetAllocator(&prevDynLoadAlloc, &prevDynLoadFree);
|
||||
OSDynLoad_SetAllocator(CustomDynLoadAlloc, CustomDynLoadFree);
|
||||
|
||||
for (auto &pluginContainer : plugins) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Doing relocations for plugin: %s", pluginContainer->getMetaInformation()->getName().c_str());
|
||||
if (!PluginManagement::doRelocation(pluginContainer->getPluginInformation()->getRelocationDataList(),
|
||||
for (const auto &pluginContainer : plugins) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Doing relocations for plugin: %s", pluginContainer->getMetaInformation().getName().c_str());
|
||||
if (!PluginManagement::doRelocation(pluginContainer->getPluginInformation().getRelocationDataList(),
|
||||
trampData,
|
||||
tramp_size,
|
||||
pluginContainer->getPluginInformation()->getTrampolineId(),
|
||||
pluginContainer->getPluginInformation().getTrampolineId(),
|
||||
usedRPls)) {
|
||||
return false;
|
||||
}
|
||||
@ -122,7 +159,7 @@ bool PluginManagement::doRelocations(const std::vector<std::unique_ptr<PluginCon
|
||||
|
||||
bool PluginManagement::RestoreFunctionPatches(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
|
||||
for (const auto &cur : std::ranges::reverse_view(plugins)) {
|
||||
for (const auto &curFunction : std::ranges::reverse_view(cur->getPluginInformation()->getFunctionDataList())) {
|
||||
for (const auto &curFunction : std::ranges::reverse_view(cur->getPluginInformation().getFunctionDataList())) {
|
||||
if (!curFunction->RemovePatch()) {
|
||||
return false;
|
||||
}
|
||||
@ -133,8 +170,9 @@ bool PluginManagement::RestoreFunctionPatches(const std::vector<std::unique_ptr<
|
||||
|
||||
bool PluginManagement::DoFunctionPatches(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
|
||||
for (const auto &cur : plugins) {
|
||||
for (const auto &curFunction : cur->getPluginInformation()->getFunctionDataList()) {
|
||||
for (const auto &curFunction : cur->getPluginInformation().getFunctionDataList()) {
|
||||
if (!curFunction->AddPatch()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to add function patch for: plugin %s", cur->getMetaInformation().getName().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -146,45 +184,4 @@ void PluginManagement::callInitHooks(const std::vector<std::unique_ptr<PluginCon
|
||||
CallHook(plugins, WUPS_LOADER_HOOK_INIT_STORAGE);
|
||||
CallHook(plugins, WUPS_LOADER_HOOK_INIT_PLUGIN);
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Done calling init hooks");
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<PluginContainer>>
|
||||
PluginManagement::loadPlugins(const std::forward_list<std::shared_ptr<PluginData>> &pluginList, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length) {
|
||||
std::vector<std::unique_ptr<PluginContainer>> plugins;
|
||||
|
||||
uint32_t trampolineID = 0;
|
||||
for (auto &pluginData : pluginList) {
|
||||
PluginParseErrors error = PLUGIN_PARSE_ERROR_UNKNOWN;
|
||||
|
||||
auto metaInfo = PluginMetaInformationFactory::loadPlugin(pluginData, error);
|
||||
if (metaInfo && error == PLUGIN_PARSE_ERROR_NONE) {
|
||||
auto info = PluginInformationFactory::load(pluginData, trampoline_data, trampoline_data_length, trampolineID++);
|
||||
if (!info) {
|
||||
auto errMsg = string_format("Failed to load plugin: %s", metaInfo.value()->getName().c_str());
|
||||
DEBUG_FUNCTION_LINE_ERR("%s", errMsg.c_str());
|
||||
DisplayErrorNotificationMessage(errMsg, 15.0f);
|
||||
continue;
|
||||
}
|
||||
auto container = make_unique_nothrow<PluginContainer>(std::move(metaInfo.value()), std::move(info.value()), pluginData);
|
||||
if (!container) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to create PluginContainer, skipping %s", metaInfo.value()->getName().c_str());
|
||||
continue;
|
||||
}
|
||||
plugins.push_back(std::move(container));
|
||||
} else {
|
||||
auto errMsg = string_format("Failed to load plugin: %s", pluginData->mSource.c_str());
|
||||
if (error == PLUGIN_PARSE_ERROR_INCOMPATIBLE_VERSION) {
|
||||
errMsg += ". Incompatible version.";
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("%s", errMsg.c_str());
|
||||
DisplayErrorNotificationMessage(errMsg, 15.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (!PluginManagement::DoFunctionPatches(plugins)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to patch functions");
|
||||
OSFatal("Failed to patch functions");
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
@ -2,25 +2,25 @@
|
||||
|
||||
#include "plugin/PluginContainer.h"
|
||||
#include <coreinit/dynload.h>
|
||||
#include <forward_list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <wums/defines/relocation_defines.h>
|
||||
|
||||
class PluginManagement {
|
||||
public:
|
||||
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 std::vector<std::unique_ptr<PluginContainer>> loadPlugins(
|
||||
const std::set<std::shared_ptr<PluginData>> &pluginDataList,
|
||||
std::vector<relocation_trampoline_entry_t> &trampolineData);
|
||||
|
||||
static void callInitHooks(const std::vector<std::unique_ptr<PluginContainer>> &plugins);
|
||||
|
||||
static bool doRelocations(const std::vector<std::unique_ptr<PluginContainer>> &plugins,
|
||||
relocation_trampoline_entry_t *trampData,
|
||||
uint32_t tramp_size,
|
||||
std::vector<relocation_trampoline_entry_t> &trampData,
|
||||
std::map<std::string, OSDynLoad_Module> &usedRPls);
|
||||
|
||||
static bool doRelocation(const std::vector<std::unique_ptr<RelocationData>> &relocData,
|
||||
relocation_trampoline_entry_t *tramp_data,
|
||||
uint32_t tramp_length,
|
||||
std::vector<relocation_trampoline_entry_t> &trampData,
|
||||
uint32_t trampolineID,
|
||||
std::map<std::string, OSDynLoad_Module> &usedRPls);
|
||||
|
||||
|
@ -26,12 +26,12 @@
|
||||
|
||||
class WUPSConfig {
|
||||
public:
|
||||
explicit WUPSConfig(const std::string &name) {
|
||||
explicit WUPSConfig(std::string_view name) {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
~WUPSConfig() {
|
||||
for (auto &element : categories) {
|
||||
for (const auto &element : categories) {
|
||||
delete element;
|
||||
}
|
||||
}
|
||||
@ -52,7 +52,7 @@ public:
|
||||
|
||||
\return On success, the created and inserted category will be returned.
|
||||
**/
|
||||
std::optional<WUPSConfigCategory *> addCategory(const std::string &categoryName) {
|
||||
std::optional<WUPSConfigCategory *> addCategory(std::string_view categoryName) {
|
||||
auto curCat = new (std::nothrow) WUPSConfigCategory(categoryName);
|
||||
if (curCat == nullptr) {
|
||||
return {};
|
||||
|
@ -24,12 +24,12 @@
|
||||
|
||||
class WUPSConfigCategory {
|
||||
public:
|
||||
explicit WUPSConfigCategory(const std::string &name) {
|
||||
explicit WUPSConfigCategory(std::string_view name) {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
~WUPSConfigCategory() {
|
||||
for (auto &element : items) {
|
||||
for (const auto &element : items) {
|
||||
delete element;
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
Sets the display name of this WUPSConfigItem
|
||||
This is the value which will be shown in the configuration menu.
|
||||
**/
|
||||
virtual void setDisplayName(const std::string &_displayName) {
|
||||
virtual void setDisplayName(std::string_view _displayName) {
|
||||
this->displayName = _displayName;
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ public:
|
||||
to be unique in the context of this WUPSConfig.
|
||||
Items in different categories are NOT allowed to have the config ID.
|
||||
**/
|
||||
virtual void setConfigID(const std::string &_configID) {
|
||||
virtual void setConfigID(std::string_view _configID) {
|
||||
this->configID = _configID;
|
||||
}
|
||||
|
||||
@ -162,7 +162,7 @@ public:
|
||||
return defaultValue != getCurrentValueDisplay();
|
||||
}
|
||||
|
||||
WUPSConfigItem(const std::string &_configID, const std::string &_displayName, WUPSConfigCallbacks_t callbacks, void *_context) {
|
||||
WUPSConfigItem(std::string_view _configID, std::string_view _displayName, WUPSConfigCallbacks_t callbacks, void *_context) {
|
||||
this->configID = _configID;
|
||||
this->displayName = _displayName;
|
||||
this->context = _context;
|
||||
|
@ -1,26 +1,23 @@
|
||||
#include "fs/FSUtils.h"
|
||||
#include "fs/CFile.hpp"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/utils.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <malloc.h>
|
||||
#include <filesystem>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) {
|
||||
//! always initialze input
|
||||
*inbuffer = NULL;
|
||||
if (size) {
|
||||
*size = 0;
|
||||
}
|
||||
int32_t FSUtils::LoadFileToMem(std::string_view filepath, std::vector<uint8_t> &buffer) {
|
||||
//! always initialize input
|
||||
buffer.clear();
|
||||
|
||||
int32_t iFd = open(filepath, O_RDONLY);
|
||||
int32_t iFd = open(filepath.data(), O_RDONLY);
|
||||
if (iFd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct stat file_stat;
|
||||
struct stat file_stat {};
|
||||
int rc = fstat(iFd, &file_stat);
|
||||
if (rc < 0) {
|
||||
close(iFd);
|
||||
@ -28,11 +25,7 @@ int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_
|
||||
}
|
||||
uint32_t filesize = file_stat.st_size;
|
||||
|
||||
auto *buffer = (uint8_t *) memalign(0x40, ROUNDUP(filesize, 0x40));
|
||||
if (buffer == nullptr) {
|
||||
close(iFd);
|
||||
return -2;
|
||||
}
|
||||
buffer.resize(filesize);
|
||||
|
||||
uint32_t blocksize = 0x80000;
|
||||
uint32_t done = 0;
|
||||
@ -42,7 +35,7 @@ int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_
|
||||
if (done + blocksize > filesize) {
|
||||
blocksize = filesize - done;
|
||||
}
|
||||
readBytes = read(iFd, buffer + done, blocksize);
|
||||
readBytes = read(iFd, buffer.data() + done, blocksize);
|
||||
if (readBytes <= 0) {
|
||||
break;
|
||||
}
|
||||
@ -52,99 +45,17 @@ int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_
|
||||
::close(iFd);
|
||||
|
||||
if (done != filesize) {
|
||||
free(buffer);
|
||||
buffer = nullptr;
|
||||
buffer.clear();
|
||||
return -3;
|
||||
}
|
||||
|
||||
*inbuffer = buffer;
|
||||
|
||||
//! sign is optional input
|
||||
if (size) {
|
||||
*size = filesize;
|
||||
}
|
||||
|
||||
return filesize;
|
||||
}
|
||||
|
||||
int32_t FSUtils::CheckFile(const char *filepath) {
|
||||
if (!filepath)
|
||||
return 0;
|
||||
|
||||
struct stat filestat;
|
||||
|
||||
char dirnoslash[strlen(filepath) + 2];
|
||||
snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath);
|
||||
|
||||
while (dirnoslash[strlen(dirnoslash) - 1] == '/')
|
||||
dirnoslash[strlen(dirnoslash) - 1] = '\0';
|
||||
|
||||
char *notRoot = strrchr(dirnoslash, '/');
|
||||
if (!notRoot) {
|
||||
strcat(dirnoslash, "/");
|
||||
}
|
||||
|
||||
if (stat(dirnoslash, &filestat) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t FSUtils::CreateSubfolder(const char *fullpath) {
|
||||
if (!fullpath)
|
||||
return 0;
|
||||
|
||||
int32_t result = 0;
|
||||
|
||||
char dirnoslash[strlen(fullpath) + 1];
|
||||
strcpy(dirnoslash, fullpath);
|
||||
|
||||
int32_t pos = strlen(dirnoslash) - 1;
|
||||
while (dirnoslash[pos] == '/') {
|
||||
dirnoslash[pos] = '\0';
|
||||
pos--;
|
||||
bool FSUtils::CreateSubfolder(std::string_view fullpath) {
|
||||
std::error_code err;
|
||||
if (!std::filesystem::create_directories(fullpath, err)) {
|
||||
return std::filesystem::exists(fullpath, err);
|
||||
}
|
||||
|
||||
if (CheckFile(dirnoslash)) {
|
||||
return 1;
|
||||
} else {
|
||||
char parentpath[strlen(dirnoslash) + 2];
|
||||
strcpy(parentpath, dirnoslash);
|
||||
char *ptr = strrchr(parentpath, '/');
|
||||
|
||||
if (!ptr) {
|
||||
//!Device root directory (must be with '/')
|
||||
strcat(parentpath, "/");
|
||||
struct stat filestat;
|
||||
if (stat(parentpath, &filestat) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
ptr[0] = '\0';
|
||||
|
||||
result = CreateSubfolder(parentpath);
|
||||
}
|
||||
|
||||
if (!result)
|
||||
return 0;
|
||||
|
||||
if (mkdir(dirnoslash, 0777) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t FSUtils::saveBufferToFile(const char *path, void *buffer, uint32_t size) {
|
||||
CFile file(path, CFile::WriteOnly);
|
||||
if (!file.isOpen()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to open %s\n", path);
|
||||
return 0;
|
||||
}
|
||||
int32_t written = file.write((const uint8_t *) buffer, size);
|
||||
file.close();
|
||||
return written;
|
||||
return true;
|
||||
}
|
||||
|
@ -1,18 +1,12 @@
|
||||
#ifndef __FS_UTILS_H_
|
||||
#define __FS_UTILS_H_
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wut_types.h>
|
||||
|
||||
class FSUtils {
|
||||
public:
|
||||
static int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size);
|
||||
static int32_t LoadFileToMem(std::string_view filepath, std::vector<uint8_t> &buffer);
|
||||
|
||||
//! todo: C++ class
|
||||
static int32_t CreateSubfolder(const char *fullpath);
|
||||
|
||||
static int32_t CheckFile(const char *filepath);
|
||||
|
||||
static int32_t saveBufferToFile(const char *path, void *buffer, uint32_t size);
|
||||
static bool CreateSubfolder(std::string_view fullpath);
|
||||
};
|
||||
|
||||
#endif // __FS_UTILS_H_
|
||||
|
@ -4,10 +4,10 @@ StoredBuffer gStoredTVBuffer __attribute__((section(".data"))) = {};
|
||||
StoredBuffer gStoredDRCBuffer __attribute__((section(".data"))) = {};
|
||||
|
||||
std::vector<std::unique_ptr<PluginContainer>> gLoadedPlugins __attribute__((section(".data")));
|
||||
relocation_trampoline_entry_t *gTrampData __attribute__((section(".data"))) = nullptr;
|
||||
std::vector<relocation_trampoline_entry_t> gTrampData __attribute__((section(".data")));
|
||||
|
||||
std::forward_list<std::shared_ptr<PluginData>> gLoadedData __attribute__((section(".data")));
|
||||
std::forward_list<std::shared_ptr<PluginData>> gLoadOnNextLaunch __attribute__((section(".data")));
|
||||
std::set<std::shared_ptr<PluginData>> gLoadedData __attribute__((section(".data")));
|
||||
std::set<std::shared_ptr<PluginData>> gLoadOnNextLaunch __attribute__((section(".data")));
|
||||
std::mutex gLoadedDataMutex __attribute__((section(".data")));
|
||||
std::map<std::string, OSDynLoad_Module> gUsedRPLs __attribute__((section(".data")));
|
||||
std::vector<void *> gAllocatedAddresses __attribute__((section(".data")));
|
||||
|
@ -16,11 +16,11 @@ extern StoredBuffer gStoredTVBuffer;
|
||||
extern StoredBuffer gStoredDRCBuffer;
|
||||
|
||||
#define TRAMP_DATA_SIZE 1024
|
||||
extern relocation_trampoline_entry_t *gTrampData;
|
||||
extern std::vector<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::set<std::shared_ptr<PluginData>> gLoadedData;
|
||||
extern std::set<std::shared_ptr<PluginData>> gLoadOnNextLaunch;
|
||||
extern std::mutex gLoadedDataMutex;
|
||||
extern std::map<std::string, OSDynLoad_Module> gUsedRPLs;
|
||||
extern std::vector<void *> gAllocatedAddresses;
|
||||
|
@ -33,15 +33,15 @@ static const char **hook_names = (const char *[]){
|
||||
|
||||
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);
|
||||
for (auto &plugin : plugins) {
|
||||
CallHook(plugin, hook_type);
|
||||
for (const auto &plugin : plugins) {
|
||||
CallHook(*plugin, hook_type);
|
||||
}
|
||||
}
|
||||
|
||||
void CallHook(const std::unique_ptr<PluginContainer> &plugin, wups_loader_hook_type_t hook_type) {
|
||||
for (const auto &hook : plugin->getPluginInformation()->getHookDataList()) {
|
||||
void CallHook(const PluginContainer &plugin, wups_loader_hook_type_t hook_type) {
|
||||
for (const auto &hook : plugin.getPluginInformation().getHookDataList()) {
|
||||
if (hook->getType() == hook_type) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s for plugin %s [%d]", hook_names[hook->getType()], plugin->metaInformation->getName().c_str(), hook_type);
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s for plugin %s [%d]", hook_names[hook->getType()], plugin.getMetaInformation().getName().c_str(), hook_type);
|
||||
void *func_ptr = hook->getFunctionPointer();
|
||||
if (func_ptr != nullptr) {
|
||||
switch (hook_type) {
|
||||
@ -74,7 +74,7 @@ void CallHook(const std::unique_ptr<PluginContainer> &plugin, wups_loader_hook_t
|
||||
wups_loader_init_storage_args_t args;
|
||||
args.open_storage_ptr = &StorageUtils::OpenStorage;
|
||||
args.close_storage_ptr = &StorageUtils::CloseStorage;
|
||||
args.plugin_id = plugin->getMetaInformation()->getStorageId().c_str();
|
||||
args.plugin_id = plugin.getMetaInformation().getStorageId().c_str();
|
||||
// clang-format off
|
||||
((void(*)(wups_loader_init_storage_args_t))((uint32_t *) func_ptr))(args);
|
||||
// clang-format on
|
||||
|
@ -7,4 +7,4 @@
|
||||
|
||||
void CallHook(const std::vector<std::unique_ptr<PluginContainer>> &plugins, wups_loader_hook_type_t hook_type);
|
||||
|
||||
void CallHook(const std::unique_ptr<PluginContainer> &plugin, wups_loader_hook_type_t hook_type);
|
||||
void CallHook(const PluginContainer &plugin, wups_loader_hook_type_t hook_type);
|
@ -26,7 +26,7 @@ WUMS_INITIALIZE() {
|
||||
|
||||
NotificationModuleStatus res;
|
||||
if ((res = NotificationModule_InitLibrary()) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to init NotificationModule");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to init NotificationModule: %s (%d)", NotificationModule_GetStatusStr(res), res);
|
||||
gNotificationModuleLoaded = false;
|
||||
} else {
|
||||
gNotificationModuleLoaded = true;
|
||||
@ -38,6 +38,7 @@ WUMS_INITIALIZE() {
|
||||
OSFatal("homebrew_wupsbackend: Failed to AddPatch function");
|
||||
}
|
||||
}
|
||||
|
||||
deinitLogging();
|
||||
}
|
||||
|
||||
@ -59,7 +60,7 @@ WUMS_APPLICATION_ENDS() {
|
||||
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_FINI_WUT_SOCKETS);
|
||||
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_FINI_WUT_DEVOPTAB);
|
||||
|
||||
for (auto &pair : gUsedRPLs) {
|
||||
for (const auto &pair : gUsedRPLs) {
|
||||
OSDynLoad_Release(pair.second);
|
||||
}
|
||||
gUsedRPLs.clear();
|
||||
@ -85,7 +86,7 @@ WUMS_APPLICATION_STARTS() {
|
||||
|
||||
// If an allocated rpl was not released properly (e.g. if something else calls OSDynload_Acquire without releasing it) memory get leaked.
|
||||
// Let's clean this up!
|
||||
for (auto &addr : gAllocatedAddresses) {
|
||||
for (const auto &addr : gAllocatedAddresses) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Memory allocated by OSDynload was not freed properly, let's clean it up! (%08X)", addr);
|
||||
free((void *) addr);
|
||||
}
|
||||
@ -96,13 +97,11 @@ WUMS_APPLICATION_STARTS() {
|
||||
|
||||
std::lock_guard<std::mutex> lock(gLoadedDataMutex);
|
||||
|
||||
if (gTrampData == nullptr) {
|
||||
gTrampData = (relocation_trampoline_entry_t *) memalign(0x4, sizeof(relocation_trampoline_entry_t) * TRAMP_DATA_SIZE);
|
||||
if (gTrampData == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocated the memory for the trampoline data");
|
||||
OSFatal("Failed to allocated the memory for the trampoline data");
|
||||
if (gTrampData.empty()) {
|
||||
gTrampData = std::vector<relocation_trampoline_entry_t>(TRAMP_DATA_SIZE);
|
||||
for (auto &cur : gTrampData) {
|
||||
cur.status = RELOC_TRAMP_FREE;
|
||||
}
|
||||
memset(gTrampData, 0, sizeof(relocation_trampoline_entry_t) * TRAMP_DATA_SIZE);
|
||||
}
|
||||
|
||||
if (gLoadedPlugins.empty()) {
|
||||
@ -111,7 +110,7 @@ WUMS_APPLICATION_STARTS() {
|
||||
DEBUG_FUNCTION_LINE("Load plugins from %s", pluginPath.c_str());
|
||||
|
||||
auto pluginData = PluginDataFactory::loadDir(pluginPath);
|
||||
gLoadedPlugins = PluginManagement::loadPlugins(pluginData, gTrampData, TRAMP_DATA_SIZE);
|
||||
gLoadedPlugins = PluginManagement::loadPlugins(pluginData, gTrampData);
|
||||
|
||||
initNeeded = true;
|
||||
}
|
||||
@ -138,10 +137,12 @@ WUMS_APPLICATION_STARTS() {
|
||||
PluginManagement::RestoreFunctionPatches(gLoadedPlugins);
|
||||
DEBUG_FUNCTION_LINE("Unload existing plugins.");
|
||||
gLoadedPlugins.clear();
|
||||
memset(gTrampData, 0, sizeof(relocation_trampoline_entry_t) * TRAMP_DATA_SIZE);
|
||||
for (auto &cur : gTrampData) {
|
||||
cur.status = RELOC_TRAMP_FREE;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Load new plugins");
|
||||
gLoadedPlugins = PluginManagement::loadPlugins(gLoadOnNextLaunch, gTrampData, TRAMP_DATA_SIZE);
|
||||
gLoadedPlugins = PluginManagement::loadPlugins(gLoadOnNextLaunch, gTrampData);
|
||||
initNeeded = true;
|
||||
}
|
||||
|
||||
@ -150,9 +151,9 @@ WUMS_APPLICATION_STARTS() {
|
||||
gLoadedData.clear();
|
||||
|
||||
if (!gLoadedPlugins.empty()) {
|
||||
if (!PluginManagement::doRelocations(gLoadedPlugins, gTrampData, TRAMP_DATA_SIZE, gUsedRPLs)) {
|
||||
if (!PluginManagement::doRelocations(gLoadedPlugins, gTrampData, gUsedRPLs)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Relocations failed");
|
||||
OSFatal("Relocations failed");
|
||||
OSFatal("WiiUPluginLoaderBackend: Relocations failed.\n See crash logs for more information.");
|
||||
}
|
||||
// PluginManagement::memsetBSS(plugins);
|
||||
|
||||
@ -179,13 +180,13 @@ WUMS_APPLICATION_STARTS() {
|
||||
void CheckCleanupCallbackUsage(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
|
||||
auto *curThread = OSGetCurrentThread();
|
||||
for (const auto &cur : plugins) {
|
||||
auto textSection = cur->getPluginInformation()->getSectionInfo(".text");
|
||||
if (!textSection.has_value()) {
|
||||
auto textSection = cur->getPluginInformation().getSectionInfo(".text");
|
||||
if (!textSection) {
|
||||
continue;
|
||||
}
|
||||
uint32_t startAddress = textSection.value()->getAddress();
|
||||
uint32_t endAddress = textSection.value()->getAddress() + textSection.value()->getSize();
|
||||
auto *pluginName = cur->getMetaInformation()->getName().c_str();
|
||||
uint32_t startAddress = textSection->getAddress();
|
||||
uint32_t endAddress = textSection->getAddress() + textSection->getSize();
|
||||
auto *pluginName = cur->getMetaInformation().getName().c_str();
|
||||
{
|
||||
__OSLockScheduler(curThread);
|
||||
int state = OSDisableInterrupts();
|
||||
|
@ -120,24 +120,20 @@ DECL_FUNCTION(uint32_t, SC17_FindClosestSymbol,
|
||||
uint32_t symbolNameBufferLength,
|
||||
char *moduleNameBuffer,
|
||||
uint32_t moduleNameBufferLength) {
|
||||
for (auto &plugin : gLoadedPlugins) {
|
||||
auto sectionInfoOpt = plugin->getPluginInformation()->getSectionInfo(".text");
|
||||
if (!sectionInfoOpt) {
|
||||
for (const auto &plugin : gLoadedPlugins) {
|
||||
auto sectionInfo = plugin->getPluginInformation().getSectionInfo(".text");
|
||||
if (!sectionInfo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto §ionInfo = sectionInfoOpt.value();
|
||||
|
||||
if (!sectionInfo->isInSection(addr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
strncpy(moduleNameBuffer, plugin->getMetaInformation().getName().c_str(), moduleNameBufferLength - 1);
|
||||
auto functionSymbolData = plugin->getPluginInformation().getNearestFunctionSymbolData(addr);
|
||||
if (functionSymbolData) {
|
||||
strncpy(symbolNameBuffer, functionSymbolData->getName().c_str(), moduleNameBufferLength - 1);
|
||||
if (outDistance) {
|
||||
*outDistance = addr - (uint32_t) functionSymbolData->getAddress();
|
||||
}
|
||||
@ -157,28 +153,25 @@ DECL_FUNCTION(uint32_t, SC17_FindClosestSymbol,
|
||||
}
|
||||
|
||||
DECL_FUNCTION(uint32_t, KiGetAppSymbolName, uint32_t addr, char *buffer, int32_t bufSize) {
|
||||
for (auto &plugin : gLoadedPlugins) {
|
||||
auto sectionInfoOpt = plugin->getPluginInformation()->getSectionInfo(".text");
|
||||
if (!sectionInfoOpt) {
|
||||
for (const auto &plugin : gLoadedPlugins) {
|
||||
auto sectionInfo = plugin->getPluginInformation().getSectionInfo(".text");
|
||||
if (!sectionInfo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto §ionInfo = sectionInfoOpt.value();
|
||||
|
||||
if (!sectionInfo->isInSection(addr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto pluginNameLen = strlen(plugin->getMetaInformation()->getName().c_str());
|
||||
auto pluginNameLen = strlen(plugin->getMetaInformation().getName().c_str());
|
||||
int32_t spaceLeftInBuffer = (int32_t) bufSize - (int32_t) pluginNameLen - 1;
|
||||
if (spaceLeftInBuffer < 0) {
|
||||
spaceLeftInBuffer = 0;
|
||||
}
|
||||
strncpy(buffer, plugin->getMetaInformation()->getName().c_str(), bufSize - 1);
|
||||
strncpy(buffer, plugin->getMetaInformation().getName().c_str(), bufSize - 1);
|
||||
|
||||
auto functionSymbolDataOpt = plugin->getPluginInformation()->getNearestFunctionSymbolData(addr);
|
||||
if (functionSymbolDataOpt) {
|
||||
auto &functionSymbolData = functionSymbolDataOpt.value();
|
||||
auto functionSymbolData = plugin->getPluginInformation().getNearestFunctionSymbolData(addr);
|
||||
if (functionSymbolData) {
|
||||
buffer[pluginNameLen] = '|';
|
||||
buffer[pluginNameLen + 1] = '\0';
|
||||
strncpy(buffer + pluginNameLen + 1, functionSymbolData->getName().c_str(), spaceLeftInBuffer - 1);
|
||||
|
@ -24,18 +24,23 @@
|
||||
class FunctionData {
|
||||
|
||||
public:
|
||||
FunctionData(void *paddress, void *vaddress, std::string name, function_replacement_library_type_t library, void *replaceAddr, void *replaceCall,
|
||||
FunctionData(void *paddress, void *vaddress, std::string_view name, function_replacement_library_type_t library, void *replaceAddr, void *replaceCall,
|
||||
FunctionPatcherTargetProcess targetProcess) {
|
||||
this->paddress = paddress;
|
||||
this->vaddress = vaddress;
|
||||
this->name = std::move(name);
|
||||
this->name = name;
|
||||
this->library = library;
|
||||
this->targetProcess = targetProcess;
|
||||
this->replaceAddr = replaceAddr;
|
||||
this->replaceCall = replaceCall;
|
||||
}
|
||||
|
||||
~FunctionData() = default;
|
||||
~FunctionData() {
|
||||
if (handle != 0) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Destroying FunctionData while it was still patched. This should never happen.");
|
||||
RemovePatch();
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return this->name;
|
||||
@ -81,7 +86,7 @@ public:
|
||||
}};
|
||||
|
||||
if (FunctionPatcher_AddFunctionPatch(&functionData, &handle, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to add patch for function");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to add patch for function (\"%s\" PA:%08X VA:%08X)", this->name.c_str(), this->paddress, this->vaddress);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -24,31 +24,31 @@ class FunctionSymbolData {
|
||||
public:
|
||||
FunctionSymbolData(const FunctionSymbolData &o2) = default;
|
||||
|
||||
FunctionSymbolData(std::string &name, void *address, uint32_t size) : name(name),
|
||||
address(address),
|
||||
size(size) {
|
||||
FunctionSymbolData(std::string_view name, void *address, uint32_t size) : mName(name),
|
||||
mAddress(address),
|
||||
mSize(size) {
|
||||
}
|
||||
|
||||
bool operator<(const FunctionSymbolData &rhs) const {
|
||||
return (uint32_t) address < (uint32_t) rhs.address;
|
||||
return (uint32_t) mAddress < (uint32_t) rhs.mAddress;
|
||||
}
|
||||
|
||||
virtual ~FunctionSymbolData() = default;
|
||||
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return name;
|
||||
return mName;
|
||||
}
|
||||
|
||||
[[nodiscard]] void *getAddress() const {
|
||||
return address;
|
||||
return mAddress;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t getSize() const {
|
||||
return size;
|
||||
return mSize;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
void *address;
|
||||
uint32_t size;
|
||||
std::string mName;
|
||||
void *mAddress;
|
||||
uint32_t mSize;
|
||||
};
|
@ -24,24 +24,24 @@
|
||||
class ImportRPLInformation {
|
||||
|
||||
public:
|
||||
explicit ImportRPLInformation(std::string name) {
|
||||
this->name = std::move(name);
|
||||
explicit ImportRPLInformation(std::string_view name) {
|
||||
this->mName = name;
|
||||
}
|
||||
|
||||
~ImportRPLInformation() = default;
|
||||
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return name;
|
||||
return mName;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getRPLName() const {
|
||||
return name.substr(strlen(".dimport_"));
|
||||
return mName.substr(strlen(".dimport_"));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isData() const {
|
||||
return name.starts_with(".dimport_");
|
||||
return mName.starts_with(".dimport_");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::string mName;
|
||||
};
|
||||
|
@ -26,28 +26,29 @@
|
||||
class PluginContainer {
|
||||
public:
|
||||
PluginContainer(std::unique_ptr<PluginMetaInformation> metaInformation, std::unique_ptr<PluginInformation> pluginInformation, std::shared_ptr<PluginData> pluginData)
|
||||
: metaInformation(std::move(metaInformation)),
|
||||
pluginInformation(std::move(pluginInformation)),
|
||||
pluginData(std::move(pluginData)) {
|
||||
: mMetaInformation(std::move(metaInformation)),
|
||||
mPluginInformation(std::move(pluginInformation)),
|
||||
mPluginData(std::move(pluginData)) {
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::unique_ptr<PluginMetaInformation> &getMetaInformation() const {
|
||||
return this->metaInformation;
|
||||
[[nodiscard]] const PluginMetaInformation &getMetaInformation() const {
|
||||
return *this->mMetaInformation;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::unique_ptr<PluginInformation> &getPluginInformation() const {
|
||||
return pluginInformation;
|
||||
[[nodiscard]] const PluginInformation &getPluginInformation() const {
|
||||
return *this->mPluginInformation;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::shared_ptr<PluginData> &getPluginData() const {
|
||||
return pluginData;
|
||||
[[nodiscard]] std::shared_ptr<PluginData> getPluginDataCopy() const {
|
||||
return mPluginData;
|
||||
}
|
||||
|
||||
uint32_t getHandle() {
|
||||
return (uint32_t) this;
|
||||
}
|
||||
|
||||
const std::unique_ptr<PluginMetaInformation> metaInformation;
|
||||
const std::unique_ptr<PluginInformation> pluginInformation;
|
||||
const std::shared_ptr<PluginData> pluginData;
|
||||
private:
|
||||
const std::unique_ptr<PluginMetaInformation> mMetaInformation;
|
||||
const std::unique_ptr<PluginInformation> mPluginInformation;
|
||||
const std::shared_ptr<PluginData> mPluginData;
|
||||
};
|
||||
|
@ -1,15 +0,0 @@
|
||||
#include "PluginData.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
PluginData::PluginData(const std::vector<uint8_t> &input, std::string source) : length(input.size()), mSource(std::move(source)) {
|
||||
auto data_copy = make_unique_nothrow<uint8_t[]>(length);
|
||||
if (!data_copy) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate space on default heap");
|
||||
this->length = 0;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb on default heap", length / 1024);
|
||||
memcpy(data_copy.get(), &input[0], length);
|
||||
this->buffer = std::move(data_copy);
|
||||
}
|
||||
}
|
@ -21,17 +21,31 @@
|
||||
#include <malloc.h>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class PluginData {
|
||||
public:
|
||||
explicit PluginData(const std::vector<uint8_t> &buffer, std::string source);
|
||||
explicit PluginData(std::vector<uint8_t> &&buffer, std::string_view source) : mBuffer(std::move(buffer)), mSource(source) {
|
||||
}
|
||||
|
||||
uint32_t getHandle() {
|
||||
explicit PluginData(std::span<uint8_t> buffer, std::string_view source) : mBuffer(buffer.begin(), buffer.end()), mSource(source) {
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t getHandle() const {
|
||||
return (uint32_t) this;
|
||||
}
|
||||
|
||||
size_t length = 0;
|
||||
std::unique_ptr<uint8_t[]> buffer;
|
||||
[[nodiscard]] std::span<uint8_t const> getBuffer() const {
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string &getSource() const {
|
||||
return mSource;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> mBuffer;
|
||||
std::string mSource;
|
||||
};
|
||||
|
@ -23,10 +23,9 @@
|
||||
#include <dirent.h>
|
||||
#include <forward_list>
|
||||
#include <memory>
|
||||
#include <sys/stat.h>
|
||||
|
||||
std::forward_list<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const std::string &path) {
|
||||
std::forward_list<std::shared_ptr<PluginData>> result;
|
||||
std::set<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(std::string_view path) {
|
||||
std::set<std::shared_ptr<PluginData>> result;
|
||||
struct dirent *dp;
|
||||
DIR *dfd;
|
||||
|
||||
@ -35,8 +34,8 @@ std::forward_list<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((dfd = opendir(path.c_str())) == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Couldn't open dir %s", path.c_str());
|
||||
if ((dfd = opendir(path.data())) == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Couldn't open dir %s", path.data());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -45,15 +44,15 @@ std::forward_list<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const
|
||||
continue;
|
||||
}
|
||||
if (std::string_view(dp->d_name).starts_with('.') || std::string_view(dp->d_name).starts_with('_') || !std::string_view(dp->d_name).ends_with(".wps")) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Skip file %s/%s", path.c_str(), dp->d_name);
|
||||
DEBUG_FUNCTION_LINE_WARN("Skip file %s/%s", path.data(), dp->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto full_file_path = string_format("%s/%s", path.c_str(), dp->d_name);
|
||||
auto full_file_path = string_format("%s/%s", path.data(), dp->d_name);
|
||||
DEBUG_FUNCTION_LINE("Loading plugin: %s", full_file_path.c_str());
|
||||
auto pluginData = load(full_file_path);
|
||||
if (pluginData) {
|
||||
result.push_front(std::move(pluginData.value()));
|
||||
result.insert(std::move(pluginData));
|
||||
} else {
|
||||
auto errMsg = string_format("Failed to load plugin: %s", full_file_path.c_str());
|
||||
DEBUG_FUNCTION_LINE_ERR("%s", errMsg.c_str());
|
||||
@ -66,33 +65,21 @@ std::forward_list<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<std::unique_ptr<PluginData>> PluginDataFactory::load(const std::string &filename) {
|
||||
uint8_t *buffer = nullptr;
|
||||
uint32_t fsize = 0;
|
||||
if (FSUtils::LoadFileToMem(filename.c_str(), &buffer, &fsize) < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load %s into memory", filename.c_str());
|
||||
return {};
|
||||
std::unique_ptr<PluginData> PluginDataFactory::load(std::string_view filename) {
|
||||
std::vector<uint8_t> buffer;
|
||||
if (FSUtils::LoadFileToMem(filename, buffer) < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load %s into memory", filename.data());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> result;
|
||||
result.resize(fsize);
|
||||
memcpy(&result[0], buffer, fsize);
|
||||
free(buffer);
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Loaded file!");
|
||||
|
||||
return load(result, filename);
|
||||
return load(std::move(buffer), filename);
|
||||
}
|
||||
|
||||
std::optional<std::unique_ptr<PluginData>> PluginDataFactory::load(const std::vector<uint8_t> &buffer, const std::string &source) {
|
||||
std::unique_ptr<PluginData> PluginDataFactory::load(std::vector<uint8_t> &&buffer, std::string_view source) {
|
||||
if (buffer.empty()) {
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto res = make_unique_nothrow<PluginData>(buffer, source);
|
||||
if (!res) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return res;
|
||||
return make_unique_nothrow<PluginData>(std::move(buffer), source);
|
||||
}
|
||||
|
@ -22,14 +22,15 @@
|
||||
#include <forward_list>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class PluginDataFactory {
|
||||
public:
|
||||
static std::forward_list<std::shared_ptr<PluginData>> loadDir(const std::string &path);
|
||||
static std::set<std::shared_ptr<PluginData>> loadDir(std::string_view path);
|
||||
|
||||
static std::optional<std::unique_ptr<PluginData>> load(const std::string &path);
|
||||
static std::unique_ptr<PluginData> load(std::string_view path);
|
||||
|
||||
static std::optional<std::unique_ptr<PluginData>> load(const std::vector<uint8_t> &buffer, const std::string &source);
|
||||
static std::unique_ptr<PluginData> load(std::vector<uint8_t> &&buffer, std::string_view source);
|
||||
};
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "PluginMetaInformation.h"
|
||||
#include "RelocationData.h"
|
||||
#include "SectionInfo.h"
|
||||
#include "utils/HeapMemoryFixedSize.h"
|
||||
#include "utils/utils.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
@ -32,109 +34,101 @@
|
||||
#include <vector>
|
||||
|
||||
struct FunctionSymbolDataComparator {
|
||||
bool operator()(const std::shared_ptr<FunctionSymbolData> &lhs,
|
||||
const std::shared_ptr<FunctionSymbolData> &rhs) const {
|
||||
return (uint32_t) lhs->getAddress() < (uint32_t) rhs->getAddress();
|
||||
bool operator()(const std::unique_ptr<FunctionSymbolData> &lhs,
|
||||
const std::unique_ptr<FunctionSymbolData> &rhs) const {
|
||||
return *lhs < *rhs;
|
||||
}
|
||||
};
|
||||
|
||||
class PluginInformation {
|
||||
public:
|
||||
void addHookData(std::unique_ptr<HookData> hook_data) {
|
||||
hook_data_list.push_back(std::move(hook_data));
|
||||
mHookDataList.push_back(std::move(hook_data));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<HookData>> &getHookDataList() const {
|
||||
return hook_data_list;
|
||||
return mHookDataList;
|
||||
}
|
||||
|
||||
void addFunctionData(std::unique_ptr<FunctionData> function_data) {
|
||||
function_data_list.push_back(std::move(function_data));
|
||||
mFunctionDataList.push_back(std::move(function_data));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<FunctionData>> &getFunctionDataList() const {
|
||||
return function_data_list;
|
||||
return mFunctionDataList;
|
||||
}
|
||||
|
||||
void addRelocationData(std::unique_ptr<RelocationData> relocation_data) {
|
||||
relocation_data_list.push_back(std::move(relocation_data));
|
||||
mRelocationDataList.push_back(std::move(relocation_data));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<RelocationData>> &getRelocationDataList() const {
|
||||
return relocation_data_list;
|
||||
return mRelocationDataList;
|
||||
}
|
||||
|
||||
|
||||
void addFunctionSymbolData(std::shared_ptr<FunctionSymbolData> symbol_data) {
|
||||
symbol_data_list.insert(std::move(symbol_data));
|
||||
void addFunctionSymbolData(std::unique_ptr<FunctionSymbolData> symbol_data) {
|
||||
mSymbolDataList.insert(std::move(symbol_data));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> &getFunctionSymbolDataList() const {
|
||||
return symbol_data_list;
|
||||
void addSectionInfo(std::unique_ptr<SectionInfo> sectionInfo) {
|
||||
mSectionInfoList[sectionInfo->getName()] = std::move(sectionInfo);
|
||||
}
|
||||
|
||||
void addSectionInfo(std::shared_ptr<SectionInfo> sectionInfo) {
|
||||
section_info_list[sectionInfo->getName()] = std::move(sectionInfo);
|
||||
[[nodiscard]] const std::map<std::string, std::unique_ptr<SectionInfo>> &getSectionInfoList() const {
|
||||
return mSectionInfoList;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::map<std::string, std::shared_ptr<SectionInfo>> &getSectionInfoList() const {
|
||||
return section_info_list;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<std::shared_ptr<SectionInfo>> getSectionInfo(const std::string §ionName) const {
|
||||
[[nodiscard]] SectionInfo *getSectionInfo(const std::string §ionName) const {
|
||||
if (getSectionInfoList().contains(sectionName)) {
|
||||
return section_info_list.at(sectionName);
|
||||
return mSectionInfoList.at(sectionName).get();
|
||||
}
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void setTrampolineId(uint8_t _trampolineId) {
|
||||
this->trampolineId = _trampolineId;
|
||||
void setTrampolineId(uint8_t trampolineId) {
|
||||
this->mTrampolineId = trampolineId;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint8_t getTrampolineId() const {
|
||||
return trampolineId;
|
||||
return mTrampolineId;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<std::shared_ptr<FunctionSymbolData>> getNearestFunctionSymbolData(uint32_t address) const {
|
||||
std::shared_ptr<FunctionSymbolData> result;
|
||||
[[nodiscard]] FunctionSymbolData *getNearestFunctionSymbolData(uint32_t address) const {
|
||||
FunctionSymbolData *result = nullptr;
|
||||
|
||||
bool foundHit = false;
|
||||
for (auto &cur : symbol_data_list) {
|
||||
for (auto &cur : mSymbolDataList) {
|
||||
if (foundHit && address < (uint32_t) cur->getAddress()) {
|
||||
break;
|
||||
}
|
||||
if (address >= (uint32_t) cur->getAddress()) {
|
||||
result = cur;
|
||||
result = cur.get();
|
||||
foundHit = true;
|
||||
}
|
||||
}
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return {};
|
||||
return result;
|
||||
}
|
||||
|
||||
void *getTextMemoryAddress() {
|
||||
return allocatedTextMemoryAddress.get();
|
||||
[[nodiscard]] const HeapMemoryFixedSize &getTextMemory() const {
|
||||
return mAllocatedTextMemoryAddress;
|
||||
}
|
||||
|
||||
void *getDataMemoryAddress() {
|
||||
return allocatedDataMemoryAddress.get();
|
||||
[[nodiscard]] const HeapMemoryFixedSize &getDataMemory() const {
|
||||
return mAllocatedDataMemoryAddress;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<HookData>> hook_data_list;
|
||||
std::vector<std::unique_ptr<FunctionData>> function_data_list;
|
||||
std::vector<std::unique_ptr<RelocationData>> relocation_data_list;
|
||||
std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> symbol_data_list;
|
||||
std::map<std::string, std::shared_ptr<SectionInfo>> section_info_list;
|
||||
std::vector<std::unique_ptr<HookData>> mHookDataList;
|
||||
std::vector<std::unique_ptr<FunctionData>> mFunctionDataList;
|
||||
std::vector<std::unique_ptr<RelocationData>> mRelocationDataList;
|
||||
std::set<std::unique_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> mSymbolDataList;
|
||||
std::map<std::string, std::unique_ptr<SectionInfo>> mSectionInfoList;
|
||||
|
||||
uint8_t trampolineId = 0;
|
||||
uint8_t mTrampolineId = 0;
|
||||
|
||||
std::unique_ptr<uint8_t[]> allocatedTextMemoryAddress;
|
||||
std::unique_ptr<uint8_t[]> allocatedDataMemoryAddress;
|
||||
HeapMemoryFixedSize mAllocatedTextMemoryAddress;
|
||||
HeapMemoryFixedSize mAllocatedDataMemoryAddress;
|
||||
|
||||
friend class PluginInformationFactory;
|
||||
};
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "PluginInformationFactory.h"
|
||||
#include "../utils/ElfUtils.h"
|
||||
#include "../utils/utils.h"
|
||||
#include "utils/HeapMemoryFixedSize.h"
|
||||
#include "utils/wiiu_zlib.hpp"
|
||||
#include <coreinit/cache.h>
|
||||
#include <map>
|
||||
@ -27,33 +28,34 @@
|
||||
|
||||
using namespace ELFIO;
|
||||
|
||||
std::optional<std::unique_ptr<PluginInformation>>
|
||||
PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
|
||||
uint8_t trampolineId) {
|
||||
if (!pluginData->buffer) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Buffer was nullptr");
|
||||
return {};
|
||||
std::unique_ptr<PluginInformation>
|
||||
PluginInformationFactory::load(const PluginData &pluginData, std::vector<relocation_trampoline_entry_t> &trampolineData, uint8_t trampolineId) {
|
||||
auto buffer = pluginData.getBuffer();
|
||||
if (buffer.empty()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Buffer was empty");
|
||||
return nullptr;
|
||||
}
|
||||
elfio reader(new wiiu_zlib);
|
||||
|
||||
if (!reader.load(reinterpret_cast<const char *>(pluginData->buffer.get()), pluginData->length)) {
|
||||
if (!reader.load(reinterpret_cast<const char *>(buffer.data()), buffer.size())) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto pluginInfo = make_unique_nothrow<PluginInformation>();
|
||||
if (!pluginInfo) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate PluginInformation");
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t sec_num = reader.sections.size();
|
||||
|
||||
auto destinations = make_unique_nothrow<uint8_t *[]>(sec_num);
|
||||
if (!destinations) {
|
||||
auto destinationsData = make_unique_nothrow<uint8_t *[]>(sec_num);
|
||||
if (!destinationsData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed alloc memory for destinations array");
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
std::span<uint8_t *> destinations(destinationsData.get(), sec_num);
|
||||
|
||||
uint32_t totalSize = 0;
|
||||
|
||||
@ -80,22 +82,18 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
|
||||
}
|
||||
}
|
||||
|
||||
auto text_data = make_unique_nothrow<uint8_t[]>(text_size);
|
||||
HeapMemoryFixedSize text_data(text_size);
|
||||
if (!text_data) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes)", text_size);
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb", text_size / 1024);
|
||||
|
||||
auto data_data = make_unique_nothrow<uint8_t[]>(data_size);
|
||||
HeapMemoryFixedSize data_data(data_size);
|
||||
if (!data_data) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .data section (%d bytes)", data_size);
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb", data_size / 1024);
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
if (psec->get_type() == 0x80000002 || psec->get_name() == ".wut_load_bounds") {
|
||||
@ -108,29 +106,29 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
|
||||
|
||||
uint32_t destination = address;
|
||||
if ((address >= 0x02000000) && address < 0x10000000) {
|
||||
destination += (uint32_t) text_data.get();
|
||||
destination += (uint32_t) text_data.data();
|
||||
destination -= 0x02000000;
|
||||
destinations[psec->get_index()] = (uint8_t *) text_data.get();
|
||||
destinations[psec->get_index()] = (uint8_t *) text_data.data();
|
||||
|
||||
if (destination + sectionSize > (uint32_t) text_data.get() + text_size) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Tried to overflow .text buffer. %08X > %08X", destination + sectionSize, (uint32_t) text_data.get() + text_size);
|
||||
if (destination + sectionSize > (uint32_t) text_data.data() + text_size) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Tried to overflow .text buffer. %08X > %08X", destination + sectionSize, (uint32_t) text_data.data() + text_data.size());
|
||||
OSFatal("WUPSLoader: Tried to overflow buffer");
|
||||
}
|
||||
} else if ((address >= 0x10000000) && address < 0xC0000000) {
|
||||
destination += (uint32_t) data_data.get();
|
||||
destination += (uint32_t) data_data.data();
|
||||
destination -= 0x10000000;
|
||||
destinations[psec->get_index()] = (uint8_t *) data_data.get();
|
||||
destinations[psec->get_index()] = (uint8_t *) data_data.data();
|
||||
|
||||
if (destination + sectionSize > (uint32_t) data_data.get() + data_size) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Tried to overflow .data buffer. %08X > %08X", destination + sectionSize, (uint32_t) data_data.get() + data_size);
|
||||
if (destination + sectionSize > (uint32_t) data_data.data() + data_data.size()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Tried to overflow .data buffer. %08X > %08X", destination + sectionSize, (uint32_t) text_data.data() + text_data.size());
|
||||
OSFatal("WUPSLoader: Tried to overflow buffer");
|
||||
}
|
||||
} else if (address >= 0xC0000000) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Loading section from 0xC0000000 is NOT supported");
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Unhandled case");
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *p = psec->get_data();
|
||||
@ -146,7 +144,7 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
|
||||
auto sectionInfo = make_unique_nothrow<SectionInfo>(psec->get_name(), destination, sectionSize);
|
||||
if (!sectionInfo) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocat SectionInfo");
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pluginInfo->addSectionInfo(std::move(sectionInfo));
|
||||
@ -163,30 +161,30 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
|
||||
section *psec = reader.sections[i];
|
||||
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()]);
|
||||
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.data(), (uint32_t) data_data.data(), trampolineData,
|
||||
trampolineId)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("linkSection failed");
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!PluginInformationFactory::addImportRelocationData(pluginInfo, reader, destinations)) {
|
||||
if (!PluginInformationFactory::addImportRelocationData(*pluginInfo, reader, destinations)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("addImportRelocationData failed");
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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);
|
||||
DCFlushRange((void *) text_data.data(), text_data.size());
|
||||
ICInvalidateRange((void *) text_data.data(), text_data.size());
|
||||
DCFlushRange((void *) data_data.data(), data_data.size());
|
||||
ICInvalidateRange((void *) data_data.data(), data_data.size());
|
||||
|
||||
pluginInfo->setTrampolineId(trampolineId);
|
||||
|
||||
auto secInfo = pluginInfo->getSectionInfo(".wups.hooks");
|
||||
if (secInfo && secInfo.value()->getSize() > 0) {
|
||||
size_t entries_count = secInfo.value()->getSize() / sizeof(wups_loader_hook_t);
|
||||
auto *entries = (wups_loader_hook_t *) secInfo.value()->getAddress();
|
||||
if (secInfo && secInfo->getSize() > 0) {
|
||||
size_t entries_count = secInfo->getSize() / sizeof(wups_loader_hook_t);
|
||||
auto *entries = (wups_loader_hook_t *) secInfo->getAddress();
|
||||
if (entries != nullptr) {
|
||||
for (size_t j = 0; j < entries_count; j++) {
|
||||
wups_loader_hook_t *hook = &entries[j];
|
||||
@ -194,7 +192,7 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
|
||||
auto hookData = make_unique_nothrow<HookData>((void *) hook->target, hook->type);
|
||||
if (!hookData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate HookData");
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
pluginInfo->addHookData(std::move(hookData));
|
||||
}
|
||||
@ -202,14 +200,14 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
|
||||
}
|
||||
|
||||
secInfo = pluginInfo->getSectionInfo(".wups.load");
|
||||
if (secInfo && secInfo.value()->getSize() > 0) {
|
||||
size_t entries_count = secInfo.value()->getSize() / sizeof(wups_loader_entry_t);
|
||||
auto *entries = (wups_loader_entry_t *) secInfo.value()->getAddress();
|
||||
if (secInfo && secInfo->getSize() > 0) {
|
||||
size_t entries_count = secInfo->getSize() / sizeof(wups_loader_entry_t);
|
||||
auto *entries = (wups_loader_entry_t *) secInfo->getAddress();
|
||||
if (entries != nullptr) {
|
||||
for (size_t j = 0; j < entries_count; j++) {
|
||||
wups_loader_entry_t *cur_function = &entries[j];
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Saving function \"%s\" of plugin . PA:%08X VA:%08X Library: %08X, target: %08X, call_addr: %08X",
|
||||
cur_function->_function.name /*,pluginData->getPluginInformation()->getName().c_str()*/,
|
||||
cur_function->_function.name /*,mPluginData->getPluginInformation()->getName().c_str()*/,
|
||||
cur_function->_function.physical_address, cur_function->_function.virtual_address, cur_function->_function.library, cur_function->_function.target,
|
||||
(void *) cur_function->_function.call_addr);
|
||||
|
||||
@ -222,7 +220,7 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
|
||||
(FunctionPatcherTargetProcess) cur_function->_function.targetProcess);
|
||||
if (!functionData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate FunctionData");
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
pluginInfo->addFunctionData(std::move(functionData));
|
||||
}
|
||||
@ -248,18 +246,18 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
|
||||
if (symbols.get_symbol(j, name, value, size, bind, type, section, other)) {
|
||||
|
||||
if (type == STT_FUNC) { // We only care about functions.
|
||||
auto sectionVal = reader.sections[section];
|
||||
auto offsetVal = value - sectionVal->get_address();
|
||||
auto sectionOpt = pluginInfo->getSectionInfo(sectionVal->get_name());
|
||||
if (!sectionOpt.has_value()) {
|
||||
auto sectionVal = reader.sections[section];
|
||||
auto offsetVal = value - sectionVal->get_address();
|
||||
auto sectionInfo = pluginInfo->getSectionInfo(sectionVal->get_name());
|
||||
if (!sectionInfo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto finalAddress = offsetVal + sectionOpt.value()->getAddress();
|
||||
auto finalAddress = offsetVal + sectionInfo->getAddress();
|
||||
auto functionSymbolData = make_unique_nothrow<FunctionSymbolData>(name, (void *) finalAddress, (uint32_t) size);
|
||||
if (!functionSymbolData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate FunctionSymbolData");
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
pluginInfo->addFunctionSymbolData(std::move(functionSymbolData));
|
||||
}
|
||||
@ -272,17 +270,18 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
|
||||
|
||||
if (totalSize > text_size + data_size) {
|
||||
DEBUG_FUNCTION_LINE_ERR("We didn't allocate enough memory!!");
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
// Save the addresses for the allocated memory. This way we can free it again :)
|
||||
pluginInfo->allocatedDataMemoryAddress = std::move(data_data);
|
||||
pluginInfo->allocatedTextMemoryAddress = std::move(text_data);
|
||||
pluginInfo->mAllocatedDataMemoryAddress = std::move(data_data);
|
||||
pluginInfo->mAllocatedTextMemoryAddress = std::move(text_data);
|
||||
|
||||
return pluginInfo;
|
||||
}
|
||||
|
||||
bool PluginInformationFactory::addImportRelocationData(const std::unique_ptr<PluginInformation> &pluginInfo, const elfio &reader, const std::unique_ptr<uint8_t *[]> &destinations) {
|
||||
bool PluginInformationFactory::addImportRelocationData(PluginInformation &pluginInfo, const elfio &reader, std::span<uint8_t *> destinations) {
|
||||
std::map<uint32_t, std::shared_ptr<ImportRPLInformation>> infoMap;
|
||||
|
||||
uint32_t sec_num = reader.sections.size();
|
||||
@ -352,16 +351,15 @@ bool PluginInformationFactory::addImportRelocationData(const std::unique_ptr<Plu
|
||||
return false;
|
||||
}
|
||||
|
||||
pluginInfo->addRelocationData(std::move(relocationData));
|
||||
pluginInfo.addRelocationData(std::move(relocationData));
|
||||
}
|
||||
}
|
||||
}
|
||||
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,
|
||||
uint32_t trampoline_data_length,
|
||||
uint8_t trampolineId) {
|
||||
bool PluginInformationFactory::linkSection(const elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data,
|
||||
std::vector<relocation_trampoline_entry_t> &trampolineData, uint8_t trampolineId) {
|
||||
uint32_t sec_num = reader.sections.size();
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
@ -431,7 +429,7 @@ bool PluginInformationFactory::linkSection(const elfio &reader, uint32_t section
|
||||
}
|
||||
// DEBUG_FUNCTION_LINE_VERBOSE("sym_value %08X adjusted_sym_value %08X offset %08X adjusted_offset %08X", (uint32_t) sym_value, adjusted_sym_value, (uint32_t) offset, adjusted_offset);
|
||||
|
||||
if (!ElfUtils::elfLinkOne(type, adjusted_offset, addend, destination, adjusted_sym_value, trampoline_data, trampoline_data_length, RELOC_TYPE_FIXED, trampolineId)) {
|
||||
if (!ElfUtils::elfLinkOne(type, adjusted_offset, addend, destination, adjusted_sym_value, trampolineData, RELOC_TYPE_FIXED, trampolineId)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Link failed");
|
||||
return false;
|
||||
}
|
||||
|
@ -27,17 +27,15 @@
|
||||
#include <vector>
|
||||
#include <wums/defines/relocation_defines.h>
|
||||
|
||||
|
||||
class PluginInformationFactory {
|
||||
public:
|
||||
static std::optional<std::unique_ptr<PluginInformation>>
|
||||
load(const std::shared_ptr<PluginData> &pluginData, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
|
||||
uint8_t trampolineId);
|
||||
static std::unique_ptr<PluginInformation>
|
||||
load(const PluginData &pluginData, std::vector<relocation_trampoline_entry_t> &trampolineData, uint8_t trampolineId);
|
||||
|
||||
static bool
|
||||
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,
|
||||
uint8_t trampolineId);
|
||||
linkSection(const ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data,
|
||||
std::vector<relocation_trampoline_entry_t> &trampolineData, uint8_t trampolineId);
|
||||
|
||||
static bool addImportRelocationData(const std::unique_ptr<PluginInformation> &pluginInfo, const ELFIO::elfio &reader, const std::unique_ptr<uint8_t *[]> &destinations);
|
||||
static bool
|
||||
addImportRelocationData(PluginInformation &pluginInfo, const ELFIO::elfio &reader, std::span<uint8_t *> destinations);
|
||||
};
|
||||
|
@ -22,55 +22,34 @@
|
||||
#include "utils/wiiu_zlib.hpp"
|
||||
#include <memory>
|
||||
|
||||
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const std::shared_ptr<PluginData> &pluginData, PluginParseErrors &error) {
|
||||
if (!pluginData->buffer) {
|
||||
std::unique_ptr<PluginMetaInformation> PluginMetaInformationFactory::loadPlugin(const PluginData &pluginData, PluginParseErrors &error) {
|
||||
return loadPlugin(pluginData.getBuffer(), error);
|
||||
}
|
||||
|
||||
std::unique_ptr<PluginMetaInformation> PluginMetaInformationFactory::loadPlugin(std::string_view filePath, PluginParseErrors &error) {
|
||||
std::vector<uint8_t> buffer;
|
||||
if (FSUtils::LoadFileToMem(filePath, buffer) < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load file to memory");
|
||||
error = PLUGIN_PARSE_ERROR_IO_ERROR;
|
||||
return {};
|
||||
}
|
||||
return loadPlugin(buffer, error);
|
||||
}
|
||||
|
||||
std::unique_ptr<PluginMetaInformation> PluginMetaInformationFactory::loadPlugin(std::span<const uint8_t> buffer, PluginParseErrors &error) {
|
||||
if (buffer.empty()) {
|
||||
error = PLUGIN_PARSE_ERROR_BUFFER_EMPTY;
|
||||
DEBUG_FUNCTION_LINE_ERR("Buffer is empty");
|
||||
return {};
|
||||
}
|
||||
ELFIO::elfio reader(new wiiu_zlib);
|
||||
if (!reader.load(reinterpret_cast<const char *>(pluginData->buffer.get()), pluginData->length)) {
|
||||
error = PLUGIN_PARSE_ERROR_ELFIO_PARSE_FAILED;
|
||||
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
|
||||
return {};
|
||||
}
|
||||
return loadPlugin(reader, error);
|
||||
}
|
||||
|
||||
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const std::string &filePath, PluginParseErrors &error) {
|
||||
ELFIO::elfio reader(new wiiu_zlib);
|
||||
|
||||
uint8_t *buffer = nullptr;
|
||||
uint32_t length = 0;
|
||||
if (FSUtils::LoadFileToMem(filePath.c_str(), &buffer, &length) < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load file to memory");
|
||||
error = PLUGIN_PARSE_ERROR_IO_ERROR;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!reader.load(reinterpret_cast<const char *>(buffer), length)) {
|
||||
error = PLUGIN_PARSE_ERROR_ELFIO_PARSE_FAILED;
|
||||
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
|
||||
return {};
|
||||
}
|
||||
auto res = loadPlugin(reader, error);
|
||||
free(buffer);
|
||||
return res;
|
||||
}
|
||||
|
||||
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(char *buffer, size_t size, PluginParseErrors &error) {
|
||||
ELFIO::elfio reader(new wiiu_zlib);
|
||||
|
||||
if (!reader.load(reinterpret_cast<const char *>(buffer), size)) {
|
||||
if (!reader.load(reinterpret_cast<const char *>(buffer.data()), buffer.size())) {
|
||||
error = PLUGIN_PARSE_ERROR_ELFIO_PARSE_FAILED;
|
||||
DEBUG_FUNCTION_LINE_ERR("Can't find or process ELF file");
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return loadPlugin(reader, error);
|
||||
}
|
||||
|
||||
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const ELFIO::elfio &reader, PluginParseErrors &error) {
|
||||
size_t pluginSize = 0;
|
||||
|
||||
auto pluginInfo = std::unique_ptr<PluginMetaInformation>(new PluginMetaInformation);
|
||||
@ -127,7 +106,7 @@ std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFacto
|
||||
if (value != "0.7.1") {
|
||||
error = PLUGIN_PARSE_ERROR_INCOMPATIBLE_VERSION;
|
||||
DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring plugin - Unsupported WUPS version: %s.", value.c_str());
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,11 +36,9 @@ enum PluginParseErrors {
|
||||
|
||||
class PluginMetaInformationFactory {
|
||||
public:
|
||||
static std::optional<std::unique_ptr<PluginMetaInformation>> loadPlugin(const std::shared_ptr<PluginData> &pluginData, PluginParseErrors &error);
|
||||
static std::unique_ptr<PluginMetaInformation> loadPlugin(const PluginData &pluginData, PluginParseErrors &error);
|
||||
|
||||
static std::optional<std::unique_ptr<PluginMetaInformation>> loadPlugin(const std::string &filePath, PluginParseErrors &error);
|
||||
static std::unique_ptr<PluginMetaInformation> loadPlugin(std::string_view filePath, PluginParseErrors &error);
|
||||
|
||||
static std::optional<std::unique_ptr<PluginMetaInformation>> loadPlugin(char *buffer, size_t size, PluginParseErrors &error);
|
||||
|
||||
static std::optional<std::unique_ptr<PluginMetaInformation>> loadPlugin(const ELFIO::elfio &reader, PluginParseErrors &error);
|
||||
static std::unique_ptr<PluginMetaInformation> loadPlugin(std::span<const uint8_t> buffer, PluginParseErrors &error);
|
||||
};
|
||||
|
@ -57,8 +57,8 @@ public:
|
||||
return name;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::shared_ptr<ImportRPLInformation> &getImportRPLInformation() const {
|
||||
return rplInfo;
|
||||
[[nodiscard]] const ImportRPLInformation &getImportRPLInformation() const {
|
||||
return *rplInfo;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -122,12 +122,11 @@ void ConfigUtils::displayMenu() {
|
||||
std::vector<ConfigDisplayItem> configs;
|
||||
for (auto &plugin : gLoadedPlugins) {
|
||||
ConfigDisplayItem cfg;
|
||||
cfg.name = plugin->metaInformation->getName();
|
||||
cfg.author = plugin->metaInformation->getAuthor();
|
||||
cfg.version = plugin->metaInformation->getVersion();
|
||||
|
||||
for (auto &hook : plugin->getPluginInformation()->getHookDataList()) {
|
||||
cfg.name = plugin->getMetaInformation().getName();
|
||||
cfg.author = plugin->getMetaInformation().getAuthor();
|
||||
cfg.version = plugin->getMetaInformation().getVersion();
|
||||
|
||||
for (const auto &hook : plugin->getPluginInformation().getHookDataList()) {
|
||||
if (hook->getType() == WUPS_LOADER_HOOK_GET_CONFIG /*WUPS_LOADER_HOOK_GET_CONFIG*/) {
|
||||
if (hook->getFunctionPointer() == nullptr) {
|
||||
break;
|
||||
|
@ -1,13 +1,14 @@
|
||||
#include <coreinit/cache.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "ElfUtils.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
// See https://github.com/decaf-emu/decaf-emu/blob/43366a34e7b55ab9d19b2444aeb0ccd46ac77dea/src/libdecaf/src/cafe/loader/cafe_loader_reloc.cpp#L144
|
||||
bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
|
||||
RelocationType reloc_type, uint8_t trampolineId) {
|
||||
bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr,
|
||||
std::vector<relocation_trampoline_entry_t> &trampolineData, RelocationType reloc_type, uint8_t trampolineId) {
|
||||
if (type == R_PPC_NONE) {
|
||||
return true;
|
||||
}
|
||||
@ -76,21 +77,21 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||
// }
|
||||
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
||||
if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) {
|
||||
if (trampoline_data == nullptr) {
|
||||
if (trampolineData.empty()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline isn't provided");
|
||||
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, distance);
|
||||
return false;
|
||||
} else {
|
||||
relocation_trampoline_entry_t *freeSlot = nullptr;
|
||||
for (uint32_t i = 0; i < trampoline_data_length; i++) {
|
||||
for (auto &cur : trampolineData) {
|
||||
// We want to override "old" relocations of imports
|
||||
// Pending relocations have the status RELOC_TRAMP_IMPORT_IN_PROGRESS.
|
||||
// When all relocations are done successfully, they will be turned into RELOC_TRAMP_IMPORT_DONE
|
||||
// so they can be overridden/updated/reused on the next application launch.
|
||||
//
|
||||
// Relocations that won't change will have the status RELOC_TRAMP_FIXED and are set to free when the module is unloaded.
|
||||
if (trampoline_data[i].status == RELOC_TRAMP_FREE) {
|
||||
freeSlot = &(trampoline_data[i]);
|
||||
if (cur.status == RELOC_TRAMP_FREE) {
|
||||
freeSlot = &cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,6 @@ uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fi
|
||||
class ElfUtils {
|
||||
|
||||
public:
|
||||
static bool elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
|
||||
static bool elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, std::vector<relocation_trampoline_entry_t> &trampolineData,
|
||||
RelocationType reloc_type, uint8_t trampolineId);
|
||||
};
|
||||
|
45
source/utils/HeapMemoryFixedSize.h
Normal file
45
source/utils/HeapMemoryFixedSize.h
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include "utils.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
class HeapMemoryFixedSize {
|
||||
public:
|
||||
HeapMemoryFixedSize() = default;
|
||||
|
||||
explicit HeapMemoryFixedSize(std::size_t size) : mData(make_unique_nothrow<uint8_t[]>(size)), mSize(mData ? size : 0) {}
|
||||
|
||||
// Delete the copy constructor and copy assignment operator
|
||||
HeapMemoryFixedSize(const HeapMemoryFixedSize &) = delete;
|
||||
HeapMemoryFixedSize &operator=(const HeapMemoryFixedSize &) = delete;
|
||||
|
||||
HeapMemoryFixedSize(HeapMemoryFixedSize &&other) noexcept
|
||||
: mData(std::move(other.mData)), mSize(other.mSize) {
|
||||
other.mSize = 0;
|
||||
}
|
||||
|
||||
HeapMemoryFixedSize &operator=(HeapMemoryFixedSize &&other) noexcept {
|
||||
if (this != &other) {
|
||||
mData = std::move(other.mData);
|
||||
mSize = other.mSize;
|
||||
other.mSize = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return mData != nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] const void *data() const {
|
||||
return mData.get();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t size() const {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<uint8_t[]> mData{};
|
||||
std::size_t mSize{};
|
||||
};
|
@ -122,7 +122,7 @@ WUPSStorageError StorageUtils::CloseStorage(const char *plugin_id, wups_storage_
|
||||
std::string folderPath = getPluginPath() + "/config/";
|
||||
std::string filePath = folderPath + plugin_id + ".json";
|
||||
|
||||
FSUtils::CreateSubfolder(folderPath.c_str());
|
||||
FSUtils::CreateSubfolder(folderPath);
|
||||
|
||||
CFile file(filePath, CFile::WriteOnly);
|
||||
if (!file.isOpen()) {
|
||||
|
@ -34,8 +34,8 @@
|
||||
#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'
|
||||
std::string string_format(std::string_view format, Args... args) {
|
||||
int size_s = std::snprintf(nullptr, 0, format.data(), args...) + 1; // Extra space for '\0'
|
||||
auto size = static_cast<size_t>(size_s);
|
||||
auto buf = make_unique_nothrow<char[]>(size);
|
||||
if (!buf) {
|
||||
@ -43,11 +43,10 @@ std::string string_format(const std::string &format, Args... args) {
|
||||
OSFatal("string_format failed, not enough memory");
|
||||
return std::string("");
|
||||
}
|
||||
std::snprintf(buf.get(), size, format.c_str(), args...);
|
||||
std::snprintf(buf.get(), size, format.data(), args...);
|
||||
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
|
||||
}
|
||||
|
||||
|
||||
class StringTools {
|
||||
public:
|
||||
static std::string truncate(const std::string &str, size_t width, bool show_ellipsis = true);
|
||||
|
@ -6,35 +6,36 @@
|
||||
#include "utils.h"
|
||||
#include <wums.h>
|
||||
|
||||
static void fillPluginInformation(plugin_information *out, const std::unique_ptr<PluginMetaInformation> &metaInformation) {
|
||||
static void fillPluginInformation(plugin_information *out, const PluginMetaInformation &metaInformation) {
|
||||
out->plugin_information_version = PLUGIN_INFORMATION_VERSION;
|
||||
strncpy(out->author, metaInformation->getAuthor().c_str(), sizeof(out->author) - 1);
|
||||
strncpy(out->buildTimestamp, metaInformation->getBuildTimestamp().c_str(), sizeof(out->buildTimestamp) - 1);
|
||||
strncpy(out->description, metaInformation->getDescription().c_str(), sizeof(out->description) - 1);
|
||||
strncpy(out->name, metaInformation->getName().c_str(), sizeof(out->name) - 1);
|
||||
strncpy(out->license, metaInformation->getLicense().c_str(), sizeof(out->license) - 1);
|
||||
strncpy(out->version, metaInformation->getVersion().c_str(), sizeof(out->version) - 1);
|
||||
strncpy(out->storageId, metaInformation->getStorageId().c_str(), sizeof(out->storageId) - 1);
|
||||
out->size = metaInformation->getSize();
|
||||
strncpy(out->author, metaInformation.getAuthor().c_str(), sizeof(out->author) - 1);
|
||||
strncpy(out->buildTimestamp, metaInformation.getBuildTimestamp().c_str(), sizeof(out->buildTimestamp) - 1);
|
||||
strncpy(out->description, metaInformation.getDescription().c_str(), sizeof(out->description) - 1);
|
||||
strncpy(out->name, metaInformation.getName().c_str(), sizeof(out->name) - 1);
|
||||
strncpy(out->license, metaInformation.getLicense().c_str(), sizeof(out->license) - 1);
|
||||
strncpy(out->version, metaInformation.getVersion().c_str(), sizeof(out->version) - 1);
|
||||
strncpy(out->storageId, metaInformation.getStorageId().c_str(), sizeof(out->storageId) - 1);
|
||||
out->size = metaInformation.getSize();
|
||||
}
|
||||
|
||||
extern "C" PluginBackendApiErrorType WUPSLoadAndLinkByDataHandle(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size) {
|
||||
if (plugin_data_handle_list == nullptr || plugin_data_handle_list_size == 0) {
|
||||
|
||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (auto &pluginData : gLoadedData) {
|
||||
for (const auto &pluginData : gLoadedData) {
|
||||
if (pluginData->getHandle() == handle) {
|
||||
gLoadOnNextLaunch.push_front(pluginData);
|
||||
gLoadOnNextLaunch.insert(pluginData);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get plugin data for handle %08X. Skipping it.", handle);
|
||||
}
|
||||
@ -45,9 +46,7 @@ extern "C" PluginBackendApiErrorType WUPSLoadAndLinkByDataHandle(const plugin_da
|
||||
|
||||
extern "C" PluginBackendApiErrorType WUPSDeletePluginData(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size) {
|
||||
if (plugin_data_handle_list != nullptr && plugin_data_handle_list_size != 0) {
|
||||
for (uint32_t i = 0; i < plugin_data_handle_list_size; i++) {
|
||||
auto handle = plugin_data_handle_list[i];
|
||||
|
||||
for (auto &handle : std::span(plugin_data_handle_list, plugin_data_handle_list_size)) {
|
||||
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);
|
||||
}
|
||||
@ -61,13 +60,11 @@ extern "C" PluginBackendApiErrorType WUPSLoadPluginAsData(GetPluginInformationIn
|
||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
std::optional<std::unique_ptr<PluginData>> pluginData;
|
||||
std::unique_ptr<PluginData> pluginData;
|
||||
if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) {
|
||||
pluginData = PluginDataFactory::load(path);
|
||||
} else if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_BUFFER && buffer != nullptr && size > 0) {
|
||||
std::vector<uint8_t> data(size);
|
||||
memcpy(&data[0], buffer, size);
|
||||
pluginData = PluginDataFactory::load(data, "<UNKNOWN>");
|
||||
pluginData = make_unique_nothrow<PluginData>(std::span((uint8_t *) buffer, size), "<UNKNOWN>");
|
||||
} else {
|
||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
}
|
||||
@ -75,11 +72,9 @@ extern "C" PluginBackendApiErrorType WUPSLoadPluginAsData(GetPluginInformationIn
|
||||
if (!pluginData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_FAILED_ALLOC");
|
||||
return PLUGIN_BACKEND_API_ERROR_FAILED_ALLOC;
|
||||
}
|
||||
|
||||
else {
|
||||
*out = pluginData.value()->getHandle();
|
||||
gLoadedData.push_front(std::move(pluginData.value()));
|
||||
} else {
|
||||
*out = pluginData->getHandle();
|
||||
gLoadedData.insert(std::move(pluginData));
|
||||
}
|
||||
|
||||
return PLUGIN_BACKEND_API_ERROR_NONE;
|
||||
@ -94,13 +89,17 @@ extern "C" PluginBackendApiErrorType WUPSLoadPluginAsDataByBuffer(plugin_data_ha
|
||||
}
|
||||
|
||||
extern "C" PluginBackendApiErrorType WUPSGetPluginMetaInformation(GetPluginInformationInputType inputType, const char *path, char *buffer, size_t size, plugin_information *output) {
|
||||
std::optional<std::unique_ptr<PluginMetaInformation>> pluginInfo;
|
||||
if (output == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_INVALID_ARG");
|
||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
std::unique_ptr<PluginMetaInformation> pluginInfo;
|
||||
PluginParseErrors error = PLUGIN_PARSE_ERROR_UNKNOWN;
|
||||
if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) {
|
||||
std::string pathStr(path);
|
||||
pluginInfo = PluginMetaInformationFactory::loadPlugin(pathStr, error);
|
||||
pluginInfo = PluginMetaInformationFactory::loadPlugin(path, error);
|
||||
} else if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_BUFFER && buffer != nullptr && size > 0) {
|
||||
pluginInfo = PluginMetaInformationFactory::loadPlugin(buffer, size, error);
|
||||
pluginInfo = PluginMetaInformationFactory::loadPlugin(std::span<uint8_t const>((uint8_t *) buffer, size), error);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_INVALID_ARG");
|
||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
@ -110,13 +109,8 @@ extern "C" PluginBackendApiErrorType WUPSGetPluginMetaInformation(GetPluginInfor
|
||||
DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_FILE_NOT_FOUND");
|
||||
return PLUGIN_BACKEND_API_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
fillPluginInformation(output, *pluginInfo);
|
||||
|
||||
if (output == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_INVALID_ARG");
|
||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
} else {
|
||||
fillPluginInformation(output, pluginInfo.value());
|
||||
}
|
||||
return PLUGIN_BACKEND_API_ERROR_NONE;
|
||||
}
|
||||
|
||||
@ -135,21 +129,21 @@ extern "C" PluginBackendApiErrorType WUPSGetPluginDataForContainerHandles(const
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(gLoadedDataMutex);
|
||||
for (uint32_t i = 0; i < buffer_size; /* only increase on success*/) {
|
||||
for (uint32_t i = 0; i < buffer_size; i++) {
|
||||
auto handle = plugin_container_handle_list[i];
|
||||
bool found = false;
|
||||
for (auto &curContainer : gLoadedPlugins) {
|
||||
for (const auto &curContainer : gLoadedPlugins) {
|
||||
if (curContainer->getHandle() == handle) {
|
||||
auto &pluginData = curContainer->getPluginData();
|
||||
auto pluginData = curContainer->getPluginDataCopy();
|
||||
plugin_data_list[i] = (uint32_t) pluginData->getHandle();
|
||||
gLoadedData.push_front(pluginData);
|
||||
gLoadedData.insert(std::move(pluginData));
|
||||
found = true;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get container for handle %08X", handle);
|
||||
return PLUGIN_BACKEND_API_INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,19 +156,19 @@ extern "C" PluginBackendApiErrorType WUPSGetMetaInformation(const plugin_contain
|
||||
for (uint32_t i = 0; i < buffer_size; i++) {
|
||||
auto handle = plugin_container_handle_list[i];
|
||||
bool found = false;
|
||||
for (auto &curContainer : gLoadedPlugins) {
|
||||
for (const auto &curContainer : gLoadedPlugins) {
|
||||
if (curContainer->getHandle() == handle) {
|
||||
auto &metaInfo = curContainer->getMetaInformation();
|
||||
const auto &metaInfo = curContainer->getMetaInformation();
|
||||
|
||||
plugin_information_list[i].plugin_information_version = PLUGIN_INFORMATION_VERSION;
|
||||
strncpy(plugin_information_list[i].storageId, metaInfo->getStorageId().c_str(), sizeof(plugin_information_list[i].storageId) - 1);
|
||||
strncpy(plugin_information_list[i].author, metaInfo->getAuthor().c_str(), sizeof(plugin_information_list[i].author) - 1);
|
||||
strncpy(plugin_information_list[i].buildTimestamp, metaInfo->getBuildTimestamp().c_str(), sizeof(plugin_information_list[i].buildTimestamp) - 1);
|
||||
strncpy(plugin_information_list[i].description, metaInfo->getDescription().c_str(), sizeof(plugin_information_list[i].description) - 1);
|
||||
strncpy(plugin_information_list[i].name, metaInfo->getName().c_str(), sizeof(plugin_information_list[i].name) - 1);
|
||||
strncpy(plugin_information_list[i].license, metaInfo->getLicense().c_str(), sizeof(plugin_information_list[i].license) - 1);
|
||||
strncpy(plugin_information_list[i].version, metaInfo->getVersion().c_str(), sizeof(plugin_information_list[i].version) - 1);
|
||||
plugin_information_list[i].size = metaInfo->getSize();
|
||||
strncpy(plugin_information_list[i].storageId, metaInfo.getStorageId().c_str(), sizeof(plugin_information_list[i].storageId) - 1);
|
||||
strncpy(plugin_information_list[i].author, metaInfo.getAuthor().c_str(), sizeof(plugin_information_list[i].author) - 1);
|
||||
strncpy(plugin_information_list[i].buildTimestamp, metaInfo.getBuildTimestamp().c_str(), sizeof(plugin_information_list[i].buildTimestamp) - 1);
|
||||
strncpy(plugin_information_list[i].description, metaInfo.getDescription().c_str(), sizeof(plugin_information_list[i].description) - 1);
|
||||
strncpy(plugin_information_list[i].name, metaInfo.getName().c_str(), sizeof(plugin_information_list[i].name) - 1);
|
||||
strncpy(plugin_information_list[i].license, metaInfo.getLicense().c_str(), sizeof(plugin_information_list[i].license) - 1);
|
||||
strncpy(plugin_information_list[i].version, metaInfo.getVersion().c_str(), sizeof(plugin_information_list[i].version) - 1);
|
||||
plugin_information_list[i].size = metaInfo.getSize();
|
||||
found = true;
|
||||
|
||||
break;
|
||||
@ -196,9 +190,8 @@ extern "C" PluginBackendApiErrorType WUPSGetLoadedPlugins(plugin_container_handl
|
||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
}
|
||||
*plugin_information_version = PLUGIN_INFORMATION_VERSION;
|
||||
auto &plugins = gLoadedPlugins;
|
||||
uint32_t counter = 0;
|
||||
for (auto &plugin : plugins) {
|
||||
for (const auto &plugin : gLoadedPlugins) {
|
||||
if (counter < buffer_size) {
|
||||
io_handles[counter] = plugin->getHandle();
|
||||
counter++;
|
||||
@ -248,10 +241,10 @@ extern "C" PluginBackendApiErrorType WUPSGetSectionInformationForPlugin(const pl
|
||||
}
|
||||
if (handle != 0 && plugin_section_list != nullptr && buffer_size != 0) {
|
||||
bool found = false;
|
||||
for (auto &curContainer : gLoadedPlugins) {
|
||||
for (const auto &curContainer : gLoadedPlugins) {
|
||||
if (curContainer->getHandle() == handle) {
|
||||
found = true;
|
||||
auto §ionInfoList = curContainer->getPluginInformation()->getSectionInfoList();
|
||||
found = true;
|
||||
const auto §ionInfoList = curContainer->getPluginInformation().getSectionInfoList();
|
||||
|
||||
uint32_t offset = 0;
|
||||
for (auto const &[key, sectionInfo] : sectionInfoList) {
|
||||
@ -292,10 +285,10 @@ extern "C" PluginBackendApiErrorType WUPSGetSectionMemoryAddresses(plugin_contai
|
||||
if (handle == 0 || textAddress == nullptr || dataAddress == nullptr) {
|
||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
}
|
||||
for (auto &curContainer : gLoadedPlugins) {
|
||||
for (const auto &curContainer : gLoadedPlugins) {
|
||||
if (curContainer->getHandle() == handle) {
|
||||
*textAddress = curContainer->getPluginInformation()->getTextMemoryAddress();
|
||||
*dataAddress = curContainer->getPluginInformation()->getDataMemoryAddress();
|
||||
*textAddress = (void *) curContainer->getPluginInformation().getTextMemory().data();
|
||||
*dataAddress = (void *) curContainer->getPluginInformation().getDataMemory().data();
|
||||
return PLUGIN_BACKEND_API_ERROR_NONE;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <coreinit/dynload.h>
|
||||
#include <cstdint>
|
||||
#include <forward_list>
|
||||
#include <malloc.h>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -60,17 +62,16 @@ std::shared_ptr<T> make_shared_nothrow(Args &&...args) noexcept(noexcept(T(std::
|
||||
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) {
|
||||
template<typename Container, typename Predicate>
|
||||
bool remove_locked_first_if(std::mutex &mutex, Container &container, 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++;
|
||||
|
||||
auto it = std::find_if(container.begin(), container.end(), pred);
|
||||
if (it != container.end()) {
|
||||
container.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user