mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2024-11-18 02:39:20 +01:00
298 lines
13 KiB
C++
298 lines
13 KiB
C++
#include <coreinit/cache.h>
|
|
|
|
#include "PluginContainer.h"
|
|
#include "PluginInformationFactory.h"
|
|
#include "PluginMetaInformationFactory.h"
|
|
#include "PluginContainerPersistence.h"
|
|
#include "DynamicLinkingHelper.h"
|
|
#include "common/plugin_defines.h"
|
|
#include "PluginInformation.h"
|
|
#include "RelocationData.h"
|
|
|
|
bool PluginContainerPersistence::savePlugin(plugin_information_t * pluginInformation, PluginContainer& plugin) {
|
|
|
|
int32_t plugin_count = pluginInformation->number_used_plugins;
|
|
|
|
auto pluginName = plugin.getMetaInformation().getName();
|
|
//auto pluginPath = plugin.getMetaInformation().getPath();
|
|
|
|
|
|
if(plugin_count >= MAXIMUM_PLUGINS - 1) {
|
|
DEBUG_FUNCTION_LINE("Maximum of %d plugins reached. %s won't be loaded!\n", MAXIMUM_PLUGINS, pluginName.c_str());
|
|
return false;
|
|
}
|
|
// Copy data to global struct.
|
|
plugin_information_single_t * plugin_data = &(pluginInformation->plugin_data[plugin_count]);
|
|
|
|
DEBUG_FUNCTION_LINE("%08X", plugin_data);
|
|
// Make sure everything is reset.
|
|
//plugin_data = {};
|
|
memset((void*)plugin_data, 0, sizeof(plugin_information_single_t));
|
|
|
|
auto pluginMetaInfo = plugin.getMetaInformation();
|
|
auto plugin_meta_data = &plugin_data->meta;
|
|
|
|
if(pluginMetaInfo.getName().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
|
DEBUG_FUNCTION_LINE("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("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("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("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("Warning: build timestampt 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("Warning: description will be truncated.");
|
|
DEBUG_FUNCTION_LINE("%s", pluginMetaInfo.getDescription().c_str());
|
|
}
|
|
strncpy(plugin_meta_data->descripion, pluginMetaInfo.getDescription().c_str(), MAXIMUM_PLUGIN_DESCRIPTION_LENGTH-1);
|
|
|
|
plugin_meta_data->size = pluginMetaInfo.getSize();
|
|
|
|
auto pluginInfo = plugin.getPluginInformation();
|
|
|
|
|
|
// Relocation
|
|
std::vector<RelocationData> 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("Failed to add a relocation entry");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
std::vector<FunctionData> function_data_list = pluginInfo.getFunctionDataList();
|
|
std::vector<HookData> hook_data_list = pluginInfo.getHookDataList();
|
|
|
|
|
|
if(function_data_list.size() > MAXIMUM_FUNCTION_PER_PLUGIN) {
|
|
DEBUG_FUNCTION_LINE("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("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("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()) {
|
|
replacement_data_function_t * function_data = &plugin_data->info.functions[i];
|
|
if(strlen(curFunction.getName().c_str()) > MAXIMUM_FUNCTION_NAME_LENGTH-1) {
|
|
DEBUG_FUNCTION_LINE("Could not add function \"%s\" for plugin \"%s\" function name is too long.", curFunction.getName().c_str(), pluginName.c_str());
|
|
continue;
|
|
}
|
|
|
|
DEBUG_FUNCTION_LINE("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->library = 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();
|
|
|
|
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("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 i = 0; i < MAXIMUM_PLUGIN_SECTION_LENGTH; i++) {
|
|
plugin_section_info_t * sectionInfo = &(plugin_data->info.sectionInfos[i]);
|
|
if(sectionInfo->addr == 0 && sectionInfo->size == 0) {
|
|
foundFreeSlot = true;
|
|
slot = i;
|
|
break;
|
|
}
|
|
}
|
|
if(foundFreeSlot) {
|
|
plugin_section_info_t * sectionInfo = &(plugin_data->info.sectionInfos[slot]);
|
|
if(strlen(curSection.first.c_str()) > MAXIMUM_PLUGIN_SECTION_NAME_LENGTH-1) {
|
|
DEBUG_FUNCTION_LINE("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("Failed to store SectionInfos");
|
|
return false;
|
|
}
|
|
}
|
|
plugin_data->info.trampolinId = pluginInfo.getTrampolinId();
|
|
|
|
/* Copy plugin data */
|
|
auto pluginData = plugin.getPluginData();
|
|
auto plugin_data_data = &plugin_data->data;
|
|
|
|
plugin_data_data->buffer = (char*)pluginData.buffer;
|
|
plugin_data_data->bufferLength = pluginData.length;
|
|
plugin_data_data->memoryType = pluginData.memoryType;
|
|
plugin_data_data->heapHandle = (int)pluginData.heapHandle;
|
|
|
|
pluginInformation->number_used_plugins++;
|
|
|
|
DCFlushRange((void*)pluginInformation,sizeof(plugin_information_t));
|
|
ICInvalidateRange((void*)pluginInformation,sizeof(plugin_information_t));
|
|
|
|
return true;
|
|
}
|
|
|
|
std::vector<PluginContainer> PluginContainerPersistence::loadPlugins(plugin_information_t * pluginInformation) {
|
|
std::vector<PluginContainer> result;
|
|
if(pluginInformation == NULL) {
|
|
DEBUG_FUNCTION_LINE("pluginInformation == NULL");
|
|
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("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]);
|
|
|
|
PluginMetaInformation metaInformation;
|
|
|
|
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);
|
|
|
|
PluginData pluginData;
|
|
|
|
plugin_data_t * data = &(plugin_data->data);
|
|
|
|
pluginData.buffer = data->buffer;
|
|
pluginData.length = data->bufferLength;
|
|
pluginData.memoryType = (eMemoryTypes) data->memoryType;
|
|
pluginData.heapHandle = (MEMHeapHandle) data->heapHandle;
|
|
pluginData.loadReader();
|
|
|
|
PluginInformation pluginInformation;
|
|
|
|
pluginInformation.setTrampolinId(plugin_data->info.trampolinId);
|
|
|
|
for(uint32_t i = 0; i < MAXIMUM_PLUGIN_SECTION_LENGTH; i++) {
|
|
plugin_section_info_t * sectionInfo = &(plugin_data->info.sectionInfos[i]);
|
|
if(sectionInfo->addr == 0 && sectionInfo->size == 0) {
|
|
continue;
|
|
}
|
|
DEBUG_FUNCTION_LINE("Add SectionInfo %s", sectionInfo->name);
|
|
pluginInformation.addSectionInfo(SectionInfo(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("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]);
|
|
HookData curHook(hook_entry->func_pointer, hook_entry->type);
|
|
pluginInformation.addHookData(curHook);
|
|
}
|
|
|
|
/* load function replacement data */
|
|
uint32_t functionReplaceCount = plugin_data->info.number_used_functions;
|
|
|
|
if(functionReplaceCount > MAXIMUM_FUNCTION_PER_PLUGIN) {
|
|
DEBUG_FUNCTION_LINE("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++) {
|
|
replacement_data_function_t * entry = &(plugin_data->info.functions[j]);
|
|
FunctionData func((void *) entry->physicalAddr, (void *) entry->virtualAddr, entry->function_name, entry->library, (void *) entry->replaceAddr, (void *) entry->replaceCall);
|
|
pluginInformation.addFunctionData(func);
|
|
}
|
|
|
|
/* load relocation data */
|
|
for(uint32_t j = 0; j < PLUGIN_DYN_LINK_RELOCATION_LIST_LENGTH; j++) {
|
|
dyn_linking_relocation_entry_t * linking_entry = &(plugin_data->info.linking_entries[j]);
|
|
if(linking_entry->destination == NULL) {
|
|
break;
|
|
}
|
|
dyn_linking_import_t* importEntry = linking_entry->importEntry;
|
|
if(importEntry == NULL) {
|
|
DEBUG_FUNCTION_LINE("importEntry was NULL, skipping relocation entry");
|
|
continue;
|
|
}
|
|
if(importEntry->importName == NULL) {
|
|
DEBUG_FUNCTION_LINE("importEntry->importName was NULL, skipping relocation entry");
|
|
continue;
|
|
}
|
|
dyn_linking_function_t* functionEntry = linking_entry->functionEntry;
|
|
|
|
if(functionEntry == NULL) {
|
|
DEBUG_FUNCTION_LINE("functionEntry was NULL, skipping relocation entry");
|
|
continue;
|
|
}
|
|
if(functionEntry->functionName == NULL) {
|
|
DEBUG_FUNCTION_LINE("functionEntry->functionName was NULL, skipping relocation entry");
|
|
continue;
|
|
}
|
|
ImportRPLInformation rplInfo(importEntry->importName, importEntry->isData);
|
|
RelocationData reloc(linking_entry->type, linking_entry->offset, linking_entry->addend, linking_entry->destination, functionEntry->functionName, rplInfo);
|
|
pluginInformation.addRelocationData(reloc);
|
|
}
|
|
|
|
PluginContainer container;
|
|
container.setMetaInformation(metaInformation);
|
|
container.setPluginData(pluginData);
|
|
container.setPluginInformation(pluginInformation);
|
|
result.push_back(container);
|
|
}
|
|
return result;
|
|
}
|