mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2026-08-20 01:51:58 -05:00
Rewrite the plugin backend, use smart pointers is possible, don't persist in structs and simplify code
This commit is contained in:
@@ -1,107 +0,0 @@
|
||||
#include "DynamicLinkingHelper.h"
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
dyn_linking_function_t *DynamicLinkingHelper::getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName) {
|
||||
if (data == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("data was NULL");
|
||||
return nullptr;
|
||||
}
|
||||
if (functionName == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("functionName was NULL");
|
||||
return nullptr;
|
||||
}
|
||||
dyn_linking_function_t *result = nullptr;
|
||||
for (auto &curEntry : data->functions) {
|
||||
if (strlen(curEntry.functionName) == 0) {
|
||||
if (strlen(functionName) > DYN_LINK_FUNCTION_NAME_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to add function name, it's too long.");
|
||||
return nullptr;
|
||||
}
|
||||
strncpy(curEntry.functionName, functionName, DYN_LINK_FUNCTION_NAME_LENGTH);
|
||||
result = &curEntry;
|
||||
break;
|
||||
}
|
||||
if (strncmp(curEntry.functionName, functionName, DYN_LINK_FUNCTION_NAME_LENGTH) == 0) {
|
||||
result = &curEntry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
dyn_linking_import_t *DynamicLinkingHelper::getOrAddFunctionImportByName(dyn_linking_relocation_data_t *data, const char *importName) {
|
||||
return getOrAddImport(data, importName, false);
|
||||
}
|
||||
|
||||
dyn_linking_import_t *DynamicLinkingHelper::getOrAddDataImportByName(dyn_linking_relocation_data_t *data, const char *importName) {
|
||||
return getOrAddImport(data, importName, true);
|
||||
}
|
||||
|
||||
dyn_linking_import_t *DynamicLinkingHelper::getOrAddImport(dyn_linking_relocation_data_t *data, const char *importName, bool isData) {
|
||||
if (importName == nullptr || data == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
dyn_linking_import_t *result = nullptr;
|
||||
for (auto &curEntry : data->imports) {
|
||||
if (strlen(curEntry.importName) == 0) {
|
||||
if (strlen(importName) > DYN_LINK_IMPORT_NAME_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to add Import, it's too long.");
|
||||
return nullptr;
|
||||
}
|
||||
strncpy(curEntry.importName, importName, DYN_LINK_IMPORT_NAME_LENGTH);
|
||||
curEntry.isData = isData;
|
||||
result = &curEntry;
|
||||
break;
|
||||
}
|
||||
if (strncmp(curEntry.importName, importName, DYN_LINK_IMPORT_NAME_LENGTH) == 0 && (curEntry.isData == isData)) {
|
||||
return &curEntry;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DynamicLinkingHelper::addReloationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length,
|
||||
const std::shared_ptr<RelocationData> &relocationData) {
|
||||
return addReloationEntry(linking_data, linking_entries, linking_entry_length, relocationData->getType(), relocationData->getOffset(), relocationData->getAddend(), relocationData->getDestination(),
|
||||
relocationData->getName(),
|
||||
relocationData->getImportRPLInformation());
|
||||
}
|
||||
|
||||
bool DynamicLinkingHelper::addReloationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset,
|
||||
int32_t addend, const void *destination,
|
||||
const std::string &name, const std::shared_ptr<ImportRPLInformation> &rplInfo) {
|
||||
dyn_linking_import_t *importInfoGbl = DynamicLinkingHelper::getOrAddImport(linking_data, rplInfo->getName().c_str(), rplInfo->isData());
|
||||
if (importInfoGbl == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Getting import info failed. Probably maximum of %d rpl files to import reached.", DYN_LINK_IMPORT_LIST_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
dyn_linking_function_t *functionInfo = DynamicLinkingHelper::getOrAddFunctionEntryByName(linking_data, name.c_str());
|
||||
if (functionInfo == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Getting import info failed. Probably maximum of %d function to be relocated reached.", DYN_LINK_FUNCTION_LIST_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
return addReloationEntry(linking_entries, linking_entry_length, type, offset, addend, destination, functionInfo, importInfoGbl);
|
||||
}
|
||||
|
||||
bool DynamicLinkingHelper::addReloationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, const void *destination,
|
||||
dyn_linking_function_t *functionName,
|
||||
dyn_linking_import_t *importInfo) {
|
||||
for (uint32_t i = 0; i < linking_entry_length; i++) {
|
||||
dyn_linking_relocation_entry_t *curEntry = &(linking_entries[i]);
|
||||
if (curEntry->functionEntry != nullptr) {
|
||||
continue;
|
||||
}
|
||||
curEntry->type = type;
|
||||
curEntry->offset = offset;
|
||||
curEntry->addend = addend;
|
||||
curEntry->destination = (void *) destination;
|
||||
curEntry->functionEntry = functionName;
|
||||
curEntry->importEntry = importInfo;
|
||||
return true;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to find empty slot for saving relocations entry. We need more than %d slots.", linking_entry_length);
|
||||
return false;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "RelocationData.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wums/defines/dynamic_linking_defines.h>
|
||||
|
||||
class DynamicLinkingHelper {
|
||||
public:
|
||||
/**
|
||||
Gets the function entry for a given function name. If the function name is not present in the list, it will be added.
|
||||
|
||||
\param functionName Name of the function
|
||||
\return Returns a pointer to the entry which contains the functionName. Null on error or if the list full.
|
||||
**/
|
||||
static dyn_linking_function_t *getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName);
|
||||
|
||||
/**
|
||||
Gets the function import entry for a given function name. If the import is not present in the list, it will be added.
|
||||
This will return entries for _function_ imports.
|
||||
|
||||
\param importName Name of the function
|
||||
\return Returns a pointer to the function import entry which contains the importName. Null on error or if the list full.
|
||||
**/
|
||||
static dyn_linking_import_t *getOrAddFunctionImportByName(dyn_linking_relocation_data_t *data, const char *importName);
|
||||
|
||||
|
||||
/**
|
||||
Gets the data import entry for a given data name. If the import is not present in the list, it will be added.
|
||||
This will return entries for _data_ imports.
|
||||
|
||||
\param importName Name of the data
|
||||
\return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full.
|
||||
**/
|
||||
static dyn_linking_import_t *getOrAddDataImportByName(dyn_linking_relocation_data_t *data, const char *importName);
|
||||
|
||||
|
||||
/**
|
||||
Gets the import entry for a given data name and type. If the import is not present in the list, it will be added.
|
||||
This will return entries for _data_ and _function_ imports, depending on the isData parameter.
|
||||
|
||||
\param importName Name of the data
|
||||
\param isData Set this to true to return a data import
|
||||
|
||||
\return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full.
|
||||
**/
|
||||
static dyn_linking_import_t *getOrAddImport(dyn_linking_relocation_data_t *data, const char *importName, bool isData);
|
||||
|
||||
static bool addReloationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length,
|
||||
const std::shared_ptr<RelocationData> &relocationData);
|
||||
|
||||
static bool
|
||||
addReloationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend,
|
||||
const void *destination, const std::string &name,
|
||||
const std::shared_ptr<ImportRPLInformation> &rplInfo);
|
||||
|
||||
static bool addReloationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, const void *destination,
|
||||
dyn_linking_function_t *functionName,
|
||||
dyn_linking_import_t *importInfo);
|
||||
|
||||
private:
|
||||
DynamicLinkingHelper() = default;
|
||||
|
||||
~DynamicLinkingHelper() = default;
|
||||
};
|
||||
@@ -16,17 +16,19 @@
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "utils/logger.h"
|
||||
#include <function_patcher/fpatching_defines.h>
|
||||
#include <function_patcher/function_patching.h>
|
||||
#include <string>
|
||||
|
||||
class FunctionData {
|
||||
|
||||
public:
|
||||
FunctionData(void *paddress, void *vaddress, const std::string &name, function_replacement_library_type_t library, void *replaceAddr, void *replaceCall,
|
||||
FunctionData(void *paddress, void *vaddress, std::string name, function_replacement_library_type_t library, void *replaceAddr, void *replaceCall,
|
||||
FunctionPatcherTargetProcess targetProcess) {
|
||||
this->paddress = paddress;
|
||||
this->vaddress = vaddress;
|
||||
this->name = name;
|
||||
this->name = std::move(name);
|
||||
this->library = library;
|
||||
this->targetProcess = targetProcess;
|
||||
this->replaceAddr = replaceAddr;
|
||||
@@ -63,6 +65,42 @@ public:
|
||||
return targetProcess;
|
||||
}
|
||||
|
||||
bool patch() {
|
||||
if (handle == 0) {
|
||||
function_replacement_data_t functionData = {
|
||||
.VERSION = FUNCTION_REPLACEMENT_DATA_STRUCT_VERSION,
|
||||
.physicalAddr = reinterpret_cast<uint32_t>(this->paddress),
|
||||
.virtualAddr = reinterpret_cast<uint32_t>(this->vaddress),
|
||||
.replaceAddr = reinterpret_cast<uint32_t>(this->replaceAddr),
|
||||
.replaceCall = static_cast<uint32_t *>(this->replaceCall),
|
||||
.library = this->library,
|
||||
.function_name = this->name.c_str(),
|
||||
.targetProcess = this->targetProcess};
|
||||
|
||||
if (!FunctionPatcherPatchFunction(&functionData, &handle)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to patch function");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Function is already patched");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool restore() {
|
||||
if (handle != 0) {
|
||||
if (!FunctionPatcherRestoreFunction(handle)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to restore function patch");
|
||||
return false;
|
||||
}
|
||||
handle = 0;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Was not patched.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void *paddress = nullptr;
|
||||
void *vaddress = nullptr;
|
||||
@@ -71,4 +109,6 @@ private:
|
||||
FunctionPatcherTargetProcess targetProcess;
|
||||
void *replaceAddr = nullptr;
|
||||
void *replaceCall = nullptr;
|
||||
|
||||
PatchedFunctionHandle handle = 0;
|
||||
};
|
||||
|
||||
@@ -24,22 +24,24 @@
|
||||
class ImportRPLInformation {
|
||||
|
||||
public:
|
||||
explicit ImportRPLInformation(std::string name, bool isData = false) {
|
||||
this->name = std::move(name);
|
||||
this->_isData = isData;
|
||||
explicit ImportRPLInformation(std::string name) {
|
||||
this->name = std::move(name);
|
||||
}
|
||||
|
||||
~ImportRPLInformation() = default;
|
||||
|
||||
[[nodiscard]] std::string getName() const {
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getRPLName() const {
|
||||
return name.substr(strlen(".dimport_"));
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isData() const {
|
||||
return _isData;
|
||||
return name.starts_with(".dimport_");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
bool _isData = false;
|
||||
};
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2020 Maschell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
* Copyright (C) 2020 Maschell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -21,42 +21,33 @@
|
||||
#include "PluginInformation.h"
|
||||
#include "PluginMetaInformation.h"
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
class PluginContainer {
|
||||
public:
|
||||
PluginContainer(const PluginContainer &other) {
|
||||
this->pluginData = other.pluginData;
|
||||
this->pluginInformation = other.pluginInformation;
|
||||
this->metaInformation = other.metaInformation;
|
||||
PluginContainer(std::unique_ptr<PluginMetaInformation> metaInformation, std::unique_ptr<PluginInformation> pluginInformation, std::shared_ptr<PluginData> pluginData)
|
||||
: metaInformation(std::move(metaInformation)),
|
||||
pluginInformation(std::move(pluginInformation)),
|
||||
pluginData(std::move(pluginData)) {
|
||||
}
|
||||
|
||||
PluginContainer() = default;
|
||||
|
||||
[[nodiscard]] const std::shared_ptr<PluginMetaInformation> &getMetaInformation() const {
|
||||
[[nodiscard]] const std::unique_ptr<PluginMetaInformation> &getMetaInformation() const {
|
||||
return this->metaInformation;
|
||||
}
|
||||
|
||||
void setMetaInformation(const std::shared_ptr<PluginMetaInformation> &metaInfo) {
|
||||
this->metaInformation = metaInfo;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::shared_ptr<PluginInformation> &getPluginInformation() const {
|
||||
[[nodiscard]] const std::unique_ptr<PluginInformation> &getPluginInformation() const {
|
||||
return pluginInformation;
|
||||
}
|
||||
|
||||
void setPluginInformation(const std::shared_ptr<PluginInformation> &_pluginInformation) {
|
||||
this->pluginInformation = _pluginInformation;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::shared_ptr<PluginData> &getPluginData() const {
|
||||
return pluginData;
|
||||
}
|
||||
|
||||
void setPluginData(const std::shared_ptr<PluginData> &_pluginData) {
|
||||
this->pluginData = _pluginData;
|
||||
uint32_t getHandle() {
|
||||
return (uint32_t) this;
|
||||
}
|
||||
|
||||
std::shared_ptr<PluginData> pluginData;
|
||||
std::shared_ptr<PluginMetaInformation> metaInformation;
|
||||
std::shared_ptr<PluginInformation> pluginInformation;
|
||||
const std::unique_ptr<PluginMetaInformation> metaInformation;
|
||||
const std::unique_ptr<PluginInformation> pluginInformation;
|
||||
const std::shared_ptr<PluginData> pluginData;
|
||||
};
|
||||
|
||||
@@ -1,348 +0,0 @@
|
||||
#include <coreinit/cache.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "DynamicLinkingHelper.h"
|
||||
#include "PluginContainer.h"
|
||||
#include "PluginContainerPersistence.h"
|
||||
#include "PluginDataPersistence.h"
|
||||
#include "PluginInformationFactory.h"
|
||||
#include "PluginMetaInformationFactory.h"
|
||||
|
||||
bool PluginContainerPersistence::savePlugin(plugin_information_t *pluginInformation, const std::shared_ptr<PluginContainer> &plugin, MEMHeapHandle heapHandle) {
|
||||
int32_t plugin_count = pluginInformation->number_used_plugins;
|
||||
|
||||
auto pluginName = plugin->getMetaInformation()->getName();
|
||||
|
||||
if (plugin_count >= MAXIMUM_PLUGINS - 1) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Maximum of %d plugins reached. %s won't be loaded!", MAXIMUM_PLUGINS, pluginName.c_str());
|
||||
return false;
|
||||
}
|
||||
// Copy data to global struct.
|
||||
plugin_information_single_t *plugin_data = &(pluginInformation->plugin_data[plugin_count]);
|
||||
|
||||
// Make sure everything is reset.
|
||||
memset((void *) plugin_data, 0, sizeof(plugin_information_single_t));
|
||||
|
||||
const auto &pluginMetaInfo = plugin->getMetaInformation();
|
||||
auto plugin_meta_data = &plugin_data->meta;
|
||||
|
||||
if (pluginMetaInfo->getName().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Warning: name will be truncated.");
|
||||
}
|
||||
strncpy(plugin_meta_data->name, pluginMetaInfo->getName().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
||||
if (pluginMetaInfo->getAuthor().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Warning: author will be truncated.");
|
||||
}
|
||||
strncpy(plugin_meta_data->author, pluginMetaInfo->getAuthor().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
||||
|
||||
if (pluginMetaInfo->getVersion().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Warning: version will be truncated.");
|
||||
}
|
||||
strncpy(plugin_meta_data->version, pluginMetaInfo->getVersion().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
||||
|
||||
if (pluginMetaInfo->getLicense().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Warning: license will be truncated.");
|
||||
}
|
||||
strncpy(plugin_meta_data->license, pluginMetaInfo->getLicense().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
||||
|
||||
if (pluginMetaInfo->getBuildTimestamp().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Warning: build timestamp will be truncated.");
|
||||
}
|
||||
strncpy(plugin_meta_data->buildTimestamp, pluginMetaInfo->getBuildTimestamp().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
||||
|
||||
if (pluginMetaInfo->getDescription().size() >= MAXIMUM_PLUGIN_DESCRIPTION_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Warning: description will be truncated.");
|
||||
DEBUG_FUNCTION_LINE_ERR("%s", pluginMetaInfo->getDescription().c_str());
|
||||
}
|
||||
strncpy(plugin_meta_data->descripion, pluginMetaInfo->getDescription().c_str(), MAXIMUM_PLUGIN_DESCRIPTION_LENGTH - 1);
|
||||
|
||||
if (pluginMetaInfo->getStorageId().length() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Warning: plugin storage id will be truncated.");
|
||||
}
|
||||
strncpy(plugin_meta_data->storageId, pluginMetaInfo->getStorageId().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
||||
|
||||
plugin_meta_data->size = pluginMetaInfo->getSize();
|
||||
|
||||
auto pluginInfo = plugin->getPluginInformation();
|
||||
|
||||
// Relocation
|
||||
auto relocationData = pluginInfo->getRelocationDataList();
|
||||
for (auto &reloc : relocationData) {
|
||||
if (!DynamicLinkingHelper::addReloationEntry(&(pluginInformation->linking_data), plugin_data->info.linking_entries, PLUGIN_DYN_LINK_RELOCATION_LIST_LENGTH, reloc)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to add a relocation entry");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto function_data_list = pluginInfo->getFunctionDataList();
|
||||
auto hook_data_list = pluginInfo->getHookDataList();
|
||||
|
||||
if (function_data_list.size() > MAXIMUM_FUNCTION_PER_PLUGIN) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Plugin %s would replace to many function (%d, maximum is %d). It won't be loaded.", pluginName.c_str(), function_data_list.size(), MAXIMUM_FUNCTION_PER_PLUGIN);
|
||||
return false;
|
||||
}
|
||||
if (hook_data_list.size() > MAXIMUM_HOOKS_PER_PLUGIN) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Plugin %s would set too many hooks (%d, maximum is %d). It won't be loaded.", pluginName.c_str(), hook_data_list.size(), MAXIMUM_HOOKS_PER_PLUGIN);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pluginName.length() > MAXIMUM_PLUGIN_NAME_LENGTH - 1) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Name for plugin %s was too long to be stored.", pluginName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Store function replacement information */
|
||||
uint32_t i = 0;
|
||||
for (auto &curFunction : pluginInfo->getFunctionDataList()) {
|
||||
function_replacement_data_t *function_data = &plugin_data->info.functions[i];
|
||||
if (strlen(curFunction->getName().c_str()) > MAXIMUM_FUNCTION_NAME_LENGTH - 1) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Could not add function \"%s\" for plugin \"%s\" function name is too long.", curFunction->getName().c_str(), pluginName.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Adding function \"%s\" for plugin \"%s\"", curFunction->getName().c_str(), pluginName.c_str());
|
||||
|
||||
strncpy(function_data->function_name, curFunction->getName().c_str(), MAXIMUM_FUNCTION_NAME_LENGTH - 1);
|
||||
|
||||
function_data->VERSION = FUNCTION_REPLACEMENT_DATA_STRUCT_VERSION;
|
||||
function_data->library = (function_replacement_library_type_t) curFunction->getLibrary();
|
||||
function_data->replaceAddr = (uint32_t) curFunction->getReplaceAddress();
|
||||
function_data->replaceCall = (uint32_t) curFunction->getReplaceCall();
|
||||
function_data->physicalAddr = (uint32_t) curFunction->getPhysicalAddress();
|
||||
function_data->virtualAddr = (uint32_t) curFunction->getVirtualAddress();
|
||||
function_data->targetProcess = curFunction->getTargetProcess();
|
||||
|
||||
plugin_data->info.number_used_functions++;
|
||||
i++;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (auto &curHook : pluginInfo->getHookDataList()) {
|
||||
replacement_data_hook_t *hook_data = &plugin_data->info.hooks[i];
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Set hook for plugin \"%s\" of type %08X to target %08X", plugin_data->meta.name, curHook->getType(), (void *) curHook->getFunctionPointer());
|
||||
|
||||
hook_data->func_pointer = (void *) curHook->getFunctionPointer();
|
||||
hook_data->type = curHook->getType();
|
||||
|
||||
plugin_data->info.number_used_hooks++;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Saving SectionInfos */
|
||||
for (auto &curSection : pluginInfo->getSectionInfoList()) {
|
||||
bool foundFreeSlot = false;
|
||||
uint32_t slot = 0;
|
||||
for (uint32_t j = 0; j < MAXIMUM_PLUGIN_SECTION_LENGTH; j++) {
|
||||
auto *sectionInfo = &(plugin_data->info.sectionInfos[j]);
|
||||
if (sectionInfo->addr == 0 && sectionInfo->size == 0) {
|
||||
foundFreeSlot = true;
|
||||
slot = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundFreeSlot) {
|
||||
auto *sectionInfo = &(plugin_data->info.sectionInfos[slot]);
|
||||
if (curSection.first.length() > MAXIMUM_PLUGIN_SECTION_NAME_LENGTH - 1) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Could not add section info \"%s\" for plugin \"%s\" section name is too long.", curSection.first.c_str(), pluginName.c_str());
|
||||
break;
|
||||
}
|
||||
strncpy(sectionInfo->name, curSection.first.c_str(), MAXIMUM_PLUGIN_SECTION_NAME_LENGTH - 1);
|
||||
sectionInfo->addr = curSection.second->getAddress();
|
||||
sectionInfo->size = curSection.second->getSize();
|
||||
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to store SectionInfos");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
plugin_data->info.trampolineId = pluginInfo->getTrampolineId();
|
||||
plugin_data->info.allocatedTextMemoryAddress = pluginInfo->allocatedTextMemoryAddress;
|
||||
plugin_data->info.allocatedDataMemoryAddress = pluginInfo->allocatedDataMemoryAddress;
|
||||
|
||||
uint32_t entryCount = pluginInfo->getFunctionSymbolDataList().size();
|
||||
if (entryCount > 0) {
|
||||
// Saving SectionInfos
|
||||
uint32_t funcSymStringLen = 1;
|
||||
for (auto &curFuncSym : pluginInfo->getFunctionSymbolDataList()) {
|
||||
funcSymStringLen += curFuncSym->getName().length() + 1;
|
||||
}
|
||||
|
||||
char *stringTable = (char *) MEMAllocFromExpHeapEx(heapHandle, funcSymStringLen, 0x4);
|
||||
if (stringTable == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed alloc memory to store string table for function symbol data");
|
||||
return false;
|
||||
}
|
||||
memset(stringTable, 0, funcSymStringLen);
|
||||
DEBUG_FUNCTION_LINE("Allocated %d for the function symbol string table", funcSymStringLen);
|
||||
auto *entryTable = (plugin_function_symbol_data_t *) MEMAllocFromExpHeapEx(heapHandle, entryCount * sizeof(plugin_function_symbol_data_t), 0x4);
|
||||
if (entryTable == nullptr) {
|
||||
MEMFreeToExpHeap((MEMHeapHandle) heapHandle, stringTable);
|
||||
free(stringTable);
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed alloc memory to store function symbol data");
|
||||
return false;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("Allocated %d for the function symbol data", entryCount * sizeof(plugin_function_symbol_data_t));
|
||||
|
||||
uint32_t curStringOffset = 0;
|
||||
uint32_t curEntryIndex = 0;
|
||||
for (auto &curFuncSym : pluginInfo->getFunctionSymbolDataList()) {
|
||||
entryTable[curEntryIndex].address = curFuncSym->getAddress();
|
||||
entryTable[curEntryIndex].name = &stringTable[curStringOffset];
|
||||
entryTable[curEntryIndex].size = curFuncSym->getSize();
|
||||
auto len = curFuncSym->getName().length() + 1;
|
||||
memcpy(stringTable + curStringOffset, curFuncSym->getName().c_str(), len);
|
||||
curStringOffset += len;
|
||||
curEntryIndex++;
|
||||
}
|
||||
|
||||
plugin_data->info.allocatedFuncSymStringTableAddress = stringTable;
|
||||
plugin_data->info.function_symbol_data = entryTable;
|
||||
}
|
||||
|
||||
plugin_data->info.number_function_symbol_data = entryCount;
|
||||
|
||||
/* Copy plugin data */
|
||||
auto pluginData = plugin->getPluginData();
|
||||
auto plugin_data_data = &plugin_data->data;
|
||||
|
||||
PluginDataPersistence::save(plugin_data_data, pluginData);
|
||||
|
||||
pluginInformation->number_used_plugins++;
|
||||
|
||||
DCFlushRange((void *) pluginInformation, sizeof(plugin_information_t));
|
||||
ICInvalidateRange((void *) pluginInformation, sizeof(plugin_information_t));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<PluginContainer>> PluginContainerPersistence::loadPlugins(plugin_information_t *pluginInformation) {
|
||||
std::vector<std::shared_ptr<PluginContainer>> result;
|
||||
if (pluginInformation == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("pluginInformation == nullptr");
|
||||
return result;
|
||||
}
|
||||
DCFlushRange((void *) pluginInformation, sizeof(plugin_information_t));
|
||||
ICInvalidateRange((void *) pluginInformation, sizeof(plugin_information_t));
|
||||
|
||||
int32_t plugin_count = pluginInformation->number_used_plugins;
|
||||
if (plugin_count > MAXIMUM_PLUGINS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("pluginInformation->plugin_count was bigger then allowed. %d > %d. Limiting to %d", plugin_count, MAXIMUM_PLUGINS, MAXIMUM_PLUGINS);
|
||||
plugin_count = MAXIMUM_PLUGINS;
|
||||
}
|
||||
for (int32_t i = 0; i < plugin_count; i++) {
|
||||
// Copy data from struct.
|
||||
plugin_information_single_t *plugin_data = &(pluginInformation->plugin_data[i]);
|
||||
|
||||
auto metaInformation = std::shared_ptr<PluginMetaInformation>(new PluginMetaInformation);
|
||||
|
||||
plugin_meta_info_t *meta = &(plugin_data->meta);
|
||||
metaInformation->setAuthor(meta->author);
|
||||
metaInformation->setVersion(meta->version);
|
||||
metaInformation->setBuildTimestamp(meta->buildTimestamp);
|
||||
metaInformation->setLicense(meta->license);
|
||||
metaInformation->setDescription(meta->descripion);
|
||||
metaInformation->setSize(meta->size);
|
||||
metaInformation->setName(meta->name);
|
||||
metaInformation->setStorageId(meta->storageId);
|
||||
|
||||
plugin_data_t *data = &(plugin_data->data);
|
||||
|
||||
auto pluginData = PluginDataPersistence::load(data);
|
||||
|
||||
auto curPluginInformation = std::make_shared<PluginInformation>();
|
||||
|
||||
curPluginInformation->setTrampolineId(plugin_data->info.trampolineId);
|
||||
curPluginInformation->allocatedTextMemoryAddress = plugin_data->info.allocatedTextMemoryAddress;
|
||||
curPluginInformation->allocatedDataMemoryAddress = plugin_data->info.allocatedDataMemoryAddress;
|
||||
|
||||
for (auto &curItem : plugin_data->info.sectionInfos) {
|
||||
plugin_section_info_t *sectionInfo = &curItem;
|
||||
if (sectionInfo->addr == 0 && sectionInfo->size == 0) {
|
||||
continue;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Add SectionInfo %s", sectionInfo->name);
|
||||
std::string name(sectionInfo->name);
|
||||
curPluginInformation->addSectionInfo(std::make_shared<SectionInfo>(name, sectionInfo->addr, sectionInfo->size));
|
||||
}
|
||||
|
||||
/* load hook data */
|
||||
uint32_t hookCount = plugin_data->info.number_used_hooks;
|
||||
|
||||
if (hookCount > MAXIMUM_HOOKS_PER_PLUGIN) {
|
||||
DEBUG_FUNCTION_LINE_ERR("number_used_hooks was bigger then allowed. %d > %d. Limiting to %d", hookCount, MAXIMUM_HOOKS_PER_PLUGIN, MAXIMUM_HOOKS_PER_PLUGIN);
|
||||
hookCount = MAXIMUM_HOOKS_PER_PLUGIN;
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < hookCount; j++) {
|
||||
replacement_data_hook_t *hook_entry = &(plugin_data->info.hooks[j]);
|
||||
curPluginInformation->addHookData(std::make_shared<HookData>(hook_entry->func_pointer, hook_entry->type));
|
||||
}
|
||||
|
||||
bool storageHasId = true;
|
||||
for (auto const &value : curPluginInformation->getHookDataList()) {
|
||||
if (value->getType() == WUPS_LOADER_HOOK_INIT_STORAGE &&
|
||||
metaInformation->getStorageId().empty()) {
|
||||
storageHasId = false;
|
||||
}
|
||||
}
|
||||
if (!storageHasId) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Plugin is using the storage API but has not set an ID");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* load function replacement data */
|
||||
uint32_t functionReplaceCount = plugin_data->info.number_used_functions;
|
||||
|
||||
if (functionReplaceCount > MAXIMUM_FUNCTION_PER_PLUGIN) {
|
||||
DEBUG_FUNCTION_LINE_ERR("number_used_functions was bigger then allowed. %d > %d. Limiting to %d", functionReplaceCount, MAXIMUM_FUNCTION_PER_PLUGIN, MAXIMUM_FUNCTION_PER_PLUGIN);
|
||||
functionReplaceCount = MAXIMUM_FUNCTION_PER_PLUGIN;
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < functionReplaceCount; j++) {
|
||||
function_replacement_data_t *entry = &(plugin_data->info.functions[j]);
|
||||
auto func = std::make_shared<FunctionData>((void *) entry->physicalAddr, (void *) entry->virtualAddr, entry->function_name, (function_replacement_library_type_t) entry->library,
|
||||
(void *) entry->replaceAddr,
|
||||
(void *) entry->replaceCall, entry->targetProcess);
|
||||
curPluginInformation->addFunctionData(func);
|
||||
}
|
||||
|
||||
/* load relocation data */
|
||||
for (auto &linking_entry : plugin_data->info.linking_entries) {
|
||||
if (linking_entry.destination == nullptr) {
|
||||
break;
|
||||
}
|
||||
dyn_linking_import_t *importEntry = linking_entry.importEntry;
|
||||
if (importEntry == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("importEntry was nullptr, skipping relocation entry");
|
||||
continue;
|
||||
}
|
||||
dyn_linking_function_t *functionEntry = linking_entry.functionEntry;
|
||||
|
||||
if (functionEntry == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("functionEntry was nullptr, skipping relocation entry");
|
||||
continue;
|
||||
}
|
||||
auto rplInfo = std::make_shared<ImportRPLInformation>(importEntry->importName, importEntry->isData);
|
||||
std::string functionName(functionEntry->functionName);
|
||||
auto reloc = std::make_shared<RelocationData>(linking_entry.type, linking_entry.offset, linking_entry.addend, linking_entry.destination, functionName, rplInfo);
|
||||
curPluginInformation->addRelocationData(reloc);
|
||||
}
|
||||
|
||||
/* load function symbol data */
|
||||
for (uint32_t j = 0; j < plugin_data->info.number_function_symbol_data; j++) {
|
||||
auto symbol_data = &plugin_data->info.function_symbol_data[j];
|
||||
std::string symbol_name = symbol_data->name;
|
||||
auto funSymbolData = std::make_shared<FunctionSymbolData>(symbol_name, (void *) symbol_data->address, symbol_data->size);
|
||||
curPluginInformation->addFunctionSymbolData(funSymbolData);
|
||||
}
|
||||
|
||||
auto container = std::make_shared<PluginContainer>();
|
||||
container->setMetaInformation(metaInformation);
|
||||
container->setPluginData(pluginData);
|
||||
container->setPluginInformation(curPluginInformation);
|
||||
result.push_back(container);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../common/plugin_defines.h"
|
||||
#include "PluginContainer.h"
|
||||
|
||||
class PluginContainerPersistence {
|
||||
public:
|
||||
static bool savePlugin(plugin_information_t *pluginInformation, const std::shared_ptr<PluginContainer> &plugin, MEMHeapHandle heapHandle);
|
||||
|
||||
static std::vector<std::shared_ptr<PluginContainer>> loadPlugins(plugin_information_t *pluginInformation);
|
||||
};
|
||||
@@ -1,63 +1,15 @@
|
||||
#include "PluginData.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
#include "../utils/logger.h"
|
||||
#include <malloc.h>
|
||||
|
||||
PluginData::PluginData(const PluginData &obj) {
|
||||
this->buffer = obj.buffer;
|
||||
this->heapHandle = obj.heapHandle;
|
||||
this->memoryType = obj.memoryType;
|
||||
this->length = obj.length;
|
||||
}
|
||||
|
||||
void PluginData::freeMemory() {
|
||||
if (buffer == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (memoryType) {
|
||||
default:
|
||||
case eMemTypeExpHeap:
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Free PluginData buffer %08X on heap %08X", buffer, this->heapHandle);
|
||||
MEMFreeToExpHeap(this->heapHandle, buffer);
|
||||
this->buffer = nullptr;
|
||||
break;
|
||||
case eMemTypeMEM2:
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Free PluginData buffer %08X on default heap", buffer);
|
||||
free(this->buffer);
|
||||
this->buffer = nullptr;
|
||||
break;
|
||||
PluginData::PluginData(const std::vector<uint8_t> &input) : length(input.size()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
PluginData::PluginData(const std::vector<uint8_t> &buffer) : PluginData(buffer, nullptr, eMemTypeMEM2) {
|
||||
}
|
||||
|
||||
PluginData::PluginData(const std::vector<uint8_t> &input, MEMHeapHandle heapHandle, eMemoryTypes memoryType) : heapHandle(heapHandle),
|
||||
memoryType(memoryType),
|
||||
length(input.size()) {
|
||||
void *data_copy = nullptr;
|
||||
switch (memoryType) {
|
||||
default:
|
||||
case eMemTypeExpHeap:
|
||||
data_copy = MEMAllocFromExpHeapEx(heapHandle, length, 4);
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb on ExpHeap", length / 1024);
|
||||
if (data_copy == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate space on exp heap");
|
||||
} else {
|
||||
memcpy(data_copy, &input[0], length);
|
||||
}
|
||||
this->buffer = data_copy;
|
||||
break;
|
||||
case eMemTypeMEM2:
|
||||
data_copy = memalign(4, length);
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb on default heap", length / 1024);
|
||||
if (data_copy == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate space on default heap");
|
||||
} else {
|
||||
memcpy(data_copy, &input[0], length);
|
||||
}
|
||||
this->buffer = data_copy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -19,41 +19,18 @@
|
||||
|
||||
#include <coreinit/memexpheap.h>
|
||||
#include <malloc.h>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "../elfio/elfio.hpp"
|
||||
|
||||
using namespace ELFIO;
|
||||
|
||||
enum eMemoryTypes {
|
||||
eMemTypeMEM2,
|
||||
eMemTypeExpHeap
|
||||
};
|
||||
|
||||
class PluginData {
|
||||
public:
|
||||
~PluginData() = default;
|
||||
|
||||
void freeMemory();
|
||||
|
||||
PluginData(const PluginData &obj);
|
||||
|
||||
PluginData() = default;
|
||||
|
||||
void *buffer = nullptr;
|
||||
MEMHeapHandle heapHandle{};
|
||||
eMemoryTypes memoryType{};
|
||||
size_t length = 0;
|
||||
|
||||
private:
|
||||
explicit PluginData(const std::vector<uint8_t> &buffer);
|
||||
|
||||
PluginData(const std::vector<uint8_t> &input, MEMHeapHandle heapHandle, eMemoryTypes memoryType);
|
||||
uint32_t getHandle() {
|
||||
return (uint32_t) this;
|
||||
}
|
||||
|
||||
friend class PluginDataFactory;
|
||||
|
||||
friend class PluginContainer;
|
||||
|
||||
friend class PluginDataPersistence;
|
||||
size_t length = 0;
|
||||
std::unique_ptr<uint8_t[]> buffer;
|
||||
};
|
||||
|
||||
@@ -15,33 +15,35 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#include "PluginDataFactory.h"
|
||||
#include "../fs/FSUtils.h"
|
||||
#include "../utils/StringTools.h"
|
||||
#include "fs/FSUtils.h"
|
||||
#include "utils/StringTools.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/utils.h"
|
||||
#include <dirent.h>
|
||||
#include <forward_list>
|
||||
#include <memory>
|
||||
#include <sys/stat.h>
|
||||
|
||||
std::vector<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const std::string &path, MEMHeapHandle heapHandle) {
|
||||
std::vector<std::shared_ptr<PluginData>> result;
|
||||
std::forward_list<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const std::string &path) {
|
||||
std::forward_list<std::shared_ptr<PluginData>> result;
|
||||
struct dirent *dp;
|
||||
DIR *dfd;
|
||||
|
||||
if (path.empty()) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Path was empty");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load Plugins from dir: Path was empty");
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((dfd = opendir(path.c_str())) == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Couldn't open dir %s", path.c_str());
|
||||
DEBUG_FUNCTION_LINE_ERR("Couldn't open dir %s", path.c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
while ((dp = readdir(dfd)) != nullptr) {
|
||||
struct stat stbuf {};
|
||||
std::string full_file_path = StringTools::strfmt("%s/%s", path.c_str(), dp->d_name);
|
||||
StringTools::RemoveDoubleSlashs(full_file_path);
|
||||
auto full_file_path = string_format("%s/%s", path.c_str(), dp->d_name);
|
||||
if (stat(full_file_path.c_str(), &stbuf) == -1) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Unable to stat file: %s", full_file_path.c_str());
|
||||
DEBUG_FUNCTION_LINE_ERR("Unable to stat file: %s", full_file_path.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -49,24 +51,25 @@ std::vector<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const std::s
|
||||
continue;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Loading plugin: %s", full_file_path.c_str());
|
||||
auto pluginData = load(full_file_path, heapHandle);
|
||||
auto pluginData = load(full_file_path);
|
||||
if (pluginData) {
|
||||
result.push_back(pluginData.value());
|
||||
result.push_front(std::move(pluginData.value()));
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load plugin: %s", full_file_path.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dfd != nullptr) {
|
||||
closedir(dfd);
|
||||
}
|
||||
|
||||
closedir(dfd);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<PluginData>> PluginDataFactory::load(const std::string &filename, MEMHeapHandle heapHandle) {
|
||||
std::optional<std::unique_ptr<PluginData>> PluginDataFactory::load(const std::string &filename) {
|
||||
uint8_t *buffer = nullptr;
|
||||
uint32_t fsize = 0;
|
||||
if (FSUtils::LoadFileToMem(filename.c_str(), &buffer, &fsize) < 0) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Failed to load file");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load %s into memory", filename.c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -77,13 +80,18 @@ std::optional<std::shared_ptr<PluginData>> PluginDataFactory::load(const std::st
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Loaded file!");
|
||||
|
||||
return load(result, heapHandle);
|
||||
return load(result);
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<PluginData>> PluginDataFactory::load(std::vector<uint8_t> &buffer, MEMHeapHandle heapHandle) {
|
||||
std::optional<std::unique_ptr<PluginData>> PluginDataFactory::load(const std::vector<uint8_t> &buffer) {
|
||||
if (buffer.empty()) {
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::shared_ptr<PluginData>(new PluginData(buffer, heapHandle, eMemoryTypes::eMemTypeMEM2));
|
||||
auto res = make_unique_nothrow<PluginData>(buffer);
|
||||
if (!res) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "PluginData.h"
|
||||
#include <coreinit/memexpheap.h>
|
||||
#include <forward_list>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@@ -26,9 +27,9 @@
|
||||
|
||||
class PluginDataFactory {
|
||||
public:
|
||||
static std::vector<std::shared_ptr<PluginData>> loadDir(const std::string &path, MEMHeapHandle heapHandle);
|
||||
static std::forward_list<std::shared_ptr<PluginData>> loadDir(const std::string &path);
|
||||
|
||||
static std::optional<std::shared_ptr<PluginData>> load(const std::string &path, MEMHeapHandle heapHandle);
|
||||
static std::optional<std::unique_ptr<PluginData>> load(const std::string &path);
|
||||
|
||||
static std::optional<std::shared_ptr<PluginData>> load(std::vector<uint8_t> &buffer, MEMHeapHandle heapHandle);
|
||||
static std::optional<std::unique_ptr<PluginData>> load(const std::vector<uint8_t> &buffer);
|
||||
};
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#include "PluginDataPersistence.h"
|
||||
#include "../common/plugin_defines.h"
|
||||
#include <memory>
|
||||
|
||||
bool PluginDataPersistence::save(plugin_data_t *pluginDataStruct, const std::shared_ptr<PluginData> &plugin) {
|
||||
if (pluginDataStruct == nullptr) {
|
||||
return false;
|
||||
}
|
||||
pluginDataStruct->buffer = (char *) plugin->buffer;
|
||||
pluginDataStruct->bufferLength = plugin->length;
|
||||
pluginDataStruct->memoryType = plugin->memoryType;
|
||||
pluginDataStruct->heapHandle = (int) plugin->heapHandle;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PluginDataPersistence::save(plugin_data_t *pluginDataStruct, PluginData *plugin) {
|
||||
if (pluginDataStruct == nullptr) {
|
||||
return false;
|
||||
}
|
||||
pluginDataStruct->buffer = (char *) plugin->buffer;
|
||||
pluginDataStruct->bufferLength = plugin->length;
|
||||
pluginDataStruct->memoryType = plugin->memoryType;
|
||||
pluginDataStruct->heapHandle = (int) plugin->heapHandle;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<PluginData> PluginDataPersistence::load(plugin_data_t *pluginDataStruct) {
|
||||
auto pluginData = std::make_shared<PluginData>();
|
||||
|
||||
pluginData->buffer = pluginDataStruct->buffer;
|
||||
pluginData->length = pluginDataStruct->bufferLength;
|
||||
pluginData->memoryType = (eMemoryTypes) pluginDataStruct->memoryType;
|
||||
pluginData->heapHandle = (MEMHeapHandle) pluginDataStruct->heapHandle;
|
||||
return pluginData;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../common/plugin_defines.h"
|
||||
#include "PluginData.h"
|
||||
#include <memory>
|
||||
|
||||
class PluginDataPersistence {
|
||||
|
||||
public:
|
||||
static bool save(plugin_data_t *pluginDataStruct, const std::shared_ptr<PluginData> &plugin);
|
||||
|
||||
static bool save(plugin_data_t *pluginDataStruct, PluginData *plugin);
|
||||
|
||||
static std::shared_ptr<PluginData> load(plugin_data_t *pluginDataStruct);
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "PluginInformation.h"
|
||||
|
||||
PluginInformation::PluginInformation(const PluginInformation &other) {
|
||||
for (const auto &i : other.hook_data_list) {
|
||||
hook_data_list.push_back(i);
|
||||
}
|
||||
for (const auto &i : other.function_data_list) {
|
||||
function_data_list.push_back(i);
|
||||
}
|
||||
for (const auto &i : other.relocation_data_list) {
|
||||
relocation_data_list.push_back(i);
|
||||
}
|
||||
for (const auto &i : other.symbol_data_list) {
|
||||
symbol_data_list.insert(i);
|
||||
}
|
||||
section_info_list = other.section_info_list;
|
||||
trampolineId = other.trampolineId;
|
||||
allocatedTextMemoryAddress = other.allocatedTextMemoryAddress;
|
||||
allocatedDataMemoryAddress = other.allocatedDataMemoryAddress;
|
||||
}
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -39,47 +40,41 @@ struct FunctionSymbolDataComparator {
|
||||
|
||||
class PluginInformation {
|
||||
public:
|
||||
PluginInformation(const PluginInformation &other);
|
||||
|
||||
PluginInformation() = default;
|
||||
|
||||
virtual ~PluginInformation() = default;
|
||||
|
||||
void addHookData(const std::shared_ptr<HookData> &hook_data) {
|
||||
hook_data_list.push_back(hook_data);
|
||||
void addHookData(std::unique_ptr<HookData> hook_data) {
|
||||
hook_data_list.push_back(std::move(hook_data));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<HookData>> &getHookDataList() const {
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<HookData>> &getHookDataList() const {
|
||||
return hook_data_list;
|
||||
}
|
||||
|
||||
void addFunctionData(const std::shared_ptr<FunctionData> &function_data) {
|
||||
function_data_list.push_back(function_data);
|
||||
void addFunctionData(std::unique_ptr<FunctionData> function_data) {
|
||||
function_data_list.push_back(std::move(function_data));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<FunctionData>> &getFunctionDataList() const {
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<FunctionData>> &getFunctionDataList() const {
|
||||
return function_data_list;
|
||||
}
|
||||
|
||||
void addRelocationData(const std::shared_ptr<RelocationData> &relocation_data) {
|
||||
relocation_data_list.push_back(relocation_data);
|
||||
void addRelocationData(std::unique_ptr<RelocationData> relocation_data) {
|
||||
relocation_data_list.push_back(std::move(relocation_data));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<RelocationData>> &getRelocationDataList() const {
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<RelocationData>> &getRelocationDataList() const {
|
||||
return relocation_data_list;
|
||||
}
|
||||
|
||||
|
||||
void addFunctionSymbolData(const std::shared_ptr<FunctionSymbolData> &symbol_data) {
|
||||
symbol_data_list.insert(symbol_data);
|
||||
void addFunctionSymbolData(std::shared_ptr<FunctionSymbolData> symbol_data) {
|
||||
symbol_data_list.insert(std::move(symbol_data));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> &getFunctionSymbolDataList() const {
|
||||
return symbol_data_list;
|
||||
}
|
||||
|
||||
void addSectionInfo(const std::shared_ptr<SectionInfo> §ionInfo) {
|
||||
section_info_list[sectionInfo->getName()] = sectionInfo;
|
||||
void addSectionInfo(std::shared_ptr<SectionInfo> sectionInfo) {
|
||||
section_info_list[sectionInfo->getName()] = std::move(sectionInfo);
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::map<std::string, std::shared_ptr<SectionInfo>> &getSectionInfoList() const {
|
||||
@@ -87,7 +82,7 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<std::shared_ptr<SectionInfo>> getSectionInfo(const std::string §ionName) const {
|
||||
if (getSectionInfoList().count(sectionName) > 0) {
|
||||
if (getSectionInfoList().contains(sectionName)) {
|
||||
return section_info_list.at(sectionName);
|
||||
}
|
||||
return std::nullopt;
|
||||
@@ -101,19 +96,37 @@ public:
|
||||
return trampolineId;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<std::shared_ptr<FunctionSymbolData>> getNearestFunctionSymbolData(uint32_t address) const {
|
||||
std::shared_ptr<FunctionSymbolData> result;
|
||||
|
||||
bool foundHit = false;
|
||||
for (auto &cur : symbol_data_list) {
|
||||
if (foundHit && address < (uint32_t) cur->getAddress()) {
|
||||
break;
|
||||
}
|
||||
if (address >= (uint32_t) cur->getAddress()) {
|
||||
result = cur;
|
||||
foundHit = true;
|
||||
}
|
||||
}
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<HookData>> hook_data_list;
|
||||
std::vector<std::shared_ptr<FunctionData>> function_data_list;
|
||||
std::vector<std::shared_ptr<RelocationData>> relocation_data_list;
|
||||
std::vector<std::unique_ptr<HookData>> hook_data_list;
|
||||
std::vector<std::unique_ptr<FunctionData>> function_data_list;
|
||||
std::vector<std::unique_ptr<RelocationData>> relocation_data_list;
|
||||
std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> symbol_data_list;
|
||||
std::map<std::string, std::shared_ptr<SectionInfo>> section_info_list;
|
||||
|
||||
uint8_t trampolineId = 0;
|
||||
|
||||
void *allocatedTextMemoryAddress = nullptr;
|
||||
void *allocatedDataMemoryAddress = nullptr;
|
||||
std::unique_ptr<uint8_t[]> allocatedTextMemoryAddress;
|
||||
std::unique_ptr<uint8_t[]> allocatedDataMemoryAddress;
|
||||
|
||||
friend class PluginInformationFactory;
|
||||
|
||||
friend class PluginContainerPersistence;
|
||||
};
|
||||
|
||||
@@ -22,28 +22,36 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wups/function_patching.h>
|
||||
|
||||
using namespace ELFIO;
|
||||
|
||||
std::optional<std::shared_ptr<PluginInformation>>
|
||||
PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, MEMHeapHandle heapHandle, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
|
||||
std::optional<std::unique_ptr<PluginInformation>>
|
||||
PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
|
||||
uint8_t trampolineId) {
|
||||
if (pluginData->buffer == nullptr) {
|
||||
if (!pluginData->buffer) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Buffer was nullptr");
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}
|
||||
elfio reader;
|
||||
if (!reader.load((char *) pluginData->buffer, pluginData->length)) {
|
||||
if (!reader.load((char *) pluginData->buffer.get(), pluginData->length)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto pluginInfo = std::make_shared<PluginInformation>();
|
||||
auto pluginInfo = make_unique_nothrow<PluginInformation>();
|
||||
if (!pluginInfo) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate PluginInformation");
|
||||
return {};
|
||||
}
|
||||
|
||||
uint32_t sec_num = reader.sections.size();
|
||||
auto **destinations = (uint8_t **) malloc(sizeof(uint8_t *) * sec_num);
|
||||
uint32_t sec_num = reader.sections.size();
|
||||
|
||||
auto destinations = make_unique_nothrow<uint8_t *[]>(sec_num);
|
||||
if (!destinations) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed alloc memory for destinations array");
|
||||
return {};
|
||||
}
|
||||
|
||||
uint32_t totalSize = 0;
|
||||
|
||||
@@ -69,21 +77,22 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
||||
}
|
||||
}
|
||||
}
|
||||
void *text_data = MEMAllocFromExpHeapEx(heapHandle, text_size, 0x1000);
|
||||
if (text_data == nullptr) {
|
||||
|
||||
auto text_data = make_unique_nothrow<uint8_t[]>(text_size);
|
||||
if (!text_data) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes)", text_size);
|
||||
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb from ExpHeap", text_size / 1024);
|
||||
void *data_data = MEMAllocFromExpHeapEx(heapHandle, data_size, 0x1000);
|
||||
if (data_data == nullptr) {
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb", text_size / 1024);
|
||||
|
||||
auto data_data = make_unique_nothrow<uint8_t[]>(data_size);
|
||||
if (!data_data) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .data section (%d bytes)", data_size);
|
||||
|
||||
MEMFreeToExpHeap(heapHandle, text_data);
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb from ExpHeap", data_size / 1024);
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d kb", data_size / 1024);
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
@@ -97,23 +106,20 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
||||
|
||||
uint32_t destination = address;
|
||||
if ((address >= 0x02000000) && address < 0x10000000) {
|
||||
destination += (uint32_t) text_data;
|
||||
destination += (uint32_t) text_data.get();
|
||||
destination -= 0x02000000;
|
||||
destinations[psec->get_index()] = (uint8_t *) text_data;
|
||||
destinations[psec->get_index()] = (uint8_t *) text_data.get();
|
||||
} else if ((address >= 0x10000000) && address < 0xC0000000) {
|
||||
destination += (uint32_t) data_data;
|
||||
destination += (uint32_t) data_data.get();
|
||||
destination -= 0x10000000;
|
||||
destinations[psec->get_index()] = (uint8_t *) data_data;
|
||||
destinations[psec->get_index()] = (uint8_t *) data_data.get();
|
||||
} else if (address >= 0xC0000000) {
|
||||
destination += (uint32_t) data_data;
|
||||
destination += (uint32_t) data_data.get();
|
||||
destination -= 0xC0000000;
|
||||
//destinations[psec->get_index()] = (uint8_t *) data_data;
|
||||
//destinations[psec->get_index()] -= 0xC0000000;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Unhandled case");
|
||||
free(destinations);
|
||||
MEMFreeToExpHeap(heapHandle, text_data);
|
||||
MEMFreeToExpHeap(heapHandle, data_data);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -127,8 +133,13 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
||||
memcpy((void *) destination, p, sectionSize);
|
||||
}
|
||||
|
||||
std::string sectionName(psec->get_name());
|
||||
pluginInfo->addSectionInfo(std::make_shared<SectionInfo>(sectionName, destination, sectionSize));
|
||||
auto sectionInfo = make_unique_nothrow<SectionInfo>(psec->get_name(), destination, sectionSize);
|
||||
if (!sectionInfo) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocat SectionInfo");
|
||||
return {};
|
||||
}
|
||||
|
||||
pluginInfo->addSectionInfo(std::move(sectionInfo));
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Saved %s section info. Location: %08X size: %08X", psec->get_name().c_str(), destination, sectionSize);
|
||||
|
||||
totalSize += sectionSize;
|
||||
@@ -142,29 +153,23 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
||||
section *psec = reader.sections[i];
|
||||
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Linking (%d)... %s at %08X", i, psec->get_name().c_str(), destinations[psec->get_index()]);
|
||||
|
||||
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], (uint32_t) text_data, (uint32_t) data_data, trampoline_data, trampoline_data_length,
|
||||
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,
|
||||
trampolineId)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("elfLink failed");
|
||||
free(destinations);
|
||||
MEMFreeToExpHeap(heapHandle, text_data);
|
||||
MEMFreeToExpHeap(heapHandle, data_data);
|
||||
return std::nullopt;
|
||||
DEBUG_FUNCTION_LINE_ERR("linkSection failed");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
auto relocationData = getImportRelocationData(reader, destinations);
|
||||
|
||||
for (auto const &reloc : relocationData) {
|
||||
pluginInfo->addRelocationData(reloc);
|
||||
if (!PluginInformationFactory::addImportRelocationData(pluginInfo, reader, destinations)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("addImportRelocationData failed");
|
||||
return {};
|
||||
}
|
||||
|
||||
DCFlushRange((void *) text_data, text_size);
|
||||
ICInvalidateRange((void *) text_data, text_size);
|
||||
DCFlushRange((void *) data_data, data_size);
|
||||
ICInvalidateRange((void *) data_data, data_size);
|
||||
|
||||
free(destinations);
|
||||
DCFlushRange((void *) text_data.get(), text_size);
|
||||
ICInvalidateRange((void *) text_data.get(), text_size);
|
||||
DCFlushRange((void *) data_data.get(), data_size);
|
||||
ICInvalidateRange((void *) data_data.get(), data_size);
|
||||
|
||||
pluginInfo->setTrampolineId(trampolineId);
|
||||
|
||||
@@ -175,9 +180,13 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
||||
if (entries != nullptr) {
|
||||
for (size_t j = 0; j < entries_count; j++) {
|
||||
wups_loader_hook_t *hook = &entries[j];
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Saving hook of plugin Type: %08X, target: %08X" /*,pluginData->getPluginInformation()->getName().c_str()*/, hook->type, (void *) hook->target);
|
||||
auto hook_data = std::make_shared<HookData>((void *) hook->target, hook->type);
|
||||
pluginInfo->addHookData(hook_data);
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Saving hook of plugin Type: %08X, target: %08X", hook->type, (void *) hook->target);
|
||||
auto hookData = make_unique_nothrow<HookData>((void *) hook->target, hook->type);
|
||||
if (!hookData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate HookData");
|
||||
return {};
|
||||
}
|
||||
pluginInfo->addHookData(std::move(hookData));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,11 +202,19 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
||||
cur_function->_function.name /*,pluginData->getPluginInformation()->getName().c_str()*/,
|
||||
cur_function->_function.physical_address, cur_function->_function.virtual_address, cur_function->_function.library, cur_function->_function.target,
|
||||
(void *) cur_function->_function.call_addr);
|
||||
auto function_data = std::make_shared<FunctionData>((void *) cur_function->_function.physical_address, (void *) cur_function->_function.virtual_address, cur_function->_function.name,
|
||||
(function_replacement_library_type_t) cur_function->_function.library,
|
||||
(void *) cur_function->_function.target, (void *) cur_function->_function.call_addr,
|
||||
(FunctionPatcherTargetProcess) cur_function->_function.targetProcess);
|
||||
pluginInfo->addFunctionData(function_data);
|
||||
|
||||
auto functionData = make_unique_nothrow<FunctionData>((void *) cur_function->_function.physical_address,
|
||||
(void *) cur_function->_function.virtual_address,
|
||||
cur_function->_function.name,
|
||||
(function_replacement_library_type_t) cur_function->_function.library,
|
||||
(void *) cur_function->_function.target,
|
||||
(void *) cur_function->_function.call_addr,
|
||||
(FunctionPatcherTargetProcess) cur_function->_function.targetProcess);
|
||||
if (!functionData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate FunctionData");
|
||||
return {};
|
||||
}
|
||||
pluginInfo->addFunctionData(std::move(functionData));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,8 +245,13 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
||||
continue;
|
||||
}
|
||||
|
||||
auto finalAddress = offsetVal + sectionOpt.value()->getAddress();
|
||||
pluginInfo->addFunctionSymbolData(std::make_shared<FunctionSymbolData>(name, (void *) finalAddress, (uint32_t) size));
|
||||
auto finalAddress = offsetVal + sectionOpt.value()->getAddress();
|
||||
auto functionSymbolData = make_unique_nothrow<FunctionSymbolData>(name, (void *) finalAddress, (uint32_t) size);
|
||||
if (!functionSymbolData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate FunctionSymbolData");
|
||||
return {};
|
||||
}
|
||||
pluginInfo->addFunctionSymbolData(std::move(functionSymbolData));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,24 +260,31 @@ PluginInformationFactory::load(const std::shared_ptr<PluginData> &pluginData, ME
|
||||
}
|
||||
}
|
||||
|
||||
if (totalSize > text_size + data_size) {
|
||||
DEBUG_FUNCTION_LINE_ERR("We didn't allocate enough memory!!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Save the addresses for the allocated memory. This way we can free it again :)
|
||||
pluginInfo->allocatedDataMemoryAddress = data_data;
|
||||
pluginInfo->allocatedTextMemoryAddress = text_data;
|
||||
pluginInfo->allocatedDataMemoryAddress = std::move(data_data);
|
||||
pluginInfo->allocatedTextMemoryAddress = std::move(text_data);
|
||||
|
||||
return pluginInfo;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<RelocationData>> PluginInformationFactory::getImportRelocationData(const elfio &reader, uint8_t **destinations) {
|
||||
std::vector<std::shared_ptr<RelocationData>> result;
|
||||
|
||||
std::map<uint32_t, std::string> infoMap;
|
||||
bool PluginInformationFactory::addImportRelocationData(const std::unique_ptr<PluginInformation> &pluginInfo, const elfio &reader, const std::unique_ptr<uint8_t *[]> &destinations) {
|
||||
std::map<uint32_t, std::shared_ptr<ImportRPLInformation>> infoMap;
|
||||
|
||||
uint32_t sec_num = reader.sections.size();
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
auto *psec = reader.sections[i];
|
||||
if (psec->get_type() == 0x80000002) {
|
||||
infoMap[i] = psec->get_name();
|
||||
auto info = make_shared_nothrow<ImportRPLInformation>(psec->get_name());
|
||||
if (!info) {
|
||||
return false;
|
||||
}
|
||||
infoMap[i] = std::move(info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,7 +303,7 @@ std::vector<std::shared_ptr<RelocationData>> PluginInformationFactory::getImport
|
||||
|
||||
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto adjusted_sym_value = (uint32_t) sym_value;
|
||||
@@ -282,35 +311,28 @@ std::vector<std::shared_ptr<RelocationData>> PluginInformationFactory::getImport
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string fimport = ".fimport_";
|
||||
std::string dimport = ".dimport_";
|
||||
|
||||
bool isData = false;
|
||||
|
||||
std::string rplName;
|
||||
std::string rawSectionName = infoMap[sym_section_index];
|
||||
|
||||
if (rawSectionName.size() < fimport.size()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Section name was shorter than expected, skipping this relocation");
|
||||
continue;
|
||||
} else if (std::equal(fimport.begin(), fimport.end(), rawSectionName.begin())) {
|
||||
rplName = rawSectionName.substr(fimport.size());
|
||||
} else if (std::equal(dimport.begin(), dimport.end(), rawSectionName.begin())) {
|
||||
rplName = rawSectionName.substr(dimport.size());
|
||||
isData = true;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("invalid section name");
|
||||
continue;
|
||||
uint32_t section_index = psec->get_info();
|
||||
if (!infoMap.contains(sym_section_index)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Relocation is referencing a unknown section. %d destination: %08X sym_name %s", section_index, destinations[section_index], sym_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto rplInfo = std::make_shared<ImportRPLInformation>(rplName, isData);
|
||||
auto relocationData = make_unique_nothrow<RelocationData>(type,
|
||||
offset - 0x02000000,
|
||||
addend,
|
||||
(void *) (destinations[section_index]),
|
||||
sym_name,
|
||||
infoMap[sym_section_index]);
|
||||
if (!relocationData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate RelocationData");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t section_index = psec->get_info();
|
||||
result.push_back(std::make_shared<RelocationData>(type, offset - 0x02000000, addend, (void *) (destinations[section_index]), sym_name, rplInfo));
|
||||
pluginInfo->addRelocationData(std::move(relocationData));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PluginInformationFactory::linkSection(const elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
|
||||
@@ -380,6 +402,5 @@ bool PluginInformationFactory::linkSection(const elfio &reader, uint32_t section
|
||||
return true;
|
||||
}
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to find relocation section");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -27,15 +27,17 @@
|
||||
#include <vector>
|
||||
#include <wums/defines/relocation_defines.h>
|
||||
|
||||
|
||||
class PluginInformationFactory {
|
||||
public:
|
||||
static std::optional<std::shared_ptr<PluginInformation>>
|
||||
load(const std::shared_ptr<PluginData> &pluginData, MEMHeapHandle heaphandle, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length, uint8_t trampolineId);
|
||||
static std::optional<std::unique_ptr<PluginInformation>>
|
||||
load(const std::shared_ptr<PluginData> &pluginData, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
|
||||
uint8_t trampolineId);
|
||||
|
||||
static bool
|
||||
linkSection(const elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
|
||||
linkSection(const ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
|
||||
uint32_t trampoline_data_length,
|
||||
uint8_t trampolineId);
|
||||
|
||||
static std::vector<std::shared_ptr<RelocationData>> getImportRelocationData(const elfio &reader, uint8_t **destinations);
|
||||
static bool addImportRelocationData(const std::unique_ptr<PluginInformation> &pluginInfo, const ELFIO::elfio &reader, const std::unique_ptr<uint8_t *[]> &destinations);
|
||||
};
|
||||
|
||||
@@ -59,36 +59,36 @@ public:
|
||||
private:
|
||||
PluginMetaInformation() = default;
|
||||
|
||||
void setName(const std::string &_name) {
|
||||
this->name = _name;
|
||||
void setName(std::string _name) {
|
||||
this->name = std::move(_name);
|
||||
}
|
||||
|
||||
void setAuthor(const std::string &_author) {
|
||||
this->author = _author;
|
||||
void setAuthor(std::string _author) {
|
||||
this->author = std::move(_author);
|
||||
}
|
||||
|
||||
void setVersion(const std::string &_version) {
|
||||
this->version = _version;
|
||||
void setVersion(std::string _version) {
|
||||
this->version = std::move(_version);
|
||||
}
|
||||
|
||||
void setLicense(const std::string &_license) {
|
||||
this->license = _license;
|
||||
void setLicense(std::string _license) {
|
||||
this->license = std::move(_license);
|
||||
}
|
||||
|
||||
void setBuildTimestamp(const std::string &_buildtimestamp) {
|
||||
this->buildtimestamp = _buildtimestamp;
|
||||
void setBuildTimestamp(std::string _buildtimestamp) {
|
||||
this->buildtimestamp = std::move(_buildtimestamp);
|
||||
}
|
||||
|
||||
void setDescription(const std::string &_description) {
|
||||
this->description = _description;
|
||||
void setDescription(std::string _description) {
|
||||
this->description = std::move(_description);
|
||||
}
|
||||
|
||||
void setSize(size_t _size) {
|
||||
this->size = _size;
|
||||
}
|
||||
|
||||
void setStorageId(const std::string &_storageId) {
|
||||
this->storageId = _storageId;
|
||||
void setStorageId(std::string _storageId) {
|
||||
this->storageId = std::move(_storageId);
|
||||
}
|
||||
|
||||
std::string name;
|
||||
@@ -102,7 +102,5 @@ private:
|
||||
|
||||
friend class PluginMetaInformationFactory;
|
||||
|
||||
friend class PluginContainerPersistence;
|
||||
|
||||
friend class PluginContainer;
|
||||
};
|
||||
|
||||
@@ -16,27 +16,25 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "PluginMetaInformationFactory.h"
|
||||
#include "../fs/FSUtils.h"
|
||||
#include "../utils/StringTools.h"
|
||||
#include "elfio/elfio.hpp"
|
||||
#include "fs/FSUtils.h"
|
||||
#include <memory>
|
||||
|
||||
using namespace ELFIO;
|
||||
|
||||
std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const std::shared_ptr<PluginData> &pluginData) {
|
||||
if (pluginData->buffer == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Buffer was nullptr");
|
||||
return std::nullopt;
|
||||
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const std::shared_ptr<PluginData> &pluginData) {
|
||||
if (!pluginData->buffer) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Buffer is empty");
|
||||
return {};
|
||||
}
|
||||
elfio reader;
|
||||
if (!reader.load((char *) pluginData->buffer, pluginData->length)) {
|
||||
ELFIO::elfio reader;
|
||||
if (!reader.load((char *) pluginData->buffer.get(), pluginData->length)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Can't process PluginData in elfio");
|
||||
return {};
|
||||
}
|
||||
return loadPlugin(reader);
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(std::string &filePath) {
|
||||
elfio reader;
|
||||
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const std::string &filePath) {
|
||||
ELFIO::elfio reader;
|
||||
|
||||
uint8_t *buffer = nullptr;
|
||||
uint32_t length = 0;
|
||||
@@ -54,8 +52,8 @@ std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFacto
|
||||
return res;
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(char *buffer, size_t size) {
|
||||
elfio reader;
|
||||
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(char *buffer, size_t size) {
|
||||
ELFIO::elfio reader;
|
||||
if (!reader.load(buffer, size)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Can't find or process ELF file");
|
||||
return std::nullopt;
|
||||
@@ -64,15 +62,15 @@ std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFacto
|
||||
return loadPlugin(reader);
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const elfio &reader) {
|
||||
std::optional<std::unique_ptr<PluginMetaInformation>> PluginMetaInformationFactory::loadPlugin(const ELFIO::elfio &reader) {
|
||||
size_t pluginSize = 0;
|
||||
|
||||
auto pluginInfo = std::shared_ptr<PluginMetaInformation>(new PluginMetaInformation);
|
||||
auto pluginInfo = std::unique_ptr<PluginMetaInformation>(new PluginMetaInformation);
|
||||
|
||||
uint32_t sec_num = reader.sections.size();
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
ELFIO::section *psec = reader.sections[i];
|
||||
|
||||
// Calculate total size:
|
||||
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
|
||||
@@ -118,7 +116,7 @@ std::optional<std::shared_ptr<PluginMetaInformation>> PluginMetaInformationFacto
|
||||
} else if (key == "storage_id") {
|
||||
pluginInfo->setStorageId(value);
|
||||
} else if (key == "wups") {
|
||||
if (value != "0.7.0") {
|
||||
if (value != "0.7.1") {
|
||||
DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring plugin - Unsupported WUPS version: %s.", value.c_str());
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "PluginData.h"
|
||||
#include "PluginMetaInformation.h"
|
||||
#include "elfio/elfio.hpp"
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@@ -26,11 +27,11 @@
|
||||
|
||||
class PluginMetaInformationFactory {
|
||||
public:
|
||||
static std::optional<std::shared_ptr<PluginMetaInformation>> loadPlugin(const std::shared_ptr<PluginData> &pluginData);
|
||||
static std::optional<std::unique_ptr<PluginMetaInformation>> loadPlugin(const std::shared_ptr<PluginData> &pluginData);
|
||||
|
||||
static std::optional<std::shared_ptr<PluginMetaInformation>> loadPlugin(std::string &filePath);
|
||||
static std::optional<std::unique_ptr<PluginMetaInformation>> loadPlugin(const std::string &filePath);
|
||||
|
||||
static std::optional<std::shared_ptr<PluginMetaInformation>> loadPlugin(char *buffer, size_t size);
|
||||
static std::optional<std::unique_ptr<PluginMetaInformation>> loadPlugin(char *buffer, size_t size);
|
||||
|
||||
static std::optional<std::shared_ptr<PluginMetaInformation>> loadPlugin(const elfio &reader);
|
||||
static std::optional<std::unique_ptr<PluginMetaInformation>> loadPlugin(const ELFIO::elfio &reader);
|
||||
};
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
class RelocationData {
|
||||
|
||||
public:
|
||||
RelocationData(const char type, size_t offset, int32_t addend, void *destination, std::string &name, std::shared_ptr<ImportRPLInformation> rplInfo) : type(type),
|
||||
offset(offset),
|
||||
addend(addend),
|
||||
destination(destination),
|
||||
name(name),
|
||||
rplInfo(std::move(rplInfo)) {
|
||||
RelocationData(const char type, size_t offset, int32_t addend, void *destination, std::string name, std::shared_ptr<ImportRPLInformation> rplInfo) : type(type),
|
||||
offset(offset),
|
||||
addend(addend),
|
||||
destination(destination),
|
||||
name(std::move(name)),
|
||||
rplInfo(std::move(rplInfo)) {
|
||||
}
|
||||
|
||||
RelocationData(const RelocationData &o2) = default;
|
||||
|
||||
@@ -22,18 +22,11 @@
|
||||
class SectionInfo {
|
||||
|
||||
public:
|
||||
SectionInfo(std::string &name, uint32_t address, uint32_t sectionSize) : name(name),
|
||||
address(address),
|
||||
sectionSize(sectionSize) {
|
||||
SectionInfo(std::string name, uint32_t address, uint32_t sectionSize) : name(std::move(name)),
|
||||
address(address),
|
||||
sectionSize(sectionSize) {
|
||||
}
|
||||
|
||||
SectionInfo() = default;
|
||||
|
||||
SectionInfo(const SectionInfo &o2) = default;
|
||||
|
||||
|
||||
virtual ~SectionInfo() = default;
|
||||
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return name;
|
||||
}
|
||||
@@ -46,6 +39,10 @@ public:
|
||||
return sectionSize;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t isInSection(uint32_t addr) const {
|
||||
return addr >= address && addr < address + sectionSize;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
uint32_t address{};
|
||||
|
||||
Reference in New Issue
Block a user