- 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:
Maschell 2023-11-04 15:32:45 +01:00
parent baee1afda3
commit cc5acd0980
37 changed files with 477 additions and 583 deletions

View File

@ -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) { if (!gNotificationModuleLoaded) {
return false; return false;
} }
@ -68,7 +68,7 @@ bool DisplayNotificationMessage(std::string &text, NotificationModuleNotificatio
if (!param) { if (!param) {
return false; 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->type = type;
param->duration = duration; param->duration = duration;
@ -84,11 +84,11 @@ bool DisplayNotificationMessage(std::string &text, NotificationModuleNotificatio
return true; 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); 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); return DisplayNotificationMessage(text, NOTIFICATION_MODULE_NOTIFICATION_TYPE_ERROR, duration);
} }
@ -101,7 +101,7 @@ void StartNotificationThread() {
constexpr int32_t messageSize = sizeof(sNotificationMessages) / sizeof(sNotificationMessages[0]); constexpr int32_t messageSize = sizeof(sNotificationMessages) / sizeof(sNotificationMessages[0]);
OSInitMessageQueue(&sNotificationQueue, sNotificationMessages, messageSize); OSInitMessageQueue(&sNotificationQueue, sNotificationMessages, messageSize);
sNotificationsThread = std::make_unique<std::thread>(NotificationMainLoop); sNotificationsThread = make_unique_nothrow<std::thread>(NotificationMainLoop);
} }
void StopNotificationThread() { void StopNotificationThread() {

View File

@ -6,6 +6,6 @@ void StartNotificationThread();
void StopNotificationThread(); 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);

View File

@ -1,7 +1,6 @@
#include "PluginManagement.h" #include "PluginManagement.h"
#include "NotificationsUtils.h" #include "NotificationsUtils.h"
#include "hooks.h" #include "hooks.h"
#include "patcher/hooks_patcher_static.h"
#include "plugin/PluginContainer.h" #include "plugin/PluginContainer.h"
#include "plugin/PluginInformationFactory.h" #include "plugin/PluginInformationFactory.h"
#include "plugin/PluginMetaInformationFactory.h" #include "plugin/PluginMetaInformationFactory.h"
@ -10,19 +9,58 @@
#include "utils/utils.h" #include "utils/utils.h"
#include <coreinit/cache.h> #include <coreinit/cache.h>
#include <coreinit/dynload.h> #include <coreinit/dynload.h>
#include <forward_list>
#include <memory.h> #include <memory.h>
#include <memory> #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, bool PluginManagement::doRelocation(const std::vector<std::unique_ptr<RelocationData>> &relocData,
relocation_trampoline_entry_t *tramp_data, std::vector<relocation_trampoline_entry_t> &trampData,
uint32_t tramp_length,
uint32_t trampolineID, uint32_t trampolineID,
std::map<std::string, OSDynLoad_Module> &usedRPls) { std::map<std::string, OSDynLoad_Module> &usedRPls) {
for (auto const &cur : relocData) { for (auto const &cur : relocData) {
uint32_t functionAddress = 0; uint32_t functionAddress = 0;
const std::string &functionName = cur->getName(); auto &functionName = cur->getName();
if (functionName == "MEMAllocFromDefaultHeap") { if (functionName == "MEMAllocFromDefaultHeap") {
OSDynLoad_Module rplHandle; OSDynLoad_Module rplHandle;
@ -39,8 +77,8 @@ bool PluginManagement::doRelocation(const std::vector<std::unique_ptr<Relocation
} }
if (functionAddress == 0) { if (functionAddress == 0) {
auto rplName = cur->getImportRPLInformation()->getRPLName(); auto rplName = cur->getImportRPLInformation().getRPLName();
int32_t isData = cur->getImportRPLInformation()->isData(); int32_t isData = cur->getImportRPLInformation().isData();
OSDynLoad_Module rplHandle = nullptr; OSDynLoad_Module rplHandle = nullptr;
if (!usedRPls.contains(rplName)) { 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()); //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"); DEBUG_FUNCTION_LINE_ERR("elfLinkOne failed");
return false; 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)); DCFlushRange((void *) trampData.data(), trampData.size() * sizeof(relocation_trampoline_entry_t));
ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t)); ICInvalidateRange((void *) trampData.data(), trampData.size() * sizeof(relocation_trampoline_entry_t));
OSMemoryBarrier(); OSMemoryBarrier();
return true; return true;
} }
bool PluginManagement::doRelocations(const std::vector<std::unique_ptr<PluginContainer>> &plugins, 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) { std::map<std::string, OSDynLoad_Module> &usedRPls) {
for (uint32_t i = 0; i < tramp_size; i++) { for (auto &cur : trampData) {
if (trampData[i].status == RELOC_TRAMP_IMPORT_DONE) { if (cur.status == RELOC_TRAMP_IMPORT_DONE) {
trampData[i].status = RELOC_TRAMP_FREE; cur.status = RELOC_TRAMP_FREE;
} }
} }
@ -104,12 +142,11 @@ bool PluginManagement::doRelocations(const std::vector<std::unique_ptr<PluginCon
OSDynLoad_GetAllocator(&prevDynLoadAlloc, &prevDynLoadFree); OSDynLoad_GetAllocator(&prevDynLoadAlloc, &prevDynLoadFree);
OSDynLoad_SetAllocator(CustomDynLoadAlloc, CustomDynLoadFree); OSDynLoad_SetAllocator(CustomDynLoadAlloc, CustomDynLoadFree);
for (auto &pluginContainer : plugins) { for (const auto &pluginContainer : plugins) {
DEBUG_FUNCTION_LINE_VERBOSE("Doing relocations for plugin: %s", pluginContainer->getMetaInformation()->getName().c_str()); DEBUG_FUNCTION_LINE_VERBOSE("Doing relocations for plugin: %s", pluginContainer->getMetaInformation().getName().c_str());
if (!PluginManagement::doRelocation(pluginContainer->getPluginInformation()->getRelocationDataList(), if (!PluginManagement::doRelocation(pluginContainer->getPluginInformation().getRelocationDataList(),
trampData, trampData,
tramp_size, pluginContainer->getPluginInformation().getTrampolineId(),
pluginContainer->getPluginInformation()->getTrampolineId(),
usedRPls)) { usedRPls)) {
return false; 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) { bool PluginManagement::RestoreFunctionPatches(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
for (const auto &cur : std::ranges::reverse_view(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()) { if (!curFunction->RemovePatch()) {
return false; 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) { bool PluginManagement::DoFunctionPatches(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
for (const auto &cur : plugins) { for (const auto &cur : plugins) {
for (const auto &curFunction : cur->getPluginInformation()->getFunctionDataList()) { for (const auto &curFunction : cur->getPluginInformation().getFunctionDataList()) {
if (!curFunction->AddPatch()) { if (!curFunction->AddPatch()) {
DEBUG_FUNCTION_LINE_ERR("Failed to add function patch for: plugin %s", cur->getMetaInformation().getName().c_str());
return false; 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_STORAGE);
CallHook(plugins, WUPS_LOADER_HOOK_INIT_PLUGIN); CallHook(plugins, WUPS_LOADER_HOOK_INIT_PLUGIN);
DEBUG_FUNCTION_LINE_VERBOSE("Done calling init hooks"); 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;
} }

View File

@ -2,25 +2,25 @@
#include "plugin/PluginContainer.h" #include "plugin/PluginContainer.h"
#include <coreinit/dynload.h> #include <coreinit/dynload.h>
#include <forward_list>
#include <map> #include <map>
#include <memory> #include <memory>
#include <set>
#include <wums/defines/relocation_defines.h> #include <wums/defines/relocation_defines.h>
class PluginManagement { class PluginManagement {
public: 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 void callInitHooks(const std::vector<std::unique_ptr<PluginContainer>> &plugins);
static bool doRelocations(const std::vector<std::unique_ptr<PluginContainer>> &plugins, static bool doRelocations(const std::vector<std::unique_ptr<PluginContainer>> &plugins,
relocation_trampoline_entry_t *trampData, std::vector<relocation_trampoline_entry_t> &trampData,
uint32_t tramp_size,
std::map<std::string, OSDynLoad_Module> &usedRPls); std::map<std::string, OSDynLoad_Module> &usedRPls);
static bool doRelocation(const std::vector<std::unique_ptr<RelocationData>> &relocData, static bool doRelocation(const std::vector<std::unique_ptr<RelocationData>> &relocData,
relocation_trampoline_entry_t *tramp_data, std::vector<relocation_trampoline_entry_t> &trampData,
uint32_t tramp_length,
uint32_t trampolineID, uint32_t trampolineID,
std::map<std::string, OSDynLoad_Module> &usedRPls); std::map<std::string, OSDynLoad_Module> &usedRPls);

View File

@ -26,12 +26,12 @@
class WUPSConfig { class WUPSConfig {
public: public:
explicit WUPSConfig(const std::string &name) { explicit WUPSConfig(std::string_view name) {
this->name = name; this->name = name;
} }
~WUPSConfig() { ~WUPSConfig() {
for (auto &element : categories) { for (const auto &element : categories) {
delete element; delete element;
} }
} }
@ -52,7 +52,7 @@ public:
\return On success, the created and inserted category will be returned. \return On success, the created and inserted category will be returned.
**/ **/
std::optional<WUPSConfigCategory *> addCategory(const std::string &categoryName) { std::optional<WUPSConfigCategory *> addCategory(std::string_view categoryName) {
auto curCat = new (std::nothrow) WUPSConfigCategory(categoryName); auto curCat = new (std::nothrow) WUPSConfigCategory(categoryName);
if (curCat == nullptr) { if (curCat == nullptr) {
return {}; return {};

View File

@ -24,12 +24,12 @@
class WUPSConfigCategory { class WUPSConfigCategory {
public: public:
explicit WUPSConfigCategory(const std::string &name) { explicit WUPSConfigCategory(std::string_view name) {
this->name = name; this->name = name;
} }
~WUPSConfigCategory() { ~WUPSConfigCategory() {
for (auto &element : items) { for (const auto &element : items) {
delete element; delete element;
} }
} }

View File

@ -30,7 +30,7 @@ public:
Sets the display name of this WUPSConfigItem Sets the display name of this WUPSConfigItem
This is the value which will be shown in the configuration menu. 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; this->displayName = _displayName;
} }
@ -47,7 +47,7 @@ public:
to be unique in the context of this WUPSConfig. to be unique in the context of this WUPSConfig.
Items in different categories are NOT allowed to have the config ID. 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; this->configID = _configID;
} }
@ -162,7 +162,7 @@ public:
return defaultValue != getCurrentValueDisplay(); 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->configID = _configID;
this->displayName = _displayName; this->displayName = _displayName;
this->context = _context; this->context = _context;

View File

@ -1,26 +1,23 @@
#include "fs/FSUtils.h" #include "fs/FSUtils.h"
#include "fs/CFile.hpp"
#include "utils/logger.h" #include "utils/logger.h"
#include "utils/utils.h" #include "utils/utils.h"
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <fcntl.h> #include <fcntl.h>
#include <malloc.h> #include <filesystem>
#include <unistd.h> #include <unistd.h>
#include <vector>
int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) { int32_t FSUtils::LoadFileToMem(std::string_view filepath, std::vector<uint8_t> &buffer) {
//! always initialze input //! always initialize input
*inbuffer = NULL; buffer.clear();
if (size) {
*size = 0;
}
int32_t iFd = open(filepath, O_RDONLY); int32_t iFd = open(filepath.data(), O_RDONLY);
if (iFd < 0) { if (iFd < 0) {
return -1; return -1;
} }
struct stat file_stat; struct stat file_stat {};
int rc = fstat(iFd, &file_stat); int rc = fstat(iFd, &file_stat);
if (rc < 0) { if (rc < 0) {
close(iFd); close(iFd);
@ -28,11 +25,7 @@ int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_
} }
uint32_t filesize = file_stat.st_size; uint32_t filesize = file_stat.st_size;
auto *buffer = (uint8_t *) memalign(0x40, ROUNDUP(filesize, 0x40)); buffer.resize(filesize);
if (buffer == nullptr) {
close(iFd);
return -2;
}
uint32_t blocksize = 0x80000; uint32_t blocksize = 0x80000;
uint32_t done = 0; uint32_t done = 0;
@ -42,7 +35,7 @@ int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_
if (done + blocksize > filesize) { if (done + blocksize > filesize) {
blocksize = filesize - done; blocksize = filesize - done;
} }
readBytes = read(iFd, buffer + done, blocksize); readBytes = read(iFd, buffer.data() + done, blocksize);
if (readBytes <= 0) { if (readBytes <= 0) {
break; break;
} }
@ -52,99 +45,17 @@ int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_
::close(iFd); ::close(iFd);
if (done != filesize) { if (done != filesize) {
free(buffer); buffer.clear();
buffer = nullptr;
return -3; 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; return 0;
} }
int32_t FSUtils::CreateSubfolder(const char *fullpath) { bool FSUtils::CreateSubfolder(std::string_view fullpath) {
if (!fullpath) std::error_code err;
return 0; if (!std::filesystem::create_directories(fullpath, err)) {
return std::filesystem::exists(fullpath, err);
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--;
} }
return true;
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;
} }

View File

@ -1,18 +1,12 @@
#ifndef __FS_UTILS_H_ #pragma once
#define __FS_UTILS_H_
#include <string>
#include <vector>
#include <wut_types.h> #include <wut_types.h>
class FSUtils { class FSUtils {
public: 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 bool CreateSubfolder(std::string_view fullpath);
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);
}; };
#endif // __FS_UTILS_H_

View File

@ -4,10 +4,10 @@ StoredBuffer gStoredTVBuffer __attribute__((section(".data"))) = {};
StoredBuffer gStoredDRCBuffer __attribute__((section(".data"))) = {}; StoredBuffer gStoredDRCBuffer __attribute__((section(".data"))) = {};
std::vector<std::unique_ptr<PluginContainer>> gLoadedPlugins __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::set<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>> gLoadOnNextLaunch __attribute__((section(".data")));
std::mutex gLoadedDataMutex __attribute__((section(".data"))); std::mutex gLoadedDataMutex __attribute__((section(".data")));
std::map<std::string, OSDynLoad_Module> gUsedRPLs __attribute__((section(".data"))); std::map<std::string, OSDynLoad_Module> gUsedRPLs __attribute__((section(".data")));
std::vector<void *> gAllocatedAddresses __attribute__((section(".data"))); std::vector<void *> gAllocatedAddresses __attribute__((section(".data")));

View File

@ -16,11 +16,11 @@ extern StoredBuffer gStoredTVBuffer;
extern StoredBuffer gStoredDRCBuffer; extern StoredBuffer gStoredDRCBuffer;
#define TRAMP_DATA_SIZE 1024 #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::vector<std::unique_ptr<PluginContainer>> gLoadedPlugins;
extern std::forward_list<std::shared_ptr<PluginData>> gLoadedData; extern std::set<std::shared_ptr<PluginData>> gLoadedData;
extern std::forward_list<std::shared_ptr<PluginData>> gLoadOnNextLaunch; extern std::set<std::shared_ptr<PluginData>> gLoadOnNextLaunch;
extern std::mutex gLoadedDataMutex; extern std::mutex gLoadedDataMutex;
extern std::map<std::string, OSDynLoad_Module> gUsedRPLs; extern std::map<std::string, OSDynLoad_Module> gUsedRPLs;
extern std::vector<void *> gAllocatedAddresses; extern std::vector<void *> gAllocatedAddresses;

View File

@ -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) { void CallHook(const std::vector<std::unique_ptr<PluginContainer>> &plugins, wups_loader_hook_type_t hook_type) {
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d]", hook_names[hook_type], hook_type); DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d]", hook_names[hook_type], hook_type);
for (auto &plugin : plugins) { for (const auto &plugin : plugins) {
CallHook(plugin, hook_type); CallHook(*plugin, 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) {
for (const auto &hook : plugin->getPluginInformation()->getHookDataList()) { for (const auto &hook : plugin.getPluginInformation().getHookDataList()) {
if (hook->getType() == hook_type) { 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(); void *func_ptr = hook->getFunctionPointer();
if (func_ptr != nullptr) { if (func_ptr != nullptr) {
switch (hook_type) { 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; wups_loader_init_storage_args_t args;
args.open_storage_ptr = &StorageUtils::OpenStorage; args.open_storage_ptr = &StorageUtils::OpenStorage;
args.close_storage_ptr = &StorageUtils::CloseStorage; args.close_storage_ptr = &StorageUtils::CloseStorage;
args.plugin_id = plugin->getMetaInformation()->getStorageId().c_str(); args.plugin_id = plugin.getMetaInformation().getStorageId().c_str();
// clang-format off // clang-format off
((void(*)(wups_loader_init_storage_args_t))((uint32_t *) func_ptr))(args); ((void(*)(wups_loader_init_storage_args_t))((uint32_t *) func_ptr))(args);
// clang-format on // clang-format on

View File

@ -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::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);

View File

@ -26,7 +26,7 @@ WUMS_INITIALIZE() {
NotificationModuleStatus res; NotificationModuleStatus res;
if ((res = NotificationModule_InitLibrary()) != NOTIFICATION_MODULE_RESULT_SUCCESS) { 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; gNotificationModuleLoaded = false;
} else { } else {
gNotificationModuleLoaded = true; gNotificationModuleLoaded = true;
@ -38,6 +38,7 @@ WUMS_INITIALIZE() {
OSFatal("homebrew_wupsbackend: Failed to AddPatch function"); OSFatal("homebrew_wupsbackend: Failed to AddPatch function");
} }
} }
deinitLogging(); deinitLogging();
} }
@ -59,7 +60,7 @@ WUMS_APPLICATION_ENDS() {
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_FINI_WUT_SOCKETS); CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_FINI_WUT_SOCKETS);
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_FINI_WUT_DEVOPTAB); CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_FINI_WUT_DEVOPTAB);
for (auto &pair : gUsedRPLs) { for (const auto &pair : gUsedRPLs) {
OSDynLoad_Release(pair.second); OSDynLoad_Release(pair.second);
} }
gUsedRPLs.clear(); 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. // 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! // 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); DEBUG_FUNCTION_LINE_WARN("Memory allocated by OSDynload was not freed properly, let's clean it up! (%08X)", addr);
free((void *) addr); free((void *) addr);
} }
@ -96,13 +97,11 @@ WUMS_APPLICATION_STARTS() {
std::lock_guard<std::mutex> lock(gLoadedDataMutex); std::lock_guard<std::mutex> lock(gLoadedDataMutex);
if (gTrampData == nullptr) { if (gTrampData.empty()) {
gTrampData = (relocation_trampoline_entry_t *) memalign(0x4, sizeof(relocation_trampoline_entry_t) * TRAMP_DATA_SIZE); gTrampData = std::vector<relocation_trampoline_entry_t>(TRAMP_DATA_SIZE);
if (gTrampData == nullptr) { for (auto &cur : gTrampData) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocated the memory for the trampoline data"); cur.status = RELOC_TRAMP_FREE;
OSFatal("Failed to allocated the memory for the trampoline data");
} }
memset(gTrampData, 0, sizeof(relocation_trampoline_entry_t) * TRAMP_DATA_SIZE);
} }
if (gLoadedPlugins.empty()) { if (gLoadedPlugins.empty()) {
@ -111,7 +110,7 @@ WUMS_APPLICATION_STARTS() {
DEBUG_FUNCTION_LINE("Load plugins from %s", pluginPath.c_str()); DEBUG_FUNCTION_LINE("Load plugins from %s", pluginPath.c_str());
auto pluginData = PluginDataFactory::loadDir(pluginPath); auto pluginData = PluginDataFactory::loadDir(pluginPath);
gLoadedPlugins = PluginManagement::loadPlugins(pluginData, gTrampData, TRAMP_DATA_SIZE); gLoadedPlugins = PluginManagement::loadPlugins(pluginData, gTrampData);
initNeeded = true; initNeeded = true;
} }
@ -138,10 +137,12 @@ WUMS_APPLICATION_STARTS() {
PluginManagement::RestoreFunctionPatches(gLoadedPlugins); PluginManagement::RestoreFunctionPatches(gLoadedPlugins);
DEBUG_FUNCTION_LINE("Unload existing plugins."); DEBUG_FUNCTION_LINE("Unload existing plugins.");
gLoadedPlugins.clear(); 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"); DEBUG_FUNCTION_LINE("Load new plugins");
gLoadedPlugins = PluginManagement::loadPlugins(gLoadOnNextLaunch, gTrampData, TRAMP_DATA_SIZE); gLoadedPlugins = PluginManagement::loadPlugins(gLoadOnNextLaunch, gTrampData);
initNeeded = true; initNeeded = true;
} }
@ -150,9 +151,9 @@ WUMS_APPLICATION_STARTS() {
gLoadedData.clear(); gLoadedData.clear();
if (!gLoadedPlugins.empty()) { if (!gLoadedPlugins.empty()) {
if (!PluginManagement::doRelocations(gLoadedPlugins, gTrampData, TRAMP_DATA_SIZE, gUsedRPLs)) { if (!PluginManagement::doRelocations(gLoadedPlugins, gTrampData, gUsedRPLs)) {
DEBUG_FUNCTION_LINE_ERR("Relocations failed"); DEBUG_FUNCTION_LINE_ERR("Relocations failed");
OSFatal("Relocations failed"); OSFatal("WiiUPluginLoaderBackend: Relocations failed.\n See crash logs for more information.");
} }
// PluginManagement::memsetBSS(plugins); // PluginManagement::memsetBSS(plugins);
@ -179,13 +180,13 @@ WUMS_APPLICATION_STARTS() {
void CheckCleanupCallbackUsage(const std::vector<std::unique_ptr<PluginContainer>> &plugins) { void CheckCleanupCallbackUsage(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
auto *curThread = OSGetCurrentThread(); auto *curThread = OSGetCurrentThread();
for (const auto &cur : plugins) { for (const auto &cur : plugins) {
auto textSection = cur->getPluginInformation()->getSectionInfo(".text"); auto textSection = cur->getPluginInformation().getSectionInfo(".text");
if (!textSection.has_value()) { if (!textSection) {
continue; continue;
} }
uint32_t startAddress = textSection.value()->getAddress(); uint32_t startAddress = textSection->getAddress();
uint32_t endAddress = textSection.value()->getAddress() + textSection.value()->getSize(); uint32_t endAddress = textSection->getAddress() + textSection->getSize();
auto *pluginName = cur->getMetaInformation()->getName().c_str(); auto *pluginName = cur->getMetaInformation().getName().c_str();
{ {
__OSLockScheduler(curThread); __OSLockScheduler(curThread);
int state = OSDisableInterrupts(); int state = OSDisableInterrupts();

View File

@ -120,24 +120,20 @@ DECL_FUNCTION(uint32_t, SC17_FindClosestSymbol,
uint32_t symbolNameBufferLength, uint32_t symbolNameBufferLength,
char *moduleNameBuffer, char *moduleNameBuffer,
uint32_t moduleNameBufferLength) { uint32_t moduleNameBufferLength) {
for (auto &plugin : gLoadedPlugins) { for (const auto &plugin : gLoadedPlugins) {
auto sectionInfoOpt = plugin->getPluginInformation()->getSectionInfo(".text"); auto sectionInfo = plugin->getPluginInformation().getSectionInfo(".text");
if (!sectionInfoOpt) { if (!sectionInfo) {
continue; continue;
} }
auto &sectionInfo = sectionInfoOpt.value();
if (!sectionInfo->isInSection(addr)) { if (!sectionInfo->isInSection(addr)) {
continue; continue;
} }
strncpy(moduleNameBuffer, plugin->getMetaInformation()->getName().c_str(), moduleNameBufferLength - 1); strncpy(moduleNameBuffer, plugin->getMetaInformation().getName().c_str(), moduleNameBufferLength - 1);
auto functionSymbolDataOpt = plugin->getPluginInformation()->getNearestFunctionSymbolData(addr); auto functionSymbolData = plugin->getPluginInformation().getNearestFunctionSymbolData(addr);
if (functionSymbolDataOpt) { if (functionSymbolData) {
auto &functionSymbolData = functionSymbolDataOpt.value(); strncpy(symbolNameBuffer, functionSymbolData->getName().c_str(), moduleNameBufferLength - 1);
strncpy(symbolNameBuffer, functionSymbolData->getName().c_str(), moduleNameBufferLength);
if (outDistance) { if (outDistance) {
*outDistance = addr - (uint32_t) functionSymbolData->getAddress(); *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) { DECL_FUNCTION(uint32_t, KiGetAppSymbolName, uint32_t addr, char *buffer, int32_t bufSize) {
for (auto &plugin : gLoadedPlugins) { for (const auto &plugin : gLoadedPlugins) {
auto sectionInfoOpt = plugin->getPluginInformation()->getSectionInfo(".text"); auto sectionInfo = plugin->getPluginInformation().getSectionInfo(".text");
if (!sectionInfoOpt) { if (!sectionInfo) {
continue; continue;
} }
auto &sectionInfo = sectionInfoOpt.value();
if (!sectionInfo->isInSection(addr)) { if (!sectionInfo->isInSection(addr)) {
continue; 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; int32_t spaceLeftInBuffer = (int32_t) bufSize - (int32_t) pluginNameLen - 1;
if (spaceLeftInBuffer < 0) { if (spaceLeftInBuffer < 0) {
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); auto functionSymbolData = plugin->getPluginInformation().getNearestFunctionSymbolData(addr);
if (functionSymbolDataOpt) { if (functionSymbolData) {
auto &functionSymbolData = functionSymbolDataOpt.value();
buffer[pluginNameLen] = '|'; buffer[pluginNameLen] = '|';
buffer[pluginNameLen + 1] = '\0'; buffer[pluginNameLen + 1] = '\0';
strncpy(buffer + pluginNameLen + 1, functionSymbolData->getName().c_str(), spaceLeftInBuffer - 1); strncpy(buffer + pluginNameLen + 1, functionSymbolData->getName().c_str(), spaceLeftInBuffer - 1);

View File

@ -24,18 +24,23 @@
class FunctionData { class FunctionData {
public: 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) { FunctionPatcherTargetProcess targetProcess) {
this->paddress = paddress; this->paddress = paddress;
this->vaddress = vaddress; this->vaddress = vaddress;
this->name = std::move(name); this->name = name;
this->library = library; this->library = library;
this->targetProcess = targetProcess; this->targetProcess = targetProcess;
this->replaceAddr = replaceAddr; this->replaceAddr = replaceAddr;
this->replaceCall = replaceCall; 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 { [[nodiscard]] const std::string &getName() const {
return this->name; return this->name;
@ -81,7 +86,7 @@ public:
}}; }};
if (FunctionPatcher_AddFunctionPatch(&functionData, &handle, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) { 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; return false;
} }
} else { } else {

View File

@ -24,31 +24,31 @@ class FunctionSymbolData {
public: public:
FunctionSymbolData(const FunctionSymbolData &o2) = default; FunctionSymbolData(const FunctionSymbolData &o2) = default;
FunctionSymbolData(std::string &name, void *address, uint32_t size) : name(name), FunctionSymbolData(std::string_view name, void *address, uint32_t size) : mName(name),
address(address), mAddress(address),
size(size) { mSize(size) {
} }
bool operator<(const FunctionSymbolData &rhs) const { 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; virtual ~FunctionSymbolData() = default;
[[nodiscard]] const std::string &getName() const { [[nodiscard]] const std::string &getName() const {
return name; return mName;
} }
[[nodiscard]] void *getAddress() const { [[nodiscard]] void *getAddress() const {
return address; return mAddress;
} }
[[nodiscard]] uint32_t getSize() const { [[nodiscard]] uint32_t getSize() const {
return size; return mSize;
} }
private: private:
std::string name; std::string mName;
void *address; void *mAddress;
uint32_t size; uint32_t mSize;
}; };

View File

@ -24,24 +24,24 @@
class ImportRPLInformation { class ImportRPLInformation {
public: public:
explicit ImportRPLInformation(std::string name) { explicit ImportRPLInformation(std::string_view name) {
this->name = std::move(name); this->mName = name;
} }
~ImportRPLInformation() = default; ~ImportRPLInformation() = default;
[[nodiscard]] const std::string &getName() const { [[nodiscard]] const std::string &getName() const {
return name; return mName;
} }
[[nodiscard]] std::string getRPLName() const { [[nodiscard]] std::string getRPLName() const {
return name.substr(strlen(".dimport_")); return mName.substr(strlen(".dimport_"));
} }
[[nodiscard]] bool isData() const { [[nodiscard]] bool isData() const {
return name.starts_with(".dimport_"); return mName.starts_with(".dimport_");
} }
private: private:
std::string name; std::string mName;
}; };

View File

@ -26,28 +26,29 @@
class PluginContainer { class PluginContainer {
public: public:
PluginContainer(std::unique_ptr<PluginMetaInformation> metaInformation, std::unique_ptr<PluginInformation> pluginInformation, std::shared_ptr<PluginData> pluginData) PluginContainer(std::unique_ptr<PluginMetaInformation> metaInformation, std::unique_ptr<PluginInformation> pluginInformation, std::shared_ptr<PluginData> pluginData)
: metaInformation(std::move(metaInformation)), : mMetaInformation(std::move(metaInformation)),
pluginInformation(std::move(pluginInformation)), mPluginInformation(std::move(pluginInformation)),
pluginData(std::move(pluginData)) { mPluginData(std::move(pluginData)) {
} }
[[nodiscard]] const std::unique_ptr<PluginMetaInformation> &getMetaInformation() const { [[nodiscard]] const PluginMetaInformation &getMetaInformation() const {
return this->metaInformation; return *this->mMetaInformation;
} }
[[nodiscard]] const std::unique_ptr<PluginInformation> &getPluginInformation() const { [[nodiscard]] const PluginInformation &getPluginInformation() const {
return pluginInformation; return *this->mPluginInformation;
} }
[[nodiscard]] const std::shared_ptr<PluginData> &getPluginData() const { [[nodiscard]] std::shared_ptr<PluginData> getPluginDataCopy() const {
return pluginData; return mPluginData;
} }
uint32_t getHandle() { uint32_t getHandle() {
return (uint32_t) this; return (uint32_t) this;
} }
const std::unique_ptr<PluginMetaInformation> metaInformation; private:
const std::unique_ptr<PluginInformation> pluginInformation; const std::unique_ptr<PluginMetaInformation> mMetaInformation;
const std::shared_ptr<PluginData> pluginData; const std::unique_ptr<PluginInformation> mPluginInformation;
const std::shared_ptr<PluginData> mPluginData;
}; };

View File

@ -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);
}
}

View File

@ -21,17 +21,31 @@
#include <malloc.h> #include <malloc.h>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <span>
#include <utility>
#include <vector> #include <vector>
class PluginData { class PluginData {
public: 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; return (uint32_t) this;
} }
size_t length = 0; [[nodiscard]] std::span<uint8_t const> getBuffer() const {
std::unique_ptr<uint8_t[]> buffer; return mBuffer;
}
[[nodiscard]] const std::string &getSource() const {
return mSource;
}
private:
std::vector<uint8_t> mBuffer;
std::string mSource; std::string mSource;
}; };

View File

@ -23,10 +23,9 @@
#include <dirent.h> #include <dirent.h>
#include <forward_list> #include <forward_list>
#include <memory> #include <memory>
#include <sys/stat.h>
std::forward_list<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const std::string &path) { std::set<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(std::string_view path) {
std::forward_list<std::shared_ptr<PluginData>> result; std::set<std::shared_ptr<PluginData>> result;
struct dirent *dp; struct dirent *dp;
DIR *dfd; DIR *dfd;
@ -35,8 +34,8 @@ std::forward_list<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const
return result; return result;
} }
if ((dfd = opendir(path.c_str())) == nullptr) { if ((dfd = opendir(path.data())) == nullptr) {
DEBUG_FUNCTION_LINE_ERR("Couldn't open dir %s", path.c_str()); DEBUG_FUNCTION_LINE_ERR("Couldn't open dir %s", path.data());
return result; return result;
} }
@ -45,15 +44,15 @@ std::forward_list<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const
continue; 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")) { 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; 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()); DEBUG_FUNCTION_LINE("Loading plugin: %s", full_file_path.c_str());
auto pluginData = load(full_file_path); auto pluginData = load(full_file_path);
if (pluginData) { if (pluginData) {
result.push_front(std::move(pluginData.value())); result.insert(std::move(pluginData));
} else { } else {
auto errMsg = string_format("Failed to load plugin: %s", full_file_path.c_str()); auto errMsg = string_format("Failed to load plugin: %s", full_file_path.c_str());
DEBUG_FUNCTION_LINE_ERR("%s", errMsg.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; return result;
} }
std::optional<std::unique_ptr<PluginData>> PluginDataFactory::load(const std::string &filename) { std::unique_ptr<PluginData> PluginDataFactory::load(std::string_view filename) {
uint8_t *buffer = nullptr; std::vector<uint8_t> buffer;
uint32_t fsize = 0; if (FSUtils::LoadFileToMem(filename, buffer) < 0) {
if (FSUtils::LoadFileToMem(filename.c_str(), &buffer, &fsize) < 0) { DEBUG_FUNCTION_LINE_ERR("Failed to load %s into memory", filename.data());
DEBUG_FUNCTION_LINE_ERR("Failed to load %s into memory", filename.c_str()); return nullptr;
return {};
} }
std::vector<uint8_t> result;
result.resize(fsize);
memcpy(&result[0], buffer, fsize);
free(buffer);
DEBUG_FUNCTION_LINE_VERBOSE("Loaded file!"); DEBUG_FUNCTION_LINE_VERBOSE("Loaded file!");
return load(std::move(buffer), filename);
return load(result, 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()) { if (buffer.empty()) {
return {}; return nullptr;
} }
auto res = make_unique_nothrow<PluginData>(buffer, source); return make_unique_nothrow<PluginData>(std::move(buffer), source);
if (!res) {
return {};
}
return res;
} }

View File

@ -22,14 +22,15 @@
#include <forward_list> #include <forward_list>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <set>
#include <string> #include <string>
#include <vector> #include <vector>
class PluginDataFactory { class PluginDataFactory {
public: 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);
}; };

View File

@ -23,6 +23,8 @@
#include "PluginMetaInformation.h" #include "PluginMetaInformation.h"
#include "RelocationData.h" #include "RelocationData.h"
#include "SectionInfo.h" #include "SectionInfo.h"
#include "utils/HeapMemoryFixedSize.h"
#include "utils/utils.h"
#include <map> #include <map>
#include <memory> #include <memory>
#include <optional> #include <optional>
@ -32,109 +34,101 @@
#include <vector> #include <vector>
struct FunctionSymbolDataComparator { struct FunctionSymbolDataComparator {
bool operator()(const std::shared_ptr<FunctionSymbolData> &lhs, bool operator()(const std::unique_ptr<FunctionSymbolData> &lhs,
const std::shared_ptr<FunctionSymbolData> &rhs) const { const std::unique_ptr<FunctionSymbolData> &rhs) const {
return (uint32_t) lhs->getAddress() < (uint32_t) rhs->getAddress(); return *lhs < *rhs;
} }
}; };
class PluginInformation { class PluginInformation {
public: public:
void addHookData(std::unique_ptr<HookData> hook_data) { 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 { [[nodiscard]] const std::vector<std::unique_ptr<HookData>> &getHookDataList() const {
return hook_data_list; return mHookDataList;
} }
void addFunctionData(std::unique_ptr<FunctionData> function_data) { 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 { [[nodiscard]] const std::vector<std::unique_ptr<FunctionData>> &getFunctionDataList() const {
return function_data_list; return mFunctionDataList;
} }
void addRelocationData(std::unique_ptr<RelocationData> relocation_data) { 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 { [[nodiscard]] const std::vector<std::unique_ptr<RelocationData>> &getRelocationDataList() const {
return relocation_data_list; return mRelocationDataList;
} }
void addFunctionSymbolData(std::unique_ptr<FunctionSymbolData> symbol_data) {
void addFunctionSymbolData(std::shared_ptr<FunctionSymbolData> symbol_data) { mSymbolDataList.insert(std::move(symbol_data));
symbol_data_list.insert(std::move(symbol_data));
} }
[[nodiscard]] const std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> &getFunctionSymbolDataList() const { void addSectionInfo(std::unique_ptr<SectionInfo> sectionInfo) {
return symbol_data_list; mSectionInfoList[sectionInfo->getName()] = std::move(sectionInfo);
} }
void addSectionInfo(std::shared_ptr<SectionInfo> sectionInfo) { [[nodiscard]] const std::map<std::string, std::unique_ptr<SectionInfo>> &getSectionInfoList() const {
section_info_list[sectionInfo->getName()] = std::move(sectionInfo); return mSectionInfoList;
} }
[[nodiscard]] const std::map<std::string, std::shared_ptr<SectionInfo>> &getSectionInfoList() const { [[nodiscard]] SectionInfo *getSectionInfo(const std::string &sectionName) const {
return section_info_list;
}
[[nodiscard]] std::optional<std::shared_ptr<SectionInfo>> getSectionInfo(const std::string &sectionName) const {
if (getSectionInfoList().contains(sectionName)) { 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) { void setTrampolineId(uint8_t trampolineId) {
this->trampolineId = _trampolineId; this->mTrampolineId = trampolineId;
} }
[[nodiscard]] uint8_t getTrampolineId() const { [[nodiscard]] uint8_t getTrampolineId() const {
return trampolineId; return mTrampolineId;
} }
[[nodiscard]] std::optional<std::shared_ptr<FunctionSymbolData>> getNearestFunctionSymbolData(uint32_t address) const { [[nodiscard]] FunctionSymbolData *getNearestFunctionSymbolData(uint32_t address) const {
std::shared_ptr<FunctionSymbolData> result; FunctionSymbolData *result = nullptr;
bool foundHit = false; bool foundHit = false;
for (auto &cur : symbol_data_list) { for (auto &cur : mSymbolDataList) {
if (foundHit && address < (uint32_t) cur->getAddress()) { if (foundHit && address < (uint32_t) cur->getAddress()) {
break; break;
} }
if (address >= (uint32_t) cur->getAddress()) { if (address >= (uint32_t) cur->getAddress()) {
result = cur; result = cur.get();
foundHit = true; foundHit = true;
} }
} }
if (result) {
return result;
}
return {}; return result;
} }
void *getTextMemoryAddress() { [[nodiscard]] const HeapMemoryFixedSize &getTextMemory() const {
return allocatedTextMemoryAddress.get(); return mAllocatedTextMemoryAddress;
} }
void *getDataMemoryAddress() { [[nodiscard]] const HeapMemoryFixedSize &getDataMemory() const {
return allocatedDataMemoryAddress.get(); return mAllocatedDataMemoryAddress;
} }
private: private:
std::vector<std::unique_ptr<HookData>> hook_data_list; std::vector<std::unique_ptr<HookData>> mHookDataList;
std::vector<std::unique_ptr<FunctionData>> function_data_list; std::vector<std::unique_ptr<FunctionData>> mFunctionDataList;
std::vector<std::unique_ptr<RelocationData>> relocation_data_list; std::vector<std::unique_ptr<RelocationData>> mRelocationDataList;
std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> symbol_data_list; std::set<std::unique_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> mSymbolDataList;
std::map<std::string, std::shared_ptr<SectionInfo>> section_info_list; std::map<std::string, std::unique_ptr<SectionInfo>> mSectionInfoList;
uint8_t trampolineId = 0; uint8_t mTrampolineId = 0;
std::unique_ptr<uint8_t[]> allocatedTextMemoryAddress; HeapMemoryFixedSize mAllocatedTextMemoryAddress;
std::unique_ptr<uint8_t[]> allocatedDataMemoryAddress; HeapMemoryFixedSize mAllocatedDataMemoryAddress;
friend class PluginInformationFactory; friend class PluginInformationFactory;
}; };

View File

@ -18,6 +18,7 @@
#include "PluginInformationFactory.h" #include "PluginInformationFactory.h"
#include "../utils/ElfUtils.h" #include "../utils/ElfUtils.h"
#include "../utils/utils.h" #include "../utils/utils.h"
#include "utils/HeapMemoryFixedSize.h"
#include "utils/wiiu_zlib.hpp" #include "utils/wiiu_zlib.hpp"
#include <coreinit/cache.h> #include <coreinit/cache.h>
#include <map> #include <map>
@ -27,33 +28,34 @@
using namespace ELFIO; using namespace ELFIO;
std::optional<std::unique_ptr<PluginInformation>> std::unique_ptr<PluginInformation>
PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length, PluginInformationFactory::load(const PluginData &pluginData, std::vector<relocation_trampoline_entry_t> &trampolineData, uint8_t trampolineId) {
uint8_t trampolineId) { auto buffer = pluginData.getBuffer();
if (!pluginData->buffer) { if (buffer.empty()) {
DEBUG_FUNCTION_LINE_ERR("Buffer was nullptr"); DEBUG_FUNCTION_LINE_ERR("Buffer was empty");
return {}; return nullptr;
} }
elfio reader(new wiiu_zlib); 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"); DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
return {}; return nullptr;
} }
auto pluginInfo = make_unique_nothrow<PluginInformation>(); auto pluginInfo = make_unique_nothrow<PluginInformation>();
if (!pluginInfo) { if (!pluginInfo) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate PluginInformation"); DEBUG_FUNCTION_LINE_ERR("Failed to allocate PluginInformation");
return {}; return nullptr;
} }
uint32_t sec_num = reader.sections.size(); uint32_t sec_num = reader.sections.size();
auto destinations = make_unique_nothrow<uint8_t *[]>(sec_num); auto destinationsData = make_unique_nothrow<uint8_t *[]>(sec_num);
if (!destinations) { if (!destinationsData) {
DEBUG_FUNCTION_LINE_ERR("Failed alloc memory for destinations array"); 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; 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) { if (!text_data) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes)", text_size); DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes)", text_size);
return {}; return nullptr;
} }
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb", text_size / 1024); HeapMemoryFixedSize data_data(data_size);
auto data_data = make_unique_nothrow<uint8_t[]>(data_size);
if (!data_data) { if (!data_data) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .data section (%d bytes)", data_size); DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .data section (%d bytes)", data_size);
return {}; return nullptr;
} }
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb", data_size / 1024);
for (uint32_t i = 0; i < sec_num; ++i) { for (uint32_t i = 0; i < sec_num; ++i) {
section *psec = reader.sections[i]; section *psec = reader.sections[i];
if (psec->get_type() == 0x80000002 || psec->get_name() == ".wut_load_bounds") { 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; uint32_t destination = address;
if ((address >= 0x02000000) && address < 0x10000000) { if ((address >= 0x02000000) && address < 0x10000000) {
destination += (uint32_t) text_data.get(); destination += (uint32_t) text_data.data();
destination -= 0x02000000; 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) { 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.get() + 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"); OSFatal("WUPSLoader: Tried to overflow buffer");
} }
} else if ((address >= 0x10000000) && address < 0xC0000000) { } else if ((address >= 0x10000000) && address < 0xC0000000) {
destination += (uint32_t) data_data.get(); destination += (uint32_t) data_data.data();
destination -= 0x10000000; 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) { 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) data_data.get() + 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"); OSFatal("WUPSLoader: Tried to overflow buffer");
} }
} else if (address >= 0xC0000000) { } else if (address >= 0xC0000000) {
DEBUG_FUNCTION_LINE_ERR("Loading section from 0xC0000000 is NOT supported"); DEBUG_FUNCTION_LINE_ERR("Loading section from 0xC0000000 is NOT supported");
return std::nullopt; return nullptr;
} else { } else {
DEBUG_FUNCTION_LINE_ERR("Unhandled case"); DEBUG_FUNCTION_LINE_ERR("Unhandled case");
return std::nullopt; return nullptr;
} }
const char *p = psec->get_data(); 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); auto sectionInfo = make_unique_nothrow<SectionInfo>(psec->get_name(), destination, sectionSize);
if (!sectionInfo) { if (!sectionInfo) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocat SectionInfo"); DEBUG_FUNCTION_LINE_ERR("Failed to allocat SectionInfo");
return {}; return nullptr;
} }
pluginInfo->addSectionInfo(std::move(sectionInfo)); pluginInfo->addSectionInfo(std::move(sectionInfo));
@ -163,30 +161,30 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
section *psec = reader.sections[i]; section *psec = reader.sections[i];
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) { if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
DEBUG_FUNCTION_LINE_VERBOSE("Linking (%d)... %s at %08X", i, psec->get_name().c_str(), destinations[psec->get_index()]); DEBUG_FUNCTION_LINE_VERBOSE("Linking (%d)... %s at %08X", i, psec->get_name().c_str(), destinations[psec->get_index()]);
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], (uint32_t) text_data.get(), (uint32_t) data_data.get(), trampoline_data, trampoline_data_length, if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], (uint32_t) text_data.data(), (uint32_t) data_data.data(), trampolineData,
trampolineId)) { trampolineId)) {
DEBUG_FUNCTION_LINE_ERR("linkSection failed"); 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"); DEBUG_FUNCTION_LINE_ERR("addImportRelocationData failed");
return {}; return nullptr;
} }
DCFlushRange((void *) text_data.get(), text_size); DCFlushRange((void *) text_data.data(), text_data.size());
ICInvalidateRange((void *) text_data.get(), text_size); ICInvalidateRange((void *) text_data.data(), text_data.size());
DCFlushRange((void *) data_data.get(), data_size); DCFlushRange((void *) data_data.data(), data_data.size());
ICInvalidateRange((void *) data_data.get(), data_size); ICInvalidateRange((void *) data_data.data(), data_data.size());
pluginInfo->setTrampolineId(trampolineId); pluginInfo->setTrampolineId(trampolineId);
auto secInfo = pluginInfo->getSectionInfo(".wups.hooks"); auto secInfo = pluginInfo->getSectionInfo(".wups.hooks");
if (secInfo && secInfo.value()->getSize() > 0) { if (secInfo && secInfo->getSize() > 0) {
size_t entries_count = secInfo.value()->getSize() / sizeof(wups_loader_hook_t); size_t entries_count = secInfo->getSize() / sizeof(wups_loader_hook_t);
auto *entries = (wups_loader_hook_t *) secInfo.value()->getAddress(); auto *entries = (wups_loader_hook_t *) secInfo->getAddress();
if (entries != nullptr) { if (entries != nullptr) {
for (size_t j = 0; j < entries_count; j++) { for (size_t j = 0; j < entries_count; j++) {
wups_loader_hook_t *hook = &entries[j]; wups_loader_hook_t *hook = &entries[j];
@ -194,7 +192,7 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
auto hookData = make_unique_nothrow<HookData>((void *) hook->target, hook->type); auto hookData = make_unique_nothrow<HookData>((void *) hook->target, hook->type);
if (!hookData) { if (!hookData) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate HookData"); DEBUG_FUNCTION_LINE_ERR("Failed to allocate HookData");
return {}; return nullptr;
} }
pluginInfo->addHookData(std::move(hookData)); pluginInfo->addHookData(std::move(hookData));
} }
@ -202,14 +200,14 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
} }
secInfo = pluginInfo->getSectionInfo(".wups.load"); secInfo = pluginInfo->getSectionInfo(".wups.load");
if (secInfo && secInfo.value()->getSize() > 0) { if (secInfo && secInfo->getSize() > 0) {
size_t entries_count = secInfo.value()->getSize() / sizeof(wups_loader_entry_t); size_t entries_count = secInfo->getSize() / sizeof(wups_loader_entry_t);
auto *entries = (wups_loader_entry_t *) secInfo.value()->getAddress(); auto *entries = (wups_loader_entry_t *) secInfo->getAddress();
if (entries != nullptr) { if (entries != nullptr) {
for (size_t j = 0; j < entries_count; j++) { for (size_t j = 0; j < entries_count; j++) {
wups_loader_entry_t *cur_function = &entries[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", 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, cur_function->_function.physical_address, cur_function->_function.virtual_address, cur_function->_function.library, cur_function->_function.target,
(void *) cur_function->_function.call_addr); (void *) cur_function->_function.call_addr);
@ -222,7 +220,7 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
(FunctionPatcherTargetProcess) cur_function->_function.targetProcess); (FunctionPatcherTargetProcess) cur_function->_function.targetProcess);
if (!functionData) { if (!functionData) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate FunctionData"); DEBUG_FUNCTION_LINE_ERR("Failed to allocate FunctionData");
return {}; return nullptr;
} }
pluginInfo->addFunctionData(std::move(functionData)); 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 (symbols.get_symbol(j, name, value, size, bind, type, section, other)) {
if (type == STT_FUNC) { // We only care about functions. if (type == STT_FUNC) { // We only care about functions.
auto sectionVal = reader.sections[section]; auto sectionVal = reader.sections[section];
auto offsetVal = value - sectionVal->get_address(); auto offsetVal = value - sectionVal->get_address();
auto sectionOpt = pluginInfo->getSectionInfo(sectionVal->get_name()); auto sectionInfo = pluginInfo->getSectionInfo(sectionVal->get_name());
if (!sectionOpt.has_value()) { if (!sectionInfo) {
continue; continue;
} }
auto finalAddress = offsetVal + sectionOpt.value()->getAddress(); auto finalAddress = offsetVal + sectionInfo->getAddress();
auto functionSymbolData = make_unique_nothrow<FunctionSymbolData>(name, (void *) finalAddress, (uint32_t) size); auto functionSymbolData = make_unique_nothrow<FunctionSymbolData>(name, (void *) finalAddress, (uint32_t) size);
if (!functionSymbolData) { if (!functionSymbolData) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate FunctionSymbolData"); DEBUG_FUNCTION_LINE_ERR("Failed to allocate FunctionSymbolData");
return {}; return nullptr;
} }
pluginInfo->addFunctionSymbolData(std::move(functionSymbolData)); pluginInfo->addFunctionSymbolData(std::move(functionSymbolData));
} }
@ -272,17 +270,18 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, re
if (totalSize > text_size + data_size) { if (totalSize > text_size + data_size) {
DEBUG_FUNCTION_LINE_ERR("We didn't allocate enough memory!!"); 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 :) // Save the addresses for the allocated memory. This way we can free it again :)
pluginInfo->allocatedDataMemoryAddress = std::move(data_data); pluginInfo->mAllocatedDataMemoryAddress = std::move(data_data);
pluginInfo->allocatedTextMemoryAddress = std::move(text_data); pluginInfo->mAllocatedTextMemoryAddress = std::move(text_data);
return pluginInfo; 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; std::map<uint32_t, std::shared_ptr<ImportRPLInformation>> infoMap;
uint32_t sec_num = reader.sections.size(); uint32_t sec_num = reader.sections.size();
@ -352,16 +351,15 @@ bool PluginInformationFactory::addImportRelocationData(const std::unique_ptr<Plu
return false; return false;
} }
pluginInfo->addRelocationData(std::move(relocationData)); pluginInfo.addRelocationData(std::move(relocationData));
} }
} }
} }
return true; return true;
} }
bool PluginInformationFactory::linkSection(const elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data, bool PluginInformationFactory::linkSection(const elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data,
uint32_t trampoline_data_length, std::vector<relocation_trampoline_entry_t> &trampolineData, uint8_t trampolineId) {
uint8_t trampolineId) {
uint32_t sec_num = reader.sections.size(); uint32_t sec_num = reader.sections.size();
for (uint32_t i = 0; i < sec_num; ++i) { for (uint32_t i = 0; i < sec_num; ++i) {
@ -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); // 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"); DEBUG_FUNCTION_LINE_ERR("Link failed");
return false; return false;
} }

View File

@ -27,17 +27,15 @@
#include <vector> #include <vector>
#include <wums/defines/relocation_defines.h> #include <wums/defines/relocation_defines.h>
class PluginInformationFactory { class PluginInformationFactory {
public: public:
static std::optional<std::unique_ptr<PluginInformation>> static std::unique_ptr<PluginInformation>
load(const std::shared_ptr<PluginData> &pluginData, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length, load(const PluginData &pluginData, std::vector<relocation_trampoline_entry_t> &trampolineData, uint8_t trampolineId);
uint8_t trampolineId);
static bool 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, linkSection(const ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data,
uint32_t trampoline_data_length, std::vector<relocation_trampoline_entry_t> &trampolineData, uint8_t trampolineId);
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);
}; };

View File

@ -22,55 +22,34 @@
#include "utils/wiiu_zlib.hpp" #include "utils/wiiu_zlib.hpp"
#include <memory> #include <memory>
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const std::shared_ptr<PluginData> &pluginData, PluginParseErrors &error) { std::unique_ptr<PluginMetaInformation> PluginMetaInformationFactory::loadPlugin(const PluginData &pluginData, PluginParseErrors &error) {
if (!pluginData->buffer) { 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; error = PLUGIN_PARSE_ERROR_BUFFER_EMPTY;
DEBUG_FUNCTION_LINE_ERR("Buffer is empty"); DEBUG_FUNCTION_LINE_ERR("Buffer is empty");
return {}; return {};
} }
ELFIO::elfio reader(new wiiu_zlib); 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) { if (!reader.load(reinterpret_cast<const char *>(buffer.data()), buffer.size())) {
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)) {
error = PLUGIN_PARSE_ERROR_ELFIO_PARSE_FAILED; error = PLUGIN_PARSE_ERROR_ELFIO_PARSE_FAILED;
DEBUG_FUNCTION_LINE_ERR("Can't find or process ELF file"); DEBUG_FUNCTION_LINE_ERR("Can't find or process ELF file");
return std::nullopt; return nullptr;
} }
return loadPlugin(reader, error);
}
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const ELFIO::elfio &reader, PluginParseErrors &error) {
size_t pluginSize = 0; size_t pluginSize = 0;
auto pluginInfo = std::unique_ptr<PluginMetaInformation>(new PluginMetaInformation); auto pluginInfo = std::unique_ptr<PluginMetaInformation>(new PluginMetaInformation);
@ -127,7 +106,7 @@ std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFacto
if (value != "0.7.1") { if (value != "0.7.1") {
error = PLUGIN_PARSE_ERROR_INCOMPATIBLE_VERSION; error = PLUGIN_PARSE_ERROR_INCOMPATIBLE_VERSION;
DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring plugin - Unsupported WUPS version: %s.", value.c_str()); DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring plugin - Unsupported WUPS version: %s.", value.c_str());
return std::nullopt; return nullptr;
} }
} }
} }

View File

@ -36,11 +36,9 @@ enum PluginParseErrors {
class PluginMetaInformationFactory { class PluginMetaInformationFactory {
public: 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::unique_ptr<PluginMetaInformation> loadPlugin(std::span<const uint8_t> buffer, PluginParseErrors &error);
static std::optional<std::unique_ptr<PluginMetaInformation>> loadPlugin(const ELFIO::elfio &reader, PluginParseErrors &error);
}; };

View File

@ -57,8 +57,8 @@ public:
return name; return name;
} }
[[nodiscard]] const std::shared_ptr<ImportRPLInformation> &getImportRPLInformation() const { [[nodiscard]] const ImportRPLInformation &getImportRPLInformation() const {
return rplInfo; return *rplInfo;
} }
private: private:

View File

@ -122,12 +122,11 @@ void ConfigUtils::displayMenu() {
std::vector<ConfigDisplayItem> configs; std::vector<ConfigDisplayItem> configs;
for (auto &plugin : gLoadedPlugins) { for (auto &plugin : gLoadedPlugins) {
ConfigDisplayItem cfg; ConfigDisplayItem cfg;
cfg.name = plugin->metaInformation->getName(); cfg.name = plugin->getMetaInformation().getName();
cfg.author = plugin->metaInformation->getAuthor(); cfg.author = plugin->getMetaInformation().getAuthor();
cfg.version = plugin->metaInformation->getVersion(); cfg.version = plugin->getMetaInformation().getVersion();
for (auto &hook : plugin->getPluginInformation()->getHookDataList()) {
for (const auto &hook : plugin->getPluginInformation().getHookDataList()) {
if (hook->getType() == WUPS_LOADER_HOOK_GET_CONFIG /*WUPS_LOADER_HOOK_GET_CONFIG*/) { if (hook->getType() == WUPS_LOADER_HOOK_GET_CONFIG /*WUPS_LOADER_HOOK_GET_CONFIG*/) {
if (hook->getFunctionPointer() == nullptr) { if (hook->getFunctionPointer() == nullptr) {
break; break;

View File

@ -1,13 +1,14 @@
#include <coreinit/cache.h> #include <coreinit/cache.h>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <vector>
#include "ElfUtils.h" #include "ElfUtils.h"
#include "utils/logger.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 // 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, bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr,
RelocationType reloc_type, uint8_t trampolineId) { std::vector<relocation_trampoline_entry_t> &trampolineData, RelocationType reloc_type, uint8_t trampolineId) {
if (type == R_PPC_NONE) { if (type == R_PPC_NONE) {
return true; 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); auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) { 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("***24-bit relative branch cannot hit target. Trampoline isn't provided");
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, distance); DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, distance);
return false; return false;
} else { } else {
relocation_trampoline_entry_t *freeSlot = nullptr; 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 // We want to override "old" relocations of imports
// Pending relocations have the status RELOC_TRAMP_IMPORT_IN_PROGRESS. // 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 // 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. // 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. // 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) { if (cur.status == RELOC_TRAMP_FREE) {
freeSlot = &(trampoline_data[i]); freeSlot = &cur;
break; break;
} }
} }

View File

@ -46,6 +46,6 @@ uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fi
class ElfUtils { class ElfUtils {
public: 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); RelocationType reloc_type, uint8_t trampolineId);
}; };

View 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{};
};

View File

@ -122,7 +122,7 @@ WUPSStorageError StorageUtils::CloseStorage(const char *plugin_id, wups_storage_
std::string folderPath = getPluginPath() + "/config/"; std::string folderPath = getPluginPath() + "/config/";
std::string filePath = folderPath + plugin_id + ".json"; std::string filePath = folderPath + plugin_id + ".json";
FSUtils::CreateSubfolder(folderPath.c_str()); FSUtils::CreateSubfolder(folderPath);
CFile file(filePath, CFile::WriteOnly); CFile file(filePath, CFile::WriteOnly);
if (!file.isOpen()) { if (!file.isOpen()) {

View File

@ -34,8 +34,8 @@
#include <wut_types.h> #include <wut_types.h>
template<typename... Args> template<typename... Args>
std::string string_format(const std::string &format, Args... args) { std::string string_format(std::string_view format, Args... args) {
int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0' int size_s = std::snprintf(nullptr, 0, format.data(), args...) + 1; // Extra space for '\0'
auto size = static_cast<size_t>(size_s); auto size = static_cast<size_t>(size_s);
auto buf = make_unique_nothrow<char[]>(size); auto buf = make_unique_nothrow<char[]>(size);
if (!buf) { if (!buf) {
@ -43,11 +43,10 @@ std::string string_format(const std::string &format, Args... args) {
OSFatal("string_format failed, not enough memory"); OSFatal("string_format failed, not enough memory");
return std::string(""); 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 return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
} }
class StringTools { class StringTools {
public: public:
static std::string truncate(const std::string &str, size_t width, bool show_ellipsis = true); static std::string truncate(const std::string &str, size_t width, bool show_ellipsis = true);

View File

@ -6,35 +6,36 @@
#include "utils.h" #include "utils.h"
#include <wums.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; out->plugin_information_version = PLUGIN_INFORMATION_VERSION;
strncpy(out->author, metaInformation->getAuthor().c_str(), sizeof(out->author) - 1); strncpy(out->author, metaInformation.getAuthor().c_str(), sizeof(out->author) - 1);
strncpy(out->buildTimestamp, metaInformation->getBuildTimestamp().c_str(), sizeof(out->buildTimestamp) - 1); strncpy(out->buildTimestamp, metaInformation.getBuildTimestamp().c_str(), sizeof(out->buildTimestamp) - 1);
strncpy(out->description, metaInformation->getDescription().c_str(), sizeof(out->description) - 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->name, metaInformation.getName().c_str(), sizeof(out->name) - 1);
strncpy(out->license, metaInformation->getLicense().c_str(), sizeof(out->license) - 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->version, metaInformation.getVersion().c_str(), sizeof(out->version) - 1);
strncpy(out->storageId, metaInformation->getStorageId().c_str(), sizeof(out->storageId) - 1); strncpy(out->storageId, metaInformation.getStorageId().c_str(), sizeof(out->storageId) - 1);
out->size = metaInformation->getSize(); out->size = metaInformation.getSize();
} }
extern "C" PluginBackendApiErrorType WUPSLoadAndLinkByDataHandle(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size) { extern "C" PluginBackendApiErrorType WUPSLoadAndLinkByDataHandle(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size) {
if (plugin_data_handle_list == nullptr || plugin_data_handle_list_size == 0) { if (plugin_data_handle_list == nullptr || plugin_data_handle_list_size == 0) {
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG; return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
} }
std::lock_guard<std::mutex> lock(gLoadedDataMutex); std::lock_guard<std::mutex> lock(gLoadedDataMutex);
for (uint32_t i = 0; i < plugin_data_handle_list_size; i++) { for (uint32_t i = 0; i < plugin_data_handle_list_size; i++) {
auto handle = plugin_data_handle_list[i]; auto handle = plugin_data_handle_list[i];
bool found = false; bool found = false;
for (auto &pluginData : gLoadedData) { for (const auto &pluginData : gLoadedData) {
if (pluginData->getHandle() == handle) { if (pluginData->getHandle() == handle) {
gLoadOnNextLaunch.push_front(pluginData); gLoadOnNextLaunch.insert(pluginData);
found = true; found = true;
break; break;
} }
} }
if (!found) { if (!found) {
DEBUG_FUNCTION_LINE_ERR("Failed to get plugin data for handle %08X. Skipping it.", handle); 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) { 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) { if (plugin_data_handle_list != nullptr && plugin_data_handle_list_size != 0) {
for (uint32_t i = 0; i < plugin_data_handle_list_size; i++) { for (auto &handle : std::span(plugin_data_handle_list, plugin_data_handle_list_size)) {
auto handle = plugin_data_handle_list[i];
if (!remove_locked_first_if(gLoadedDataMutex, gLoadedData, [handle](auto &cur) { return cur->getHandle() == handle; })) { 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); 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; 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) { if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) {
pluginData = PluginDataFactory::load(path); pluginData = PluginDataFactory::load(path);
} else if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_BUFFER && buffer != nullptr && size > 0) { } else if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_BUFFER && buffer != nullptr && size > 0) {
std::vector<uint8_t> data(size); pluginData = make_unique_nothrow<PluginData>(std::span((uint8_t *) buffer, size), "<UNKNOWN>");
memcpy(&data[0], buffer, size);
pluginData = PluginDataFactory::load(data, "<UNKNOWN>");
} else { } else {
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG; return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
} }
@ -75,11 +72,9 @@ extern "C" PluginBackendApiErrorType WUPSLoadPluginAsData(GetPluginInformationIn
if (!pluginData) { if (!pluginData) {
DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_FAILED_ALLOC"); DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_FAILED_ALLOC");
return PLUGIN_BACKEND_API_ERROR_FAILED_ALLOC; return PLUGIN_BACKEND_API_ERROR_FAILED_ALLOC;
} } else {
*out = pluginData->getHandle();
else { gLoadedData.insert(std::move(pluginData));
*out = pluginData.value()->getHandle();
gLoadedData.push_front(std::move(pluginData.value()));
} }
return PLUGIN_BACKEND_API_ERROR_NONE; 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) { 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; PluginParseErrors error = PLUGIN_PARSE_ERROR_UNKNOWN;
if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) { if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) {
std::string pathStr(path); pluginInfo = PluginMetaInformationFactory::loadPlugin(path, error);
pluginInfo = PluginMetaInformationFactory::loadPlugin(pathStr, error);
} else if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_BUFFER && buffer != nullptr && size > 0) { } 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 { } else {
DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_INVALID_ARG"); DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_INVALID_ARG");
return 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"); DEBUG_FUNCTION_LINE_ERR("PLUGIN_BACKEND_API_ERROR_FILE_NOT_FOUND");
return 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; return PLUGIN_BACKEND_API_ERROR_NONE;
} }
@ -135,21 +129,21 @@ extern "C" PluginBackendApiErrorType WUPSGetPluginDataForContainerHandles(const
} }
std::lock_guard<std::mutex> lock(gLoadedDataMutex); 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]; auto handle = plugin_container_handle_list[i];
bool found = false; bool found = false;
for (auto &curContainer : gLoadedPlugins) { for (const auto &curContainer : gLoadedPlugins) {
if (curContainer->getHandle() == handle) { if (curContainer->getHandle() == handle) {
auto &pluginData = curContainer->getPluginData(); auto pluginData = curContainer->getPluginDataCopy();
plugin_data_list[i] = (uint32_t) pluginData->getHandle(); plugin_data_list[i] = (uint32_t) pluginData->getHandle();
gLoadedData.push_front(pluginData); gLoadedData.insert(std::move(pluginData));
found = true; found = true;
i++;
break; break;
} }
} }
if (!found) { if (!found) {
DEBUG_FUNCTION_LINE_ERR("Failed to get container for handle %08X", handle); 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++) { for (uint32_t i = 0; i < buffer_size; i++) {
auto handle = plugin_container_handle_list[i]; auto handle = plugin_container_handle_list[i];
bool found = false; bool found = false;
for (auto &curContainer : gLoadedPlugins) { for (const auto &curContainer : gLoadedPlugins) {
if (curContainer->getHandle() == handle) { if (curContainer->getHandle() == handle) {
auto &metaInfo = curContainer->getMetaInformation(); const auto &metaInfo = curContainer->getMetaInformation();
plugin_information_list[i].plugin_information_version = PLUGIN_INFORMATION_VERSION; plugin_information_list[i].plugin_information_version = PLUGIN_INFORMATION_VERSION;
strncpy(plugin_information_list[i].storageId, metaInfo->getStorageId().c_str(), sizeof(plugin_information_list[i].storageId) - 1); strncpy(plugin_information_list[i].storageId, metaInfo.getStorageId().c_str(), sizeof(plugin_information_list[i].storageId) - 1);
strncpy(plugin_information_list[i].author, metaInfo->getAuthor().c_str(), sizeof(plugin_information_list[i].author) - 1); strncpy(plugin_information_list[i].author, metaInfo.getAuthor().c_str(), sizeof(plugin_information_list[i].author) - 1);
strncpy(plugin_information_list[i].buildTimestamp, metaInfo->getBuildTimestamp().c_str(), sizeof(plugin_information_list[i].buildTimestamp) - 1); strncpy(plugin_information_list[i].buildTimestamp, metaInfo.getBuildTimestamp().c_str(), sizeof(plugin_information_list[i].buildTimestamp) - 1);
strncpy(plugin_information_list[i].description, metaInfo->getDescription().c_str(), sizeof(plugin_information_list[i].description) - 1); strncpy(plugin_information_list[i].description, metaInfo.getDescription().c_str(), sizeof(plugin_information_list[i].description) - 1);
strncpy(plugin_information_list[i].name, metaInfo->getName().c_str(), sizeof(plugin_information_list[i].name) - 1); strncpy(plugin_information_list[i].name, metaInfo.getName().c_str(), sizeof(plugin_information_list[i].name) - 1);
strncpy(plugin_information_list[i].license, metaInfo->getLicense().c_str(), sizeof(plugin_information_list[i].license) - 1); strncpy(plugin_information_list[i].license, metaInfo.getLicense().c_str(), sizeof(plugin_information_list[i].license) - 1);
strncpy(plugin_information_list[i].version, metaInfo->getVersion().c_str(), sizeof(plugin_information_list[i].version) - 1); strncpy(plugin_information_list[i].version, metaInfo.getVersion().c_str(), sizeof(plugin_information_list[i].version) - 1);
plugin_information_list[i].size = metaInfo->getSize(); plugin_information_list[i].size = metaInfo.getSize();
found = true; found = true;
break; break;
@ -196,9 +190,8 @@ extern "C" PluginBackendApiErrorType WUPSGetLoadedPlugins(plugin_container_handl
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG; return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
} }
*plugin_information_version = PLUGIN_INFORMATION_VERSION; *plugin_information_version = PLUGIN_INFORMATION_VERSION;
auto &plugins = gLoadedPlugins;
uint32_t counter = 0; uint32_t counter = 0;
for (auto &plugin : plugins) { for (const auto &plugin : gLoadedPlugins) {
if (counter < buffer_size) { if (counter < buffer_size) {
io_handles[counter] = plugin->getHandle(); io_handles[counter] = plugin->getHandle();
counter++; counter++;
@ -248,10 +241,10 @@ extern "C" PluginBackendApiErrorType WUPSGetSectionInformationForPlugin(const pl
} }
if (handle != 0 && plugin_section_list != nullptr && buffer_size != 0) { if (handle != 0 && plugin_section_list != nullptr && buffer_size != 0) {
bool found = false; bool found = false;
for (auto &curContainer : gLoadedPlugins) { for (const auto &curContainer : gLoadedPlugins) {
if (curContainer->getHandle() == handle) { if (curContainer->getHandle() == handle) {
found = true; found = true;
auto &sectionInfoList = curContainer->getPluginInformation()->getSectionInfoList(); const auto &sectionInfoList = curContainer->getPluginInformation().getSectionInfoList();
uint32_t offset = 0; uint32_t offset = 0;
for (auto const &[key, sectionInfo] : sectionInfoList) { for (auto const &[key, sectionInfo] : sectionInfoList) {
@ -292,10 +285,10 @@ extern "C" PluginBackendApiErrorType WUPSGetSectionMemoryAddresses(plugin_contai
if (handle == 0 || textAddress == nullptr || dataAddress == nullptr) { if (handle == 0 || textAddress == nullptr || dataAddress == nullptr) {
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG; return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
} }
for (auto &curContainer : gLoadedPlugins) { for (const auto &curContainer : gLoadedPlugins) {
if (curContainer->getHandle() == handle) { if (curContainer->getHandle() == handle) {
*textAddress = curContainer->getPluginInformation()->getTextMemoryAddress(); *textAddress = (void *) curContainer->getPluginInformation().getTextMemory().data();
*dataAddress = curContainer->getPluginInformation()->getDataMemoryAddress(); *dataAddress = (void *) curContainer->getPluginInformation().getDataMemory().data();
return PLUGIN_BACKEND_API_ERROR_NONE; return PLUGIN_BACKEND_API_ERROR_NONE;
} }
} }

View File

@ -1,11 +1,13 @@
#pragma once #pragma once
#include <algorithm>
#include <coreinit/dynload.h> #include <coreinit/dynload.h>
#include <cstdint> #include <cstdint>
#include <forward_list> #include <forward_list>
#include <malloc.h> #include <malloc.h>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <set>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { 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)...)); return std::shared_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
} }
template<typename T, class Allocator, class Predicate> template<typename Container, typename Predicate>
bool remove_locked_first_if(std::mutex &mutex, std::forward_list<T, Allocator> &list, Predicate pred) { bool remove_locked_first_if(std::mutex &mutex, Container &container, Predicate pred) {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
auto oit = list.before_begin(), it = std::next(oit);
while (it != list.end()) { auto it = std::find_if(container.begin(), container.end(), pred);
if (pred(*it)) { if (it != container.end()) {
list.erase_after(oit); container.erase(it);
return true; return true;
}
oit = it++;
} }
return false; return false;
} }