Rewrite of the WUMSLoader to simplify the code and have more memory for modules

This commit is contained in:
Maschell 2022-05-07 21:12:18 +02:00
parent b247427427
commit b1b99343d6
88 changed files with 1299 additions and 2476 deletions

View File

@ -12,7 +12,7 @@ jobs:
- uses: actions/checkout@v2
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./relocator/src
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./wumsloader/src
build-binary:
runs-on: ubuntu-18.04
needs: clang-format

View File

@ -9,7 +9,18 @@ jobs:
- uses: actions/checkout@v2
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./relocator/src
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./wumsloader/src
check-build-with-logging:
runs-on: ubuntu-18.04
needs: clang-format
steps:
- uses: actions/checkout@v2
- name: build binary with logging
run: |
docker build . -t builder
docker run --rm -v ${PWD}:/project builder make DEBUG=VERBOSE
docker run --rm -v ${PWD}:/project builder make clean
docker run --rm -v ${PWD}:/project builder make DEBUG=1
build-binary:
runs-on: ubuntu-18.04
needs: clang-format

View File

@ -1,5 +1,5 @@
FROM wiiuenv/devkitppc:20211229
FROM wiiuenv/devkitppc:20220507
COPY --from=wiiuenv/wiiumodulesystem:20220127 /artifacts $DEVKITPRO
COPY --from=wiiuenv/wiiumodulesystem:20220507 /artifacts $DEVKITPRO
WORKDIR project

View File

@ -31,7 +31,7 @@ INCLUDES := source
#-------------------------------------------------------------------------------
# options for code generation
#-------------------------------------------------------------------------------
CFLAGS := -Wall -O2 -ffunction-sections \
CFLAGS := -Wall -Os -ffunction-sections \
$(MACHDEP)
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
@ -42,10 +42,17 @@ ASFLAGS := -g $(ARCH)
LDFLAGS = -g $(ARCH) $(RPXSPECS) --entry=_start -Wl,-Map,$(notdir $*.map)
ifeq ($(DEBUG),1)
export DEBUG=1
CXXFLAGS += -DDEBUG -g
CFLAGS += -DDEBUG -g
endif
ifeq ($(DEBUG),VERBOSE)
export DEBUG=VERBOSE
CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
endif
LIBS := -lwut -lz
#-------------------------------------------------------------------------------
@ -91,7 +98,7 @@ endif
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC) relocator.elf.o
export OFILES := $(OFILES_BIN) $(OFILES_SRC) wumsloader.elf.o
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
@ -107,13 +114,13 @@ all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C relocator
@$(MAKE) --no-print-directory -C wumsloader
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#-------------------------------------------------------------------------------
clean:
@echo clean ...
make clean -C relocator
make clean -C wumsloader
@rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf
#-------------------------------------------------------------------------------
@ -126,16 +133,16 @@ DEPENDS := $(OFILES:.o=.d)
# main targets
#-------------------------------------------------------------------------------
relocator_elf := ../relocator/relocator.elf
wumsloader_elf := ../wumsloader/wumsloader.elf
all : $(OUTPUT).rpx
$(relocator_elf):
make -C ../relocator
$(wumsloader_elf):
make -C ../wumsloader
$(OUTPUT).rpx : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
$(OFILES) : relocator_elf.h
$(OFILES) : wumsloader_elf.h
$(OFILES_SRC) : $(HFILES_BIN)
@ -152,7 +159,7 @@ $(OFILES_SRC) : $(HFILES_BIN)
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER)
relocator_elf.h: $(relocator_elf)
wumsloader_elf.h: $(wumsloader_elf)
bin2s -a 32 -H `(echo $(<F) | tr . _)`.h $< | $(AS) -o $(<F).o
-include $(DEPENDS)

View File

@ -8,7 +8,7 @@ Put the `10_wums_loader.rpx` in the `fs:/vol/external01/wiiu/environments/[ENVIR
Put modules (in form of `.wms` files) that should be used a main()-hook into `fs:/vol/external01/wiiu/environments/[ENVIRONMENT]/modules/`.
The area between `0x00800000` and whereever this loader is loaded, will be used.
The area between `0x00809000` and `0x00FFF000` will be used.
## Building
Make you to have [wut](https://github.com/devkitPro/wut/) and [WiiUModuleSystem](https://github.com/wiiu-env/WiiUModuleSystem) installed and use the following command for build:
@ -33,10 +33,10 @@ docker run -it --rm -v ${PWD}:/project wumsloader-builder make clean
## Format the code via docker
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./relocator/src -i`
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./wumsloader/src -i`
## Credits
- maschell
- Maschell
- Copy paste stuff from dimok
- Copy pasted the solution for using wut header in .elf files from [RetroArch](https://github.com/libretro/RetroArch)
- Copy pasted resolving the ElfRelocations from [decaf](https://github.com/decaf-emu/decaf-emu)

View File

@ -1,108 +0,0 @@
#include "DynamicLinkingHelper.h"
#include <cstring>
dyn_linking_function_t *DynamicLinkingHelper::getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName) {
if (data == nullptr) {
return nullptr;
}
if (functionName == nullptr) {
return nullptr;
}
dyn_linking_function_t *result = nullptr;
for (auto &function : data->functions) {
dyn_linking_function_t *curEntry = &function;
if (strlen(curEntry->functionName) == 0) {
if (strlen(functionName) > DYN_LINK_FUNCTION_NAME_LENGTH) {
DEBUG_FUNCTION_LINE("Failed to add function name, it's too long.\n");
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 &import : data->imports) {
dyn_linking_import_t *curEntry = &import;
if (strlen(curEntry->importName) == 0) {
if (strlen(importName) > DYN_LINK_IMPORT_NAME_LENGTH) {
DEBUG_FUNCTION_LINE("Failed to add Import, it's too long.\n");
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::addRelocationEntry(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 addRelocationEntry(linking_data, linking_entries, linking_entry_length, relocationData->getType(),
relocationData->getOffset(), relocationData->getAddend(), relocationData->getDestination(),
relocationData->getName(),
relocationData->getImportRPLInformation());
}
bool DynamicLinkingHelper::addRelocationEntry(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, 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("Getting import info failed. Probably maximum of %d rpl files to import reached.\n", 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("Getting import info failed. Probably maximum of %d function to be relocated reached.\n", DYN_LINK_FUNCTION_LIST_LENGTH);
return false;
}
return addRelocationEntry(linking_entries, linking_entry_length, type, offset, addend, destination, functionInfo,
importInfoGbl);
}
bool DynamicLinkingHelper::addRelocationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, 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 = destination;
curEntry->functionEntry = functionName;
curEntry->importEntry = importInfo;
return true;
}
return false;
}

View File

@ -1,66 +0,0 @@
#pragma once
#include "../../source/module/RelocationData.h"
#include "utils/logger.h"
#include <string>
#include <vector>
#include <wums.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 addRelocationEntry(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
addRelocationEntry(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,
void *destination, const std::string &name,
const std::shared_ptr<ImportRPLInformation> &rplInfo);
static bool
addRelocationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination,
dyn_linking_function_t *functionName, dyn_linking_import_t *importInfo);
private:
DynamicLinkingHelper() = default;
~DynamicLinkingHelper() = default;
};

View File

@ -1,87 +0,0 @@
/****************************************************************************
* Copyright (C) 2018-2021 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/>.
****************************************************************************/
#include "../../source/module/HookData.h"
#include "../../source/module/RelocationData.h"
#include <vector>
#pragma once
class ModuleDataMinimal {
public:
ModuleDataMinimal() = default;
~ModuleDataMinimal() = default;
void setExportName(const std::string &name) {
this->export_name = name;
}
[[nodiscard]] std::string getExportName() const {
return this->export_name;
}
void addRelocationData(const std::shared_ptr<RelocationData> &relocation_data) {
relocation_data_list.push_back(relocation_data);
}
[[nodiscard]] const std::vector<std::shared_ptr<RelocationData>> &getRelocationDataList() const {
return relocation_data_list;
}
void addHookData(const std::shared_ptr<HookData> &data) {
hook_data_list.push_back(data);
}
[[nodiscard]] const std::vector<std::shared_ptr<HookData>> &getHookDataList() const {
return hook_data_list;
}
void setEntrypoint(uint32_t addr) {
this->entrypoint = addr;
}
[[nodiscard]] uint32_t getEntrypoint() const {
return entrypoint;
}
[[nodiscard]] bool isInitBeforeRelocationDoneHook() const {
return this->initBeforeRelocationDoneHook;
}
void setInitBeforeRelocationDoneHook(bool value) {
this->initBeforeRelocationDoneHook = value;
}
[[nodiscard]] bool isSkipInitFini() const {
return this->skipInitFini;
}
void setSkipInitFini(bool value) {
this->skipInitFini = value;
}
bool relocationsDone = false;
private:
std::vector<std::shared_ptr<RelocationData>> relocation_data_list;
std::vector<std::shared_ptr<HookData>> hook_data_list;
std::string export_name;
uint32_t entrypoint = 0;
bool initBeforeRelocationDoneHook = false;
bool skipInitFini = false;
};

View File

@ -1,71 +0,0 @@
#include "ModuleDataPersistence.h"
#include "DynamicLinkingHelper.h"
#include <coreinit/cache.h>
#include <wums.h>
std::vector<std::shared_ptr<ModuleDataMinimal>> ModuleDataPersistence::loadModuleData(module_information_t *moduleInformation) {
std::vector<std::shared_ptr<ModuleDataMinimal>> result;
if (moduleInformation == nullptr) {
DEBUG_FUNCTION_LINE("moduleInformation == NULL\n");
return result;
}
DCFlushRange((void *) moduleInformation, sizeof(module_information_t));
ICInvalidateRange((void *) moduleInformation, sizeof(module_information_t));
int32_t module_count = moduleInformation->number_used_modules;
if (module_count > MAXIMUM_MODULES) {
DEBUG_FUNCTION_LINE("moduleInformation->module_count was bigger then allowed. %d > %d. Limiting to %d\n", module_count, MAXIMUM_MODULES, MAXIMUM_MODULES);
module_count = MAXIMUM_MODULES;
}
for (int32_t i = 0; i < module_count; i++) {
// Copy data from struct.
module_information_single_t *module_data = &(moduleInformation->module_data[i]);
auto moduleData = std::make_shared<ModuleDataMinimal>();
moduleData->setEntrypoint(module_data->entrypoint);
moduleData->setInitBeforeRelocationDoneHook(module_data->initBeforeRelocationDoneHook);
moduleData->setSkipInitFini(module_data->skipInitFini);
moduleData->setExportName(module_data->module_export_name);
for (auto &hook_entry : module_data->hook_entries) {
if (hook_entry.target == 0) {
continue;
}
moduleData->addHookData(std::make_shared<HookData>(static_cast<wums_hook_type_t>(hook_entry.type), reinterpret_cast<const void *>(hook_entry.target)));
}
for (auto &linking_entry : module_data->linking_entries) {
if (linking_entry.destination == nullptr) {
break;
}
dyn_linking_import_t *importEntry = linking_entry.importEntry;
if (importEntry == nullptr) {
DEBUG_FUNCTION_LINE("importEntry was NULL, skipping relocation entry\n");
continue;
}
if (importEntry->importName == nullptr) {
DEBUG_FUNCTION_LINE("importEntry->importName was NULL, skipping relocation entry\n");
continue;
}
dyn_linking_function_t *functionEntry = linking_entry.functionEntry;
if (functionEntry == nullptr) {
DEBUG_FUNCTION_LINE("functionEntry was NULL, skipping relocation entry\n");
continue;
}
if (functionEntry->functionName == nullptr) {
DEBUG_FUNCTION_LINE("functionEntry->functionName was NULL, skipping relocation entry\n");
continue;
}
auto rplInfo = std::make_shared<ImportRPLInformation>(importEntry->importName, importEntry->isData);
auto reloc = std::make_shared<RelocationData>(linking_entry.type, linking_entry.offset, linking_entry.addend, linking_entry.destination, functionEntry->functionName, rplInfo);
moduleData->addRelocationData(reloc);
}
result.push_back(moduleData);
}
return result;
}

View File

@ -1,10 +0,0 @@
#pragma once
#include "ModuleDataMinimal.h"
#include <vector>
#include <wums.h>
class ModuleDataPersistence {
public:
static std::vector<std::shared_ptr<ModuleDataMinimal>> loadModuleData(module_information_t *moduleInformation);
};

View File

@ -1,264 +0,0 @@
#include "../../source/module/RelocationData.h"
#include "ElfUtils.h"
#include "ModuleDataPersistence.h"
#include "globals.h"
#include "hooks.h"
#include "utils/dynamic.h"
#include "utils/logger.h"
#include "utils/memory.h"
#include <algorithm>
#include <coreinit/cache.h>
#include <coreinit/dynload.h>
#include <coreinit/memexpheap.h>
#include <cstdint>
#include <map>
#include <string>
#include <vector>
MEMHeapHandle gHeapHandle __attribute__((section(".data"))) = nullptr;
uint8_t gFunctionsPatched __attribute__((section(".data"))) = 0;
uint8_t gInitCalled __attribute__((section(".data"))) = 0;
extern "C" void socket_lib_init();
std::vector<std::shared_ptr<ModuleDataMinimal>> OrderModulesByDependencies(const std::vector<std::shared_ptr<ModuleDataMinimal>> &loadedModules);
void CallInitHooksForModule(const std::shared_ptr<ModuleDataMinimal> &curModule);
extern "C" void doStart(int argc, char **argv);
// We need to wrap it to make sure the main function is called AFTER our code.
// The compiler tries to optimize this otherwise and calling the main function earlier
extern "C" int _start(int argc, char **argv) {
InitFunctionPointers();
static uint8_t ucSetupRequired = 1;
if (ucSetupRequired) {
gHeapHandle = MEMCreateExpHeapEx((void *) (MEMORY_REGION_USABLE_HEAP_START), MEMORY_REGION_USABLE_HEAP_END - MEMORY_REGION_USABLE_HEAP_START, 1);
ucSetupRequired = 0;
}
socket_lib_init();
log_init();
doStart(argc, argv);
DEBUG_FUNCTION_LINE_VERBOSE("Call real one\n");
log_deinit();
return ((int (*)(int, char **))(*(unsigned int *) 0x1005E040))(argc, argv);
}
bool doRelocation(std::vector<std::shared_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, bool skipAllocReplacement) {
std::map<std::string, OSDynLoad_Module> moduleCache;
for (auto const &curReloc : relocData) {
std::string functionName = curReloc->getName();
std::string rplName = curReloc->getImportRPLInformation()->getName();
uint32_t functionAddress = 0;
for (uint32_t i = 0; i < MAXIMUM_MODULES; i++) {
if (rplName == gModuleData->module_data[i].module_export_name) {
export_data_t *exportEntries = gModuleData->module_data[i].export_entries;
for (uint32_t j = 0; j < EXPORT_ENTRY_LIST_LENGTH; j++) {
if (functionName == exportEntries[j].name) {
functionAddress = (uint32_t) exportEntries[j].address;
}
}
}
}
if (!skipAllocReplacement) {
if (functionName == "MEMAllocFromDefaultHeap") {
functionAddress = reinterpret_cast<uint32_t>(&MEMAlloc);
} else if (functionName == "MEMAllocFromDefaultHeapEx") {
functionAddress = reinterpret_cast<uint32_t>(&MEMAllocEx);
} else if (functionName == "MEMFreeToDefaultHeap") {
functionAddress = reinterpret_cast<uint32_t>(&MEMFree);
}
}
if (functionAddress == 0) {
int32_t isData = curReloc->getImportRPLInformation()->isData();
OSDynLoad_Module rplHandle = nullptr;
if (moduleCache.count(rplName) == 0) {
OSDynLoad_Error err = OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle);
if (err != OS_DYNLOAD_OK || rplHandle == nullptr) {
DEBUG_FUNCTION_LINE_VERBOSE("%s is not yet loaded\n", rplName.c_str());
// only acquire if not already loaded.
err = OSDynLoad_Acquire(rplName.c_str(), &rplHandle);
if (err != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE("Failed to acquire %s\n", rplName.c_str());
//return false;
}
}
moduleCache[rplName] = rplHandle;
}
rplHandle = moduleCache.at(rplName);
OSDynLoad_FindExport(rplHandle, isData, functionName.c_str(), (void **) &functionAddress);
if (functionAddress == 0) {
OSFatal_printf("Failed to find export %s of %s", functionName.c_str(), rplName.c_str());
return false;
}
}
if (!ElfUtils::elfLinkOne(curReloc->getType(), curReloc->getOffset(), curReloc->getAddend(), (uint32_t) curReloc->getDestination(), functionAddress, tramp_data, tramp_length,
RELOC_TYPE_IMPORT)) {
DEBUG_FUNCTION_LINE("Relocation failed\n");
return false;
}
}
DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
return true;
}
bool ResolveRelocations(std::vector<std::shared_ptr<ModuleDataMinimal>> &loadedModules, bool skipMemoryMappingModule) {
bool wasSuccessful = true;
for (auto &curModule : loadedModules) {
DEBUG_FUNCTION_LINE_VERBOSE("Let's do the relocations for %s\n", curModule->getExportName().c_str());
if (wasSuccessful) {
auto relocData = curModule->getRelocationDataList();
// On first usage we can't redirect the alloc functions to our custom heap
// because threads can't run it on it. In order to patch the kernel
// to fully support our memory region, we have to run the FunctionPatcher and MemoryMapping
// once with the default heap. Afterwards we can just rely on the custom heap.
bool skipAllocFunction = skipMemoryMappingModule && (curModule->getExportName() == "homebrew_memorymapping" || curModule->getExportName() == "homebrew_functionpatcher");
DEBUG_FUNCTION_LINE_VERBOSE("Skip alloc replace? %d\n", skipAllocFunction);
if (!doRelocation(relocData, gModuleData->trampolines, DYN_LINK_TRAMPOLINE_LIST_LENGTH, skipAllocFunction)) {
DEBUG_FUNCTION_LINE("FAIL\n");
wasSuccessful = false;
curModule->relocationsDone = false;
}
curModule->relocationsDone = true;
}
}
DCFlushRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE);
ICInvalidateRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE);
return wasSuccessful;
}
extern "C" void doStart(int argc, char **argv) {
if (!gFunctionsPatched) {
gFunctionsPatched = 1;
}
DEBUG_FUNCTION_LINE("Loading module data\n");
auto loadedModulesUnordered = ModuleDataPersistence::loadModuleData(gModuleData);
auto loadedModules = OrderModulesByDependencies(loadedModulesUnordered);
bool applicationEndHookLoaded = false;
for (auto &curModule : loadedModules) {
if (curModule->getExportName() == "homebrew_applicationendshook") {
DEBUG_FUNCTION_LINE_VERBOSE("We have ApplicationEndsHook Module!\n");
applicationEndHookLoaded = true;
break;
}
}
// Make sure WUMS_HOOK_APPLICATION_ENDS and WUMS_HOOK_FINI_WUT are called
for (auto &curModule : loadedModules) {
for (auto &curHook : curModule->getHookDataList()) {
if (curHook->getType() == WUMS_HOOK_APPLICATION_ENDS || curHook->getType() == WUMS_HOOK_FINI_WUT_DEVOPTAB) {
if (!applicationEndHookLoaded) {
OSFatal_printf("%s requires module homebrew_applicationendshook", curModule->getExportName().c_str());
}
}
}
}
DEBUG_FUNCTION_LINE_VERBOSE("Number of modules %d\n", gModuleData->number_used_modules);
if (!gInitCalled) {
gInitCalled = 1;
DEBUG_FUNCTION_LINE_VERBOSE("Resolve relocations without replacing alloc functions\n");
ResolveRelocations(loadedModules, true);
for (auto &curModule : loadedModules) {
if (curModule->isInitBeforeRelocationDoneHook()) {
CallInitHooksForModule(curModule);
}
}
DEBUG_FUNCTION_LINE_VERBOSE("Call Relocations done hook\n");
CallHook(loadedModules, WUMS_HOOK_RELOCATIONS_DONE);
for (auto &curModule : loadedModules) {
if (!curModule->isInitBeforeRelocationDoneHook()) {
CallInitHooksForModule(curModule);
}
}
} else {
DEBUG_FUNCTION_LINE_VERBOSE("Resolve relocations and replace alloc functions\n");
ResolveRelocations(loadedModules, false);
CallHook(loadedModules, WUMS_HOOK_RELOCATIONS_DONE);
}
CallHook(loadedModules, WUMS_HOOK_INIT_WUT_DEVOPTAB);
CallHook(loadedModules, WUMS_HOOK_INIT_WUT_SOCKETS);
CallHook(loadedModules, WUMS_HOOK_APPLICATION_STARTS);
}
void CallInitHooksForModule(const std::shared_ptr<ModuleDataMinimal> &curModule) {
CallHook(curModule, WUMS_HOOK_INIT_WUT_MALLOC);
CallHook(curModule, WUMS_HOOK_INIT_WUT_NEWLIB);
CallHook(curModule, WUMS_HOOK_INIT_WUT_STDCPP);
CallHook(curModule, WUMS_HOOK_INIT_WUT_DEVOPTAB);
CallHook(curModule, WUMS_HOOK_INIT_WUT_SOCKETS);
CallHook(curModule, WUMS_HOOK_INIT_WRAPPER, !curModule->isSkipInitFini());
CallHook(curModule, WUMS_HOOK_INIT);
}
std::vector<std::shared_ptr<ModuleDataMinimal>> OrderModulesByDependencies(const std::vector<std::shared_ptr<ModuleDataMinimal>> &loadedModules) {
std::vector<std::shared_ptr<ModuleDataMinimal>> finalOrder;
std::vector<std::string> loadedModulesExportNames;
std::vector<uint32_t> loadedModulesEntrypoints;
while (true) {
bool canBreak = true;
bool weDidSomething = false;
for (auto const &curModule : loadedModules) {
if (std::find(loadedModulesEntrypoints.begin(), loadedModulesEntrypoints.end(), curModule->getEntrypoint()) != loadedModulesEntrypoints.end()) {
// DEBUG_FUNCTION_LINE("%s [%08X] is already loaded\n", curModule->getExportName().c_str(), curModule->getEntrypoint());
continue;
}
canBreak = false;
DEBUG_FUNCTION_LINE_VERBOSE("Check if we can load %s\n", curModule->getExportName().c_str());
std::vector<std::string> importsFromOtherModules;
for (const auto &curReloc : curModule->getRelocationDataList()) {
std::string curRPL = curReloc->getImportRPLInformation()->getName();
if (curRPL.rfind("homebrew", 0) == 0) {
if (std::find(importsFromOtherModules.begin(), importsFromOtherModules.end(), curRPL) != importsFromOtherModules.end()) {
// is already in vector
} else {
DEBUG_FUNCTION_LINE_VERBOSE("%s is importing from %s\n", curModule->getExportName().c_str(), curRPL.c_str());
importsFromOtherModules.push_back(curRPL);
}
}
}
bool canLoad = true;
for (auto &curImportRPL : importsFromOtherModules) {
if (std::find(loadedModulesExportNames.begin(), loadedModulesExportNames.end(), curImportRPL) != loadedModulesExportNames.end()) {
} else {
DEBUG_FUNCTION_LINE_VERBOSE("We can't load the module, because %s is not loaded yet\n", curImportRPL.c_str());
canLoad = false;
break;
}
}
if (canLoad) {
weDidSomething = true;
DEBUG_FUNCTION_LINE_VERBOSE("We can load: %s\n", curModule->getExportName().c_str());
finalOrder.push_back(curModule);
loadedModulesExportNames.push_back(curModule->getExportName());
loadedModulesEntrypoints.push_back(curModule->getEntrypoint());
}
}
if (canBreak) {
break;
} else if (!weDidSomething) {
OSFatal_printf("Failed to resolve dependencies.");
}
}
return finalOrder;
}

View File

@ -1,4 +0,0 @@
#include "globals.h"
uint32_t MemoryMappingEffectiveToPhysicalPTR = 0;
uint32_t MemoryMappingPhysicalToEffectivePTR = 0;

View File

@ -1,7 +0,0 @@
#pragma once
#include "../../source/globals.h"
#include <cstdint>
extern uint32_t MemoryMappingEffectiveToPhysicalPTR;
extern uint32_t MemoryMappingPhysicalToEffectivePTR;

View File

@ -1,13 +0,0 @@
#pragma once
#include "ModuleDataMinimal.h"
#include <vector>
#include <wums.h>
void CallHook(const std::vector<std::shared_ptr<ModuleDataMinimal>> &modules, wums_hook_type_t type, bool condition);
void CallHook(const std::vector<std::shared_ptr<ModuleDataMinimal>> &modules, wums_hook_type_t type);
void CallHook(const std::shared_ptr<ModuleDataMinimal> &module, wums_hook_type_t type, bool condition);
void CallHook(const std::shared_ptr<ModuleDataMinimal> &module, wums_hook_type_t type);

View File

@ -1,33 +0,0 @@
OUTPUT(loader.elf);
ENTRY(_start);
SECTIONS {
. = 0x00809000;
.text : {
*(.kernel_code*);
*(.text*);
/* Tell linker to not garbage collect this section as it is not referenced anywhere */
KEEP(*(.kernel_code*));
}
.sdata : {
*(.sdata*)
}
.data : {
*(.data*)
}
.rodata : {
*(.rodata*)
}
.sbss : {
*(.sbss*)
}
.bss : {
*(.bss*)
}
/DISCARD/ : {
*(*);
}
}
ASSERT((SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.sdata) + SIZEOF(.rodata) + SIZEOF(.sbss) + SIZEOF(.bss)) < 0x77000, "Memory overlapping with modules.");

View File

@ -1,141 +0,0 @@
#include "logger.h"
#include <coreinit/debug.h>
#include <coreinit/systeminfo.h>
#include <coreinit/thread.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int log_socket __attribute__((section(".data"))) = -1;
static struct sockaddr_in connect_addr __attribute__((section(".data")));
static volatile int log_lock __attribute__((section(".data"))) = 0;
#define SOL_SOCKET -1
#define SOCK_DGRAM 2
#define INADDR_ANY 0
#define INADDR_BROADCAST 0xFFFFFFFF
#define PF_UNSPEC 0
#define PF_INET 2
#define PF_INET6 23
#define AF_UNSPEC PF_UNSPEC
#define AF_INET PF_INET
#define AF_INET6 PF_INET6
#define IPPROTO_UDP 17
#define SO_BROADCAST 0x0020 // broadcast
typedef uint16_t sa_family_t;
struct in_addr {
unsigned int s_addr;
};
struct sockaddr {
sa_family_t sa_family;
char sa_data[];
};
struct sockaddr_in {
unsigned short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
typedef uint32_t socklen_t;
extern int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
extern int socket(int domain, int type, int protocol);
extern int socketclose(int sockfd);
extern int sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
extern uint32_t htonl(uint32_t val);
void log_init() {
int broadcastEnable = 1;
log_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (log_socket < 0)
return;
setsockopt(log_socket, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
memset(&connect_addr, 0, sizeof(struct sockaddr_in));
connect_addr.sin_family = AF_INET;
connect_addr.sin_port = 4405;
connect_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
}
void log_deinit() {
if (log_socket < 0) {
return;
}
if (socketclose(log_socket) != 0) {
return;
}
}
void log_print(const char *str) {
OSReport(str);
// socket is always 0 initially as it is in the BSS
if (log_socket < 0) {
return;
}
while (log_lock) {
OSSleepTicks(OSMicrosecondsToTicks(1000));
}
log_lock = 1;
int len = strlen(str);
int ret;
while (len > 0) {
int block = len < 1400 ? len : 1400; // take max 1400 bytes per UDP packet
ret = sendto(log_socket, str, block, 0, (struct sockaddr *) &connect_addr, sizeof(struct sockaddr_in));
if (ret < 0)
break;
len -= ret;
str += ret;
}
log_lock = 0;
}
void OSFatal_printf(const char *format, ...) {
char tmp[512];
tmp[0] = 0;
va_list va;
va_start(va, format);
if ((vsprintf(tmp, format, va) >= 0)) {
OSFatal(tmp);
}
va_end(va);
}
void log_printf(const char *format, ...) {
if (log_socket < 0) {
return;
}
char tmp[512];
tmp[0] = 0;
va_list va;
va_start(va, format);
if ((vsprintf(tmp, format, va) >= 0)) {
log_print(tmp);
}
va_end(va);
}

View File

@ -1,42 +0,0 @@
#ifndef __LOGGER_H_
#define __LOGGER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
void log_init();
void log_deinit(void);
void log_print(const char *str);
void log_printf(const char *format, ...);
void OSFatal_printf(const char *format, ...);
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
#define OSFATAL_FUNCTION_LINE(FMT, ARGS...) \
do { \
OSFatal_printf("[%s]%s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
} while (0)
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \
do { \
log_printf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
} while (0)
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) \
do { \
log_printf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
} while (0)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,53 +1,6 @@
#include "../wumsloader/src/elfio/elf_types.hpp"
#include "utils/logger.h"
#include <coreinit/cache.h>
#include <coreinit/debug.h>
#include <coreinit/memdefaultheap.h>
#include <whb/file.h>
#include <whb/log.h>
#include <whb/sdcard.h>
#include "ElfUtils.h"
#include "elfio/elfio.hpp"
int32_t LoadFileToMem(const char *relativefilepath, char **fileOut, uint32_t *sizeOut) {
char path[256];
int result = 0;
char *sdRootPath = nullptr;
if (!WHBMountSdCard()) {
DEBUG_FUNCTION_LINE("Failed to mount SD Card...");
result = -1;
goto exit;
}
sdRootPath = WHBGetSdCardMountPath();
sprintf(path, "%s/%s", sdRootPath, relativefilepath);
DEBUG_FUNCTION_LINE("Loading file %s.", path);
*fileOut = WHBReadWholeFile(path, sizeOut);
if (!(*fileOut)) {
result = -2;
DEBUG_FUNCTION_LINE("WHBReadWholeFile(%s) returned NULL", path);
goto exit;
}
exit:
WHBUnmountSdCard();
return result;
}
uint32_t load_loader_elf_from_sd(unsigned char *baseAddress, const char *relativePath) {
char *elf_data = nullptr;
uint32_t fileSize = 0;
if (LoadFileToMem(relativePath, &elf_data, &fileSize) != 0) {
OSFatal("Failed to load hook_payload.elf from the SD Card.");
}
uint32_t result = load_loader_elf(baseAddress, elf_data, fileSize);
MEMFreeToDefaultHeap((void *) elf_data);
return result;
}
uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fileSize) {
ELFIO::Elf32_Ehdr *ehdr;
@ -105,149 +58,4 @@ uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fi
}
return ehdr->e_entry;
}
// See https://github.com/decaf-emu/decaf-emu/blob/43366a34e7b55ab9d19b2444aeb0ccd46ac77dea/src/libdecaf/src/cafe/loader/cafe_loader_reloc.cpp#L144
bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
RelocationType reloc_type) {
if (type == R_PPC_NONE) {
return true;
}
auto target = destination + offset;
auto value = symbol_addr + addend;
auto relValue = value - static_cast<uint32_t>(target);
switch (type) {
case R_PPC_NONE:
break;
case R_PPC_ADDR32:
*((uint32_t *) (target)) = value;
break;
case R_PPC_ADDR16_LO:
*((uint16_t *) (target)) = static_cast<uint16_t>(value & 0xFFFF);
break;
case R_PPC_ADDR16_HI:
*((uint16_t *) (target)) = static_cast<uint16_t>(value >> 16);
break;
case R_PPC_ADDR16_HA:
*((uint16_t *) (target)) = static_cast<uint16_t>((value + 0x8000) >> 16);
break;
case R_PPC_DTPMOD32:
DEBUG_FUNCTION_LINE("################IMPLEMENT ME\n");
//*((int32_t *)(target)) = tlsModuleIndex;
break;
case R_PPC_DTPREL32:
*((uint32_t *) (target)) = value;
break;
case R_PPC_GHS_REL16_HA:
*((uint16_t *) (target)) = static_cast<uint16_t>((relValue + 0x8000) >> 16);
break;
case R_PPC_GHS_REL16_HI:
*((uint16_t *) (target)) = static_cast<uint16_t>(relValue >> 16);
break;
case R_PPC_GHS_REL16_LO:
*((uint16_t *) (target)) = static_cast<uint16_t>(relValue & 0xFFFF);
break;
case R_PPC_REL14: {
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
if (distance > 0x7FFC || distance < -0x7FFC) {
DEBUG_FUNCTION_LINE("***14-bit relative branch cannot hit target.");
return false;
}
if (distance & 3) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470040);
return false;
}
if ((distance >= 0 && (distance & 0xFFFF8000)) ||
(distance < 0 && ((distance & 0xFFFF8000) != 0xFFFF8000))) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 17 bits before shift must all be the same.", -470040);
return false;
}
*(int32_t *) target = (*(int32_t *) target & 0xFFBF0003) | (distance & 0x0000fffc);
break;
}
case R_PPC_REL24: {
// if (isWeakSymbol && !symbolValue) {
// symbolValue = static_cast<uint32_t>(target);
// value = symbolValue + addend;
// }
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) {
if (trampoline_data == nullptr) {
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline isn't provided\n");
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance);
return false;
} else {
relocation_trampoline_entry_t *freeSlot = nullptr;
for (uint32_t i = 0; i < trampoline_data_length; i++) {
// We want to override "old" relocations of imports
// Pending relocations have the status RELOC_TRAMP_IMPORT_IN_PROGRESS.
// When all relocations are done successfully, they will be turned into RELOC_TRAMP_IMPORT_DONE
// so they can be overridden/updated/reused on the next application launch.
//
// Relocations that won't change will have the status RELOC_TRAMP_FIXED and are set to free when the module is unloaded.
if (trampoline_data[i].status == RELOC_TRAMP_FREE ||
trampoline_data[i].status == RELOC_TRAMP_IMPORT_DONE) {
freeSlot = &(trampoline_data[i]);
break;
}
}
if (freeSlot == nullptr) {
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline data list is full\n");
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0])));
return false;
}
if (target - (uint32_t) & (freeSlot->trampoline[0]) > 0x1FFFFFC) {
DEBUG_FUNCTION_LINE("**Cannot link 24-bit jump (too far to tramp buffer).");
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0])));
return false;
}
freeSlot->trampoline[0] = 0x3D600000 | ((((uint32_t) value) >> 16) & 0x0000FFFF); // lis r11, real_addr@h
freeSlot->trampoline[1] = 0x616B0000 | (((uint32_t) value) & 0x0000ffff); // ori r11, r11, real_addr@l
freeSlot->trampoline[2] = 0x7D6903A6; // mtctr r11
freeSlot->trampoline[3] = 0x4E800420; // bctr
DCFlushRange((void *) freeSlot->trampoline, sizeof(freeSlot->trampoline));
ICInvalidateRange((unsigned char *) freeSlot->trampoline, sizeof(freeSlot->trampoline));
if (reloc_type == RELOC_TYPE_FIXED) {
freeSlot->status = RELOC_TRAMP_FIXED;
} else {
// Relocations for the imports may be overridden
freeSlot->status = RELOC_TRAMP_IMPORT_DONE;
}
auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]);
value = symbolValue + addend;
distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
}
}
if (distance & 3) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470022);
return false;
}
if (distance < 0 && (distance & 0xFE000000) != 0xFE000000) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (1).", -470040);
return false;
}
if (distance >= 0 && (distance & 0xFE000000)) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (0).", -470040);
return false;
}
*(int32_t *) target = (*(int32_t *) target & 0xfc000003) | (distance & 0x03fffffc);
break;
}
default:
DEBUG_FUNCTION_LINE("***ERROR: Unsupported Relocation_Add Type (%08X):", type);
return false;
}
return true;
}
}

View File

@ -1,52 +1,6 @@
#pragma once
#include <stdint.h>
#include <stdio.h>
#include <wums.h>
#include <cstdint>
#include <cstdio>
#ifdef __cplusplus
extern "C" {
#endif
int32_t LoadFileToMem(const char *relativefilepath, char **fileOut, uint32_t *sizeOut);
uint32_t load_loader_elf_from_sd(unsigned char *baseAddress, const char *relativePath);
uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fileSize);
#define R_PPC_NONE 0
#define R_PPC_ADDR32 1
#define R_PPC_ADDR16_LO 4
#define R_PPC_ADDR16_HI 5
#define R_PPC_ADDR16_HA 6
#define R_PPC_REL24 10
#define R_PPC_REL14 11
#define R_PPC_DTPMOD32 68
#define R_PPC_DTPREL32 78
#define R_PPC_EMB_SDA21 109
#define R_PPC_EMB_RELSDA 116
#define R_PPC_DIAB_SDA21_LO 180
#define R_PPC_DIAB_SDA21_HI 181
#define R_PPC_DIAB_SDA21_HA 182
#define R_PPC_DIAB_RELSDA_LO 183
#define R_PPC_DIAB_RELSDA_HI 184
#define R_PPC_DIAB_RELSDA_HA 185
#define R_PPC_GHS_REL16_HA 251
#define R_PPC_GHS_REL16_HI 252
#define R_PPC_GHS_REL16_LO 253
// Masks for manipulating Power PC relocation targets
#define PPC_WORD32 0xFFFFFFFF
#define PPC_WORD30 0xFFFFFFFC
#define PPC_LOW24 0x03FFFFFC
#define PPC_LOW14 0x0020FFFC
#define PPC_HALF16 0xFFFF
#ifdef __cplusplus
}
#endif
class ElfUtils {
public:
static bool elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
RelocationType reloc_type);
};

View File

@ -1,173 +0,0 @@
#include <fs/CFile.hpp>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
CFile::CFile() {
iFd = -1;
mem_file = NULL;
filesize = 0;
pos = 0;
}
CFile::CFile(const std::string &filepath, eOpenTypes mode) {
iFd = -1;
this->open(filepath, mode);
}
CFile::CFile(const uint8_t *mem, int32_t size) {
iFd = -1;
this->open(mem, size);
}
CFile::~CFile() {
this->close();
}
int32_t CFile::open(const std::string &filepath, eOpenTypes mode) {
this->close();
int32_t openMode = 0;
// This depend on the devoptab implementation.
// see https://github.com/devkitPro/wut/blob/master/libraries/wutdevoptab/devoptab_fs_open.c#L21 fpr reference
switch (mode) {
default:
case ReadOnly: // file must exist
openMode = O_RDONLY;
break;
case WriteOnly: // file will be created / zerod
openMode = O_TRUNC | O_CREAT | O_WRONLY;
break;
case ReadWrite: // file must exist
openMode = O_RDWR;
break;
case Append: // append to file, file will be created if missing. write only
openMode = O_CREAT | O_APPEND | O_WRONLY;
break;
}
//! Using fopen works only on the first launch as expected
//! on the second launch it causes issues because we don't overwrite
//! the .data sections which is needed for a normal application to re-init
//! this will be added with launching as RPX
iFd = ::open(filepath.c_str(), openMode);
if (iFd < 0)
return iFd;
filesize = ::lseek(iFd, 0, SEEK_END);
::lseek(iFd, 0, SEEK_SET);
return 0;
}
int32_t CFile::open(const uint8_t *mem, int32_t size) {
this->close();
mem_file = mem;
filesize = size;
return 0;
}
void CFile::close() {
if (iFd >= 0)
::close(iFd);
iFd = -1;
mem_file = NULL;
filesize = 0;
pos = 0;
}
int32_t CFile::read(uint8_t *ptr, size_t size) {
if (iFd >= 0) {
int32_t ret = ::read(iFd, ptr, size);
if (ret > 0)
pos += ret;
return ret;
}
int32_t readsize = size;
if (readsize > (int64_t) (filesize - pos))
readsize = filesize - pos;
if (readsize <= 0)
return readsize;
if (mem_file != NULL) {
memcpy(ptr, mem_file + pos, readsize);
pos += readsize;
return readsize;
}
return -1;
}
int32_t CFile::write(const uint8_t *ptr, size_t size) {
if (iFd >= 0) {
size_t done = 0;
while (done < size) {
int32_t ret = ::write(iFd, ptr, size - done);
if (ret <= 0)
return ret;
ptr += ret;
done += ret;
pos += ret;
}
return done;
}
return -1;
}
int32_t CFile::seek(long int offset, int32_t origin) {
int32_t ret = 0;
int64_t newPos = pos;
if (origin == SEEK_SET) {
newPos = offset;
} else if (origin == SEEK_CUR) {
newPos += offset;
} else if (origin == SEEK_END) {
newPos = filesize + offset;
}
if (newPos < 0) {
pos = 0;
} else {
pos = newPos;
}
if (iFd >= 0)
ret = ::lseek(iFd, pos, SEEK_SET);
if (mem_file != NULL) {
if (pos > filesize) {
pos = filesize;
}
}
return ret;
}
int32_t CFile::fwrite(const char *format, ...) {
char tmp[512];
tmp[0] = 0;
int32_t result = -1;
va_list va;
va_start(va, format);
if ((vsprintf(tmp, format, va) >= 0)) {
result = this->write((uint8_t *) tmp, strlen(tmp));
}
va_end(va);
return result;
}

View File

@ -1,71 +0,0 @@
#ifndef CFILE_HPP_
#define CFILE_HPP_
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <unistd.h>
#include <wut_types.h>
class CFile {
public:
enum eOpenTypes {
ReadOnly,
WriteOnly,
ReadWrite,
Append
};
CFile();
CFile(const std::string &filepath, eOpenTypes mode);
CFile(const uint8_t *memory, int32_t memsize);
virtual ~CFile();
int32_t open(const std::string &filepath, eOpenTypes mode);
int32_t open(const uint8_t *memory, int32_t memsize);
BOOL isOpen() const {
if (iFd >= 0)
return true;
if (mem_file)
return true;
return false;
}
void close();
int32_t read(uint8_t *ptr, size_t size);
int32_t write(const uint8_t *ptr, size_t size);
int32_t fwrite(const char *format, ...);
int32_t seek(long int offset, int32_t origin);
uint64_t tell() {
return pos;
};
uint64_t size() {
return filesize;
};
void rewind() {
this->seek(0, SEEK_SET);
};
protected:
int32_t iFd;
const uint8_t *mem_file;
uint64_t filesize;
uint64_t pos;
};
#endif

View File

@ -1,15 +0,0 @@
#pragma once
#include <cstdint>
#include <wums/defines/module_defines.h>
#define MEMORY_REGION_START 0x00800000
#define MEMORY_REGION_SIZE 0x00800000
#define MEMORY_REGION_USABLE_HEAP_START (MEMORY_REGION_START + 0x00080000) // We don't want to override the relocator
#define MEMORY_REGION_USABLE_HEAP_END (MEMORY_REGION_USABLE_HEAP_START + 0x00080000) // heap size is 512 KiB for now
#define MEMORY_REGION_USABLE_START MEMORY_REGION_USABLE_HEAP_END
#define MEMORY_REGION_USABLE_END 0x00FFF000 // The last 0x1000 bytes are reserved kernel hook
#define gModuleData ((module_information_t *) (MEMORY_REGION_USABLE_START))

View File

@ -1,20 +1,20 @@
#include "kernel.h"
#include "ElfUtils.h"
#include "relocator_elf.h"
#include "wumsloader_elf.h"
#include <coreinit/cache.h>
#include <coreinit/memorymap.h>
extern "C" void SCKernelCopyData(uint32_t addr, uint32_t src, uint32_t len);
extern "C" void SC_KernelCopyData(uint32_t addr, uint32_t src, uint32_t len);
void SetupRelocator() {
void SetupWUMSLoader() {
kern_write((void *) (KERN_SYSCALL_TBL_1 + (0x25 * 4)), (unsigned int) SCKernelCopyData);
kern_write((void *) (KERN_SYSCALL_TBL_2 + (0x25 * 4)), (unsigned int) SCKernelCopyData);
kern_write((void *) (KERN_SYSCALL_TBL_3 + (0x25 * 4)), (unsigned int) SCKernelCopyData);
kern_write((void *) (KERN_SYSCALL_TBL_4 + (0x25 * 4)), (unsigned int) SCKernelCopyData);
kern_write((void *) (KERN_SYSCALL_TBL_5 + (0x25 * 4)), (unsigned int) SCKernelCopyData);
uint32_t entryPoint = load_loader_elf(0, (char *) relocator_elf, relocator_elf_size);
uint32_t entryPoint = load_loader_elf(0, (char *) wumsloader_elf, wumsloader_elf_size);
unsigned int repl_addr = ADDRESS_main_entry_hook;
KernelWriteU32(repl_addr, 0x48000003 | entryPoint);

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include <cstdint>
#define ADDRESS_main_entry_hook 0x0101C56C
@ -10,7 +10,7 @@
#define KERN_SYSCALL_TBL_4 0xFFEAAA60 // works with home menu
#define KERN_SYSCALL_TBL_5 0xFFEAAE60 // works with browser (previously KERN_SYSCALL_TBL)
void SetupRelocator();
void SetupWUMSLoader();
void KernelWriteU32(uint32_t addr, uint32_t value);

View File

@ -1,51 +1,26 @@
#include <cstring>
#include <elfio/elfio.hpp>
#include "../wumsloader/src/globals.h"
#include "kernel.h"
#include "utils/logger.h"
#include <nn/act/client_cpp.h>
#include <sysapp/launch.h>
#include "ElfUtils.h"
#include "fs/DirList.h"
#include "globals.h"
#include "kernel.h"
#include "module/ModuleDataFactory.h"
#include "module/ModuleDataPersistence.h"
extern "C" uint32_t textStart();
extern "C" void __fini();
int main(int argc, char **argv) {
initLogging();
// We subtract 0x100 to be safe.
uint32_t textSectionStart = textStart() - 0x100;
memset((void *) gModuleData, 0, sizeof(module_information_t));
gModuleData->version = MODULE_INFORMATION_VERSION;
std::string basePath = "fs:/vol/external01/wiiu";
if (argc >= 1) {
basePath = argv[0];
}
DirList modules(basePath + "/modules", ".wms", DirList::Files, 1);
modules.SortList();
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#pragma GCC diagnostic ignored "-Wstringop-overflow="
strncpy(ENVRIONMENT_STRING, basePath.c_str(), ENVIRONMENT_PATH_LENGTH - 1);
#pragma GCC diagnostic pop
uint32_t destination_address = ((uint32_t) gModuleData + (sizeof(module_information_t) + 0x0000FFFF)) & 0xFFFF0000;
for (int i = 0; i < modules.GetFilecount(); i++) {
DEBUG_FUNCTION_LINE("Loading module %s", modules.GetFilepath(i));
auto moduleData = ModuleDataFactory::load(modules.GetFilepath(i), &destination_address, textSectionStart - destination_address, gModuleData->trampolines,
DYN_LINK_TRAMPOLINE_LIST_LENGTH);
if (moduleData) {
DEBUG_FUNCTION_LINE("Successfully loaded %s", modules.GetFilepath(i));
ModuleDataPersistence::saveModuleData(gModuleData, moduleData.value());
} else {
DEBUG_FUNCTION_LINE("Failed to load %s", modules.GetFilepath(i));
}
}
DEBUG_FUNCTION_LINE("Setup relocator");
SetupRelocator();
DEBUG_FUNCTION_LINE("Setup wumsloader");
SetupWUMSLoader();
nn::act::Initialize();
nn::act::SlotNo slot = nn::act::GetSlotNo();

View File

@ -1,111 +0,0 @@
#include "DynamicLinkingHelper.h"
#include "utils/logger.h"
#include <coreinit/dynload.h>
#include <cstdio>
#include <cstring>
#include <vector>
dyn_linking_function_t *DynamicLinkingHelper::getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName) {
if (data == nullptr) {
return nullptr;
}
if (functionName == nullptr) {
return nullptr;
}
dyn_linking_function_t *result = nullptr;
for (auto &function : data->functions) {
dyn_linking_function_t *curEntry = &function;
if (strlen(curEntry->functionName) == 0) {
if (strlen(functionName) > DYN_LINK_FUNCTION_NAME_LENGTH) {
DEBUG_FUNCTION_LINE("Failed to add function name, it's too long.\n");
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 &import : data->imports) {
dyn_linking_import_t *curEntry = &import;
if (strlen(curEntry->importName) == 0) {
if (strlen(importName) > DYN_LINK_IMPORT_NAME_LENGTH) {
DEBUG_FUNCTION_LINE("Failed to add Import, it's too long.\n");
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::addRelocationEntry(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, 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("Getting import info failed. Probably maximum of %d rpl files to import reached.\n", 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("Getting import info failed. Probably maximum of %d function to be relocated reached.\n", DYN_LINK_FUNCTION_LIST_LENGTH);
return false;
}
return addRelocationEntry(linking_entries, linking_entry_length, type, offset, addend, destination, functionInfo,
importInfoGbl);
}
bool DynamicLinkingHelper::addRelocationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, 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 = destination;
curEntry->functionEntry = functionName;
curEntry->importEntry = importInfo;
return true;
}
return false;
}

View File

@ -1,65 +0,0 @@
#pragma once
#include "RelocationData.h"
#include "utils/logger.h"
#include <string>
#include <vector>
#include <wums.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 addRelocationEntry(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,
void *destination, const std::string &name,
const std::shared_ptr<ImportRPLInformation> &rplInfo);
static bool
addRelocationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination,
dyn_linking_function_t *functionName, dyn_linking_import_t *importInfo);
private:
DynamicLinkingHelper() = default;
~DynamicLinkingHelper() = default;
};

View File

@ -1,10 +0,0 @@
#include "ModuleData.h"
#include "utils/StringTools.h"
std::string ModuleData::toString() const {
std::string res = StringTools::strfmt("Entrypoint %08X, bss: %08X (%d), bss: %08X (%d)\n", getEntrypoint(), getBSSAddr(), getBSSSize(), getSBSSAddr(), getSBSSSize());
for (auto const &reloc : relocation_data_list) {
res += reloc->toString();
}
return res;
}

View File

@ -1,181 +0,0 @@
#include "ModuleDataPersistence.h"
#include "DynamicLinkingHelper.h"
#include <coreinit/cache.h>
bool ModuleDataPersistence::saveModuleData(module_information_t *moduleInformation, const std::shared_ptr<ModuleData> &module) {
int32_t module_count = moduleInformation->number_used_modules;
if (module_count >= MAXIMUM_MODULES) {
DEBUG_FUNCTION_LINE("Reached maximum module count of %d", MAXIMUM_MODULES);
return false;
}
// Copy data to global struct.
module_information_single_t *module_data = &(moduleInformation->module_data[module_count]);
DEBUG_FUNCTION_LINE("Saving relocation data for module at %08X", module->getEntrypoint());
// Relocation
auto relocationData = module->getRelocationDataList();
for (auto const &reloc : relocationData) {
if (!DynamicLinkingHelper::addRelocationEntry(&(moduleInformation->linking_data), module_data->linking_entries,
DYN_LINK_RELOCATION_LIST_LENGTH, reloc)) {
DEBUG_FUNCTION_LINE("Failed to add relocation entry\n");
return false;
}
}
auto exportData = module->getExportDataList();
for (auto const &curExport : exportData) {
bool found = false;
for (auto &export_entry : module_data->export_entries) {
if (export_entry.address == 0) {
export_entry.type = curExport->getType();
export_entry.name[0] = '\0';
strncat(export_entry.name, curExport->getName().c_str(), sizeof(export_entry.name) - 1);
export_entry.address = (uint32_t) curExport->getAddress();
found = true;
break;
}
}
if (!found) {
DEBUG_FUNCTION_LINE("Failed to found enough exports slots");
break;
}
}
auto hookData = module->getHookDataList();
for (auto const &curHook : hookData) {
bool found = false;
for (auto &hook_entry : module_data->hook_entries) {
if (hook_entry.target == 0) {
hook_entry.type = curHook->getType();
hook_entry.target = (uint32_t) curHook->getTarget();
found = true;
break;
}
}
if (!found) {
DEBUG_FUNCTION_LINE("Failed to found enough hook slots");
break;
}
}
strncpy(module_data->module_export_name, module->getExportName().c_str(), MAXIMUM_EXPORT_MODULE_NAME_LENGTH);
uint32_t entryCount = module->getFunctionSymbolDataList().size();
if (entryCount > 0) {
auto ptr = &moduleInformation->function_symbols[moduleInformation->number_used_function_symbols];
module_data->function_symbol_entries = ptr;
uint32_t sym_offset = 0;
for (auto &curFuncSym : module->getFunctionSymbolDataList()) {
if (moduleInformation->number_used_function_symbols >= FUNCTION_SYMBOL_LIST_LENGTH) {
DEBUG_FUNCTION_LINE("Function symbol list is full");
break;
}
module_data->function_symbol_entries[sym_offset].address = curFuncSym->getAddress();
module_data->function_symbol_entries[sym_offset].name = (char *) curFuncSym->getName();
module_data->function_symbol_entries[sym_offset].size = curFuncSym->getSize();
sym_offset++;
moduleInformation->number_used_function_symbols++;
}
module_data->number_used_function_symbols = sym_offset;
} else {
module_data->function_symbol_entries = nullptr;
module_data->number_used_function_symbols = 0;
}
module_data->bssAddr = module->getBSSAddr();
module_data->bssSize = module->getBSSSize();
module_data->sbssAddr = module->getSBSSAddr();
module_data->sbssSize = module->getSBSSSize();
module_data->startAddress = module->getStartAddress();
module_data->endAddress = module->getEndAddress();
module_data->entrypoint = module->getEntrypoint();
module_data->skipInitFini = module->isSkipInitFini();
module_data->initBeforeRelocationDoneHook = module->isInitBeforeRelocationDoneHook();
moduleInformation->number_used_modules++;
DCFlushRange((void *) moduleInformation, sizeof(module_information_t));
ICInvalidateRange((void *) moduleInformation, sizeof(module_information_t));
return true;
}
std::vector<std::shared_ptr<ModuleData>> ModuleDataPersistence::loadModuleData(module_information_t *moduleInformation) {
std::vector<std::shared_ptr<ModuleData>> result;
if (moduleInformation == nullptr) {
DEBUG_FUNCTION_LINE("moduleInformation == NULL\n");
return result;
}
DCFlushRange((void *) moduleInformation, sizeof(module_information_t));
ICInvalidateRange((void *) moduleInformation, sizeof(module_information_t));
int32_t module_count = moduleInformation->number_used_modules;
if (module_count > MAXIMUM_MODULES) {
DEBUG_FUNCTION_LINE("moduleInformation->module_count was bigger then allowed. %d > %d. Limiting to %d\n", module_count, MAXIMUM_MODULES, MAXIMUM_MODULES);
module_count = MAXIMUM_MODULES;
}
for (int32_t i = 0; i < module_count; i++) {
// Copy data from struct.
module_information_single_t *module_data = &(moduleInformation->module_data[i]);
auto moduleData = std::make_shared<ModuleData>();
moduleData->setBSSLocation(module_data->bssAddr, module_data->bssSize);
moduleData->setSBSSLocation(module_data->sbssAddr, module_data->sbssSize);
moduleData->setEntrypoint(module_data->entrypoint);
moduleData->setStartAddress(module_data->startAddress);
moduleData->setEndAddress(module_data->endAddress);
moduleData->setExportName(module_data->module_export_name);
moduleData->setSkipInitFini(module_data->skipInitFini);
moduleData->setInitBeforeRelocationDoneHook(module_data->initBeforeRelocationDoneHook);
for (auto &export_entrie : module_data->export_entries) {
export_data_t *export_entry = &export_entrie;
if (export_entry->address == 0) {
continue;
}
auto exportData = std::make_shared<ExportData>(static_cast<wums_entry_type_t>(export_entry->type), export_entry->name, reinterpret_cast<const void *>(export_entry->address));
moduleData->addExportData(exportData);
}
for (auto &hook_entry : module_data->hook_entries) {
if (hook_entry.target == 0) {
continue;
}
auto hookData = std::make_shared<HookData>(static_cast<wums_hook_type_t>(hook_entry.type), reinterpret_cast<const void *>(hook_entry.target));
moduleData->addHookData(hookData);
}
for (auto &linking_entry : module_data->linking_entries) {
if (linking_entry.destination == nullptr) {
break;
}
dyn_linking_import_t *importEntry = linking_entry.importEntry;
if (importEntry == nullptr) {
DEBUG_FUNCTION_LINE("importEntry was NULL, skipping relocation entry\n");
continue;
}
dyn_linking_function_t *functionEntry = linking_entry.functionEntry;
if (functionEntry == nullptr) {
DEBUG_FUNCTION_LINE("functionEntry was NULL, skipping relocation entry\n");
continue;
}
auto rplInfo = std::make_shared<ImportRPLInformation>(importEntry->importName, importEntry->isData);
auto reloc = std::make_shared<RelocationData>(linking_entry.type, linking_entry.offset, linking_entry.addend, linking_entry.destination, functionEntry->functionName, rplInfo);
moduleData->addRelocationData(reloc);
}
if (module_data->function_symbol_entries != nullptr && module_data->number_used_function_symbols > 0) {
for (uint32_t j = 0; j < module_data->number_used_function_symbols; j++) {
auto symbol = &module_data->function_symbol_entries[j];
auto functionSymbolData = std::make_shared<FunctionSymbolData>(symbol->name, symbol->address, symbol->size);
moduleData->addFunctionSymbolData(functionSymbolData);
}
}
result.push_back(moduleData);
}
return result;
}

View File

@ -1,11 +0,0 @@
#pragma once
#include "ModuleData.h"
#include <wums.h>
class ModuleDataPersistence {
public:
static bool saveModuleData(module_information_t *moduleInformation, const std::shared_ptr<ModuleData> &module);
static std::vector<std::shared_ptr<ModuleData>> loadModuleData(module_information_t *moduleInformation);
};

View File

@ -1,7 +0,0 @@
#include "RelocationData.h"
#include "utils/StringTools.h"
std::string RelocationData::toString() const {
return StringTools::strfmt("%s destination: %08X offset: %08X type: %02X addend: %d rplName: %s isData: %d \n", name.c_str(), destination, offset, type, addend, rplInfo->getName().c_str(),
rplInfo->isData());
}

View File

@ -1,9 +0,0 @@
.section ".crt0"
.global textStart
textStart:
mflr 4;
bl a
mflr 3;
mtlr 4;
subi 3,3,0x8
a: blr

View File

@ -1,3 +0,0 @@
#pragma once
int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size);

View File

@ -1,289 +0,0 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <strings.h>
#include <utils/StringTools.h>
#include <vector>
#include <wchar.h>
#include <wut_types.h>
BOOL StringTools::EndsWith(const std::string &a, const std::string &b) {
if (b.size() > a.size())
return false;
return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
}
const char *StringTools::byte_to_binary(int32_t x) {
static char b[9];
b[0] = '\0';
int32_t z;
for (z = 128; z > 0; z >>= 1) {
strcat(b, ((x & z) == z) ? "1" : "0");
}
return b;
}
std::string StringTools::removeCharFromString(std::string &input, char toBeRemoved) {
std::string output = input;
size_t position;
while (1) {
position = output.find(toBeRemoved);
if (position == std::string::npos)
break;
output.erase(position, 1);
}
return output;
}
const char *StringTools::fmt(const char *format, ...) {
static char strChar[512];
strChar[0] = 0;
va_list va;
va_start(va, format);
if ((vsprintf(strChar, format, va) >= 0)) {
va_end(va);
return (const char *) strChar;
}
va_end(va);
return NULL;
}
const wchar_t *StringTools::wfmt(const char *format, ...) {
static char tmp[512];
static wchar_t strWChar[512];
strWChar[0] = 0;
tmp[0] = 0;
if (!format)
return (const wchar_t *) strWChar;
if (strcmp(format, "") == 0)
return (const wchar_t *) strWChar;
va_list va;
va_start(va, format);
if ((vsprintf(tmp, format, va) >= 0)) {
int bt;
int32_t strlength = strlen(tmp);
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512);
if (bt > 0) {
strWChar[bt] = 0;
return (const wchar_t *) strWChar;
}
}
va_end(va);
return NULL;
}
int32_t StringTools::strprintf(std::string &str, const char *format, ...) {
static char tmp[512];
tmp[0] = 0;
int32_t result = 0;
va_list va;
va_start(va, format);
if ((vsprintf(tmp, format, va) >= 0)) {
str = tmp;
result = str.size();
}
va_end(va);
return result;
}
std::string StringTools::strfmt(const char *format, ...) {
std::string str;
static char tmp[512];
tmp[0] = 0;
va_list va;
va_start(va, format);
if ((vsprintf(tmp, format, va) >= 0)) {
str = tmp;
}
va_end(va);
return str;
}
BOOL StringTools::char2wchar_t(const char *strChar, wchar_t *dest) {
if (!strChar || !dest)
return false;
int bt;
bt = mbstowcs(dest, strChar, strlen(strChar));
if (bt > 0) {
dest[bt] = 0;
return true;
}
return false;
}
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
if (!string || !compare)
return -1;
char TokCopy[512];
strncpy(TokCopy, compare, sizeof(TokCopy));
TokCopy[511] = '\0';
char *strTok = strtok(TokCopy, separator);
while (strTok != NULL) {
if (strcasecmp(string, strTok) == 0) {
return 0;
}
strTok = strtok(NULL, separator);
}
return -1;
}
int32_t StringTools::strextcmp(const char *string, const char *extension, char seperator) {
if (!string || !extension)
return -1;
char *ptr = strrchr(string, seperator);
if (!ptr)
return -1;
return strcasecmp(ptr + 1, extension);
}
std::vector<std::string> StringTools::stringSplit(const std::string &inValue, const std::string &splitter) {
std::string value = inValue;
std::vector<std::string> result;
while (true) {
uint32_t index = value.find(splitter);
if (index == std::string::npos) {
result.push_back(value);
break;
}
std::string first = value.substr(0, index);
result.push_back(first);
if (index + splitter.size() == value.length()) {
result.push_back("");
break;
}
if (index + splitter.size() > value.length()) {
break;
}
value = value.substr(index + splitter.size(), value.length());
}
return result;
}
const char *StringTools::FullpathToFilename(const char *path) {
if (!path)
return path;
const char *ptr = path;
const char *Filename = ptr;
while (*ptr != '\0') {
if (ptr[0] == '/' && ptr[1] != '\0')
Filename = ptr + 1;
++ptr;
}
return Filename;
}
void StringTools::RemoveDoubleSlashs(std::string &str) {
uint32_t length = str.size();
//! clear path of double slashes
for (uint32_t i = 1; i < length; ++i) {
if (str[i - 1] == '/' && str[i] == '/') {
str.erase(i, 1);
i--;
length--;
}
}
}
// You must free the result if result is non-NULL.
char *StringTools::str_replace(char *orig, char *rep, char *with) {
char *result; // the return string
char *ins; // the next insert point
char *tmp; // varies
int len_rep; // length of rep (the string to remove)
int len_with; // length of with (the string to replace rep with)
int len_front; // distance between rep and end of last rep
int count; // number of replacements
// sanity checks and initialization
if (!orig || !rep)
return NULL;
len_rep = strlen(rep);
if (len_rep == 0)
return NULL; // empty rep causes infinite loop during count
if (!with)
with = (char *) "";
len_with = strlen(with);
// count the number of replacements needed
ins = orig;
for (count = 0; (tmp = strstr(ins, rep)); ++count) {
ins = tmp + len_rep;
}
tmp = result = (char *) malloc(strlen(orig) + (len_with - len_rep) * count + 1);
if (!result)
return NULL;
// first time through the loop, all the variable are set correctly
// from here on,
// tmp points to the end of the result string
// ins points to the next occurrence of rep in orig
// orig points to the remainder of orig after "end of rep"
while (count--) {
ins = strstr(orig, rep);
len_front = ins - orig;
tmp = strncpy(tmp, orig, len_front) + len_front;
tmp = strcpy(tmp, with) + len_with;
orig += len_front + len_rep; // move to next "end of rep"
}
strcpy(tmp, orig);
return result;
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <coreinit/debug.h>
#include <string.h>
#include <whb/log.h>
@ -7,22 +8,33 @@
extern "C" {
#endif
#define LOG_APP_TYPE "M"
#define LOG_APP_NAME "WUMSInstaller"
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX(LOG_FUNC, "", "", FMT, ##ARGS)
#define LOG_EX(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \
do { \
LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
} while (0)
#ifdef DEBUG
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
#ifdef VERBOSE_DEBUG
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#else
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#endif
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \
do { \
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
} while (0)
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) \
do { \
WHBLogWritef("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
} while (0)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
#else
@ -32,6 +44,8 @@ extern "C" {
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
#endif
void initLogging();

View File

@ -1,38 +0,0 @@
#include "utils/logger.h"
#include <stddef.h>
#include <string.h>
#include <whb/log.h>
// https://gist.github.com/ccbrown/9722406
void dumpHex(const void *data, size_t size) {
char ascii[17];
size_t i, j;
ascii[16] = '\0';
DEBUG_FUNCTION_LINE_WRITE("0x%08X (0x0000): ", data);
for (i = 0; i < size; ++i) {
WHBLogWritef("%02X ", ((unsigned char *) data)[i]);
if (((unsigned char *) data)[i] >= ' ' && ((unsigned char *) data)[i] <= '~') {
ascii[i % 16] = ((unsigned char *) data)[i];
} else {
ascii[i % 16] = '.';
}
if ((i + 1) % 8 == 0 || i + 1 == size) {
WHBLogWritef(" ");
if ((i + 1) % 16 == 0) {
WHBLogPrintf("| %s ", ascii);
if (i + 1 < size) {
DEBUG_FUNCTION_LINE_WRITE("0x%08X (0x%04X); ", data + i + 1, i + 1);
}
} else if (i + 1 == size) {
ascii[(i + 1) % 16] = '\0';
if ((i + 1) % 16 <= 8) {
WHBLogWritef(" ");
}
for (j = (i + 1) % 16; j < 16; ++j) {
WHBLogWritef(" ");
}
WHBLogPrintf("| %s ", ascii);
}
}
}
}

View File

@ -1,41 +0,0 @@
#ifndef __UTILS_H_
#define __UTILS_H_
#include <malloc.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LIMIT(x, min, max) \
({ \
typeof(x) _x = x; \
typeof(min) _min = min; \
typeof(max) _max = max; \
(((_x) < (_min)) ? (_min) : ((_x) > (_max)) ? (_max) \
: (_x)); \
})
#define DegToRad(a) ((a) *0.01745329252f)
#define RadToDeg(a) ((a) *57.29577951f)
#define ALIGN4(x) (((x) + 3) & ~3)
#define ALIGN32(x) (((x) + 31) & ~31)
// those work only in powers of 2
#define ROUNDDOWN(val, align) ((val) & ~(align - 1))
#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align - 1)), align)
#define le16(i) ((((uint16_t) ((i) &0xFF)) << 8) | ((uint16_t) (((i) &0xFF00) >> 8)))
#define le32(i) ((((uint32_t) le16((i) &0xFFFF)) << 16) | ((uint32_t) le16(((i) &0xFFFF0000) >> 16)))
#define le64(i) ((((uint64_t) le32((i) &0xFFFFFFFFLL)) << 32) | ((uint64_t) le32(((i) &0xFFFFFFFF00000000LL) >> 32)))
//Needs to have log_init() called beforehand.
void dumpHex(const void *data, size_t size);
#ifdef __cplusplus
}
#endif
#endif // __UTILS_H_

View File

@ -23,6 +23,7 @@ export AR := $(PREFIX)ar
export OBJCOPY := $(PREFIX)objcopy
WUMS_ROOT := $(DEVKITPRO)/wums
WUT_ROOT := $(DEVKITPRO)/wut
#---------------------------------------------------------------------------------
# TARGET is the name of the output
@ -30,10 +31,14 @@ WUMS_ROOT := $(DEVKITPRO)/wums
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET := relocator
TARGET := wumsloader
BUILD := build
BUILD_DBG := $(TARGET)_dbg
SOURCES := src src/utils src/kernel
SOURCES := src \
src/utils \
src/kernel \
src/fs \
src/module
DATA := data
@ -42,10 +47,22 @@ INCLUDES := src
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS := -g -Wall -O3 -ffunction-sections $(MACHDEP) $(INCLUDE) -D__WIIU__ -D__WUT__
CFLAGS := -g -Wall -O0 -ffunction-sections $(MACHDEP) $(INCLUDE) -D__WIIU__ -D__WUT__
CXXFLAGS := $(CFLAGS) -std=c++20 -fno-exceptions -fno-rtti
ASFLAGS := -mregnames
LDFLAGS := -nostartfiles -Wl,--gc-sections
LDFLAGS := -Wl,--gc-sections,--allow-multiple-definition
ifeq ($(DEBUG),1)
export DEBUG=1
CXXFLAGS += -DDEBUG -g
CFLAGS += -DDEBUG -g
endif
ifeq ($(DEBUG),VERBOSE)
export DEBUG=VERBOSE
CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
endif
#---------------------------------------------------------------------------------
Q := @
@ -53,18 +70,13 @@ MAKEFLAGS += --no-print-directory
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lwums
LIBS := -lwums -lwut -lz
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(CURDIR) \
$(DEVKITPPC)/lib \
$(DEVKITPRO)/wut \
$(WUMS_ROOT) \
$(DEVKITPPC)/lib/gcc/powerpc-eabi/$(GCC_VER)
LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUMS_ROOT)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
@ -104,15 +116,10 @@ export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \
# build a list of include paths
#---------------------------------------------------------------------------------
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD) -I$(LIBOGC_INC) \
-I$(PORTLIBS)/include -I$(PORTLIBS)/include/freetype2
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
#---------------------------------------------------------------------------------
# build a list of library paths
#---------------------------------------------------------------------------------
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \
-L$(LIBOGC_LIB) -L$(PORTLIBS)/lib
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
export OUTPUT := $(CURDIR)/$(TARGET)
.PHONY: $(BUILD) clean install

View File

@ -1,5 +1,4 @@
# Setup payload - relocator
This is a payload that is bundled with the SetupPayload that handled the relocations for the imports.
# WUMSLoader
## Credits
- maschell

View File

@ -270,7 +270,7 @@ class section_impl : public section
ret = inflate(&s, Z_FINISH);
if (ret != Z_OK && ret != Z_STREAM_END){
DEBUG_FUNCTION_LINE("NOOOO");
DEBUG_FUNCTION_LINE_ERR("inflate section failed.");
}
inflateEnd(&s);
@ -288,7 +288,7 @@ class section_impl : public section
}
}else{
set_size(0);
DEBUG_FUNCTION_LINE("Failed to allocate memory.");
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory.");
}
}
}

189
wumsloader/src/entry.cpp Normal file
View File

@ -0,0 +1,189 @@
#include "entry.h"
#include "fs/DirList.h"
#include "globals.h"
#include "module/ModuleDataFactory.h"
#include "module/ModuleDataPersistence.h"
#include "utils/ElfUtils.h"
#include "utils/RelocationUtils.h"
#include "utils/dynamic.h"
#include "utils/hooks.h"
#include "utils/logger.h"
#include <coreinit/debug.h>
#include <coreinit/memexpheap.h>
#include <cstdint>
void CallInitHooksForModule(const std::shared_ptr<ModuleData> &curModule);
std::vector<std::shared_ptr<ModuleData>> OrderModulesByDependencies(const std::vector<std::shared_ptr<ModuleData>> &loadedModules);
// We need to wrap it to make sure the main function is called AFTER our code.
// The compiler tries to optimize this otherwise and calling the main function earlier
extern "C" int _start(int argc, char **argv) {
InitFunctionPointers();
static uint8_t ucSetupRequired = 1;
if (ucSetupRequired) {
gHeapHandle = MEMCreateExpHeapEx((void *) (MEMORY_REGION_USABLE_HEAP_START), MEMORY_REGION_USABLE_HEAP_END - MEMORY_REGION_USABLE_HEAP_START, 1);
if (!gHeapHandle) {
OSFatal("Failed to alloc heap");
}
__init();
ucSetupRequired = 0;
}
doStart(argc, argv);
return ((int (*)(int, char **))(*(unsigned int *) 0x1005E040))(argc, argv);
}
void doStart(int argc, char **argv) {
__init_wut();
initLogging();
if (!gInitCalled) {
gInitCalled = 1;
std::string basePath = ENVRIONMENT_STRING;
DEBUG_FUNCTION_LINE("We need to load the modules. basePath %s", basePath.c_str());
DirList modules(basePath + "/modules", ".wms", DirList::Files, 1);
modules.SortList();
for (int i = 0; i < modules.GetFilecount(); i++) {
DEBUG_FUNCTION_LINE("Loading module %s", modules.GetFilepath(i));
auto moduleData = ModuleDataFactory::load(modules.GetFilepath(i));
if (moduleData) {
DEBUG_FUNCTION_LINE("Successfully loaded %s", modules.GetFilepath(i));
gLoadedModules.push_back(std::move(moduleData.value()));
} else {
DEBUG_FUNCTION_LINE_ERR("Failed to load %s", modules.GetFilepath(i));
}
}
gModuleInformation = {.version = MODULE_INFORMATION_VERSION};
ModuleDataPersistence::saveModuleData(&gModuleInformation, gLoadedModules);
auto orderedModules = OrderModulesByDependencies(gLoadedModules);
// make sure the plugin backend module is at the end.
auto it = std::find_if(gLoadedModules.begin(),
gLoadedModules.end(),
[](auto &cur) { return std::string_view(cur->getExportName()) == "homebrew_wupsbackend"; });
if (it != gLoadedModules.end()) {
auto module = *it;
gLoadedModules.erase(it);
gLoadedModules.push_back(module);
}
bool applicationEndHookLoaded = false;
for (auto &curModule : gLoadedModules) {
if (std::string_view(curModule->getExportName()) == "homebrew_applicationendshook") {
DEBUG_FUNCTION_LINE_VERBOSE("We have ApplicationEndsHook Module!");
applicationEndHookLoaded = true;
break;
}
}
// Make sure WUMS_HOOK_APPLICATION_ENDS and WUMS_HOOK_FINI_WUT are called
for (auto &curModule : gLoadedModules) {
for (auto &curHook : curModule->getHookDataList()) {
if (curHook->getType() == WUMS_HOOK_APPLICATION_ENDS || curHook->getType() == WUMS_HOOK_FINI_WUT_DEVOPTAB) {
if (!applicationEndHookLoaded) {
DEBUG_FUNCTION_LINE_ERR("%s requires module homebrew_applicationendshook", curModule->getExportName().c_str());
OSFatal("module requires module homebrew_applicationendshook");
}
}
}
}
DEBUG_FUNCTION_LINE_VERBOSE("Resolve relocations without replacing alloc functions");
ResolveRelocations(gLoadedModules, true);
for (auto &curModule : gLoadedModules) {
if (curModule->isInitBeforeRelocationDoneHook()) {
CallInitHooksForModule(curModule);
}
}
DEBUG_FUNCTION_LINE_VERBOSE("Call Relocations done hook");
CallHook(gLoadedModules, WUMS_HOOK_RELOCATIONS_DONE);
for (auto &curModule : gLoadedModules) {
if (!curModule->isInitBeforeRelocationDoneHook()) {
CallInitHooksForModule(curModule);
}
}
} else {
DEBUG_FUNCTION_LINE("Resolve relocations and replace alloc functions");
ResolveRelocations(gLoadedModules, false);
CallHook(gLoadedModules, WUMS_HOOK_RELOCATIONS_DONE);
}
CallHook(gLoadedModules, WUMS_HOOK_INIT_WUT_DEVOPTAB);
CallHook(gLoadedModules, WUMS_HOOK_INIT_WUT_SOCKETS);
CallHook(gLoadedModules, WUMS_HOOK_APPLICATION_STARTS);
deinitLogging();
__fini_wut();
}
void CallInitHooksForModule(const std::shared_ptr<ModuleData> &curModule) {
CallHook(curModule, WUMS_HOOK_INIT_WUT_MALLOC);
CallHook(curModule, WUMS_HOOK_INIT_WUT_NEWLIB);
CallHook(curModule, WUMS_HOOK_INIT_WUT_STDCPP);
CallHook(curModule, WUMS_HOOK_INIT_WUT_DEVOPTAB);
CallHook(curModule, WUMS_HOOK_INIT_WUT_SOCKETS);
CallHook(curModule, WUMS_HOOK_INIT_WRAPPER, !curModule->isSkipInitFini());
CallHook(curModule, WUMS_HOOK_INIT);
}
std::vector<std::shared_ptr<ModuleData>> OrderModulesByDependencies(const std::vector<std::shared_ptr<ModuleData>> &loadedModules) {
std::vector<std::shared_ptr<ModuleData>> finalOrder;
std::vector<std::string_view> loadedModulesExportNames;
std::vector<uint32_t> loadedModulesEntrypoints;
while (true) {
bool canBreak = true;
bool weDidSomething = false;
for (auto const &curModule : loadedModules) {
if (std::find(loadedModulesEntrypoints.begin(), loadedModulesEntrypoints.end(), curModule->getEntrypoint()) != loadedModulesEntrypoints.end()) {
// DEBUG_FUNCTION_LINE("%s [%08X] is already loaded" curModule->getExportName().c_str(), curModule->getEntrypoint());
continue;
}
canBreak = false;
DEBUG_FUNCTION_LINE_VERBOSE("Check if we can load %s", curModule->getExportName());
std::vector<std::string_view> importsFromOtherModules;
for (const auto &curReloc : curModule->getRelocationDataList()) {
std::string_view curRPL = curReloc->getImportRPLInformation()->getRPLName();
if (curRPL == "homebrew_wupsbackend") {
OSFatal("Error: module depends on homebrew_wupsbackend, this is not supported");
}
if (curRPL.starts_with("homebrew")) {
if (std::find(importsFromOtherModules.begin(), importsFromOtherModules.end(), curRPL) == importsFromOtherModules.end()) {
DEBUG_FUNCTION_LINE_VERBOSE("%s is importing from %s", curModule->getExportName(), curRPL.begin());
importsFromOtherModules.push_back(curRPL);
}
}
}
bool canLoad = true;
for (auto &curImportRPL : importsFromOtherModules) {
if (std::find(loadedModulesExportNames.begin(), loadedModulesExportNames.end(), curImportRPL) == loadedModulesExportNames.end()) {
DEBUG_FUNCTION_LINE_VERBOSE("We can't load the module, because %s is not loaded yet", curImportRPL.begin());
canLoad = false;
break;
}
}
if (canLoad) {
weDidSomething = true;
DEBUG_FUNCTION_LINE_VERBOSE("We can load: %s", curModule->getExportName());
finalOrder.push_back(curModule);
loadedModulesExportNames.emplace_back(curModule->getExportName());
loadedModulesEntrypoints.push_back(curModule->getEntrypoint());
}
}
if (canBreak) {
break;
} else if (!weDidSomething) {
OSFatal("Failed to resolve dependencies.");
}
}
return finalOrder;
}

7
wumsloader/src/entry.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
extern "C" void __init();
extern "C" void __init_wut();
extern "C" void __fini_wut();
void doStart(int argc, char **argv);

View File

@ -1,21 +1,22 @@
#include "utils/logger.h"
#include <coreinit/memdefaultheap.h>
#include <cstdint>
#include <fcntl.h>
#include <malloc.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <unistd.h>
#define ROUNDDOWN(val, align) ((val) & ~(align - 1))
#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align - 1)), align)
int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) {
int32_t LoadFileToMem(const std::string &filepath, uint8_t **inbuffer, uint32_t *size) {
//! always initialze input
*inbuffer = NULL;
*inbuffer = nullptr;
if (size) {
*size = 0;
}
int32_t iFd = open(filepath, O_RDONLY);
int32_t iFd = open(filepath.c_str(), O_RDONLY);
if (iFd < 0) {
return -1;
}
@ -23,7 +24,7 @@ int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size)
uint32_t filesize = lseek(iFd, 0, SEEK_END);
lseek(iFd, 0, SEEK_SET);
auto *buffer = (uint8_t *) memalign(0x40, ROUNDUP(filesize, 0x40));
auto *buffer = (uint8_t *) MEMAllocFromDefaultHeapEx(ROUNDUP(filesize, 0x40), 0x40);
if (buffer == nullptr) {
close(iFd);
return -2;
@ -59,4 +60,4 @@ int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size)
}
return filesize;
}
}

View File

@ -0,0 +1,4 @@
#pragma once
#include <stdint.h>
int32_t LoadFileToMem(const std::string &filepath, uint8_t **inbuffer, uint32_t *size);

View File

@ -0,0 +1,7 @@
#include "globals.h"
MEMHeapHandle gHeapHandle __attribute__((section(".data"))) = nullptr;
uint8_t gInitCalled __attribute__((section(".data"))) = 0;
module_information_t gModuleInformation __attribute__((section(".data")));
std::vector<std::shared_ptr<ModuleData>> gLoadedModules __attribute__((section(".data")));
std::unique_ptr<module_information_single_t[]> gModuleDataInfo __attribute__((section(".data")));

25
wumsloader/src/globals.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include "module/ModuleData.h"
#include <coreinit/memheap.h>
#include <cstdint>
#include <memory>
extern uint8_t gInitCalled;
extern MEMHeapHandle gHeapHandle;
extern module_information_t gModuleInformation;
extern std::vector<std::shared_ptr<ModuleData>> gLoadedModules;
extern std::unique_ptr<module_information_single_t[]> gModuleDataInfo;
#define MEMORY_REGION_START 0x00800000
#define MEMORY_REGION_SIZE 0x00800000
#define CUSTOM_RPX_LOADER_RETURN_CODE 0x00009000 // We have to skip the first 0x00009000 bytes because it's still used
#define RELOCATOR_SIZE 0x130000 // Maximum size of the wumsloader, needs to match the one defined in link.ld
#define ENVIRONMENT_PATH_LENGTH 0x100 // Length of the EnvironmentPath.
#define MEMORY_REGION_ENVIRONMENT_STRING_ADRR (MEMORY_REGION_START + CUSTOM_RPX_LOADER_RETURN_CODE + RELOCATOR_SIZE)
#define MEMORY_REGION_USABLE_HEAP_START (MEMORY_REGION_ENVIRONMENT_STRING_ADRR + ENVIRONMENT_PATH_LENGTH)
#define MEMORY_REGION_USABLE_HEAP_END (0x00FFF000) // We need to leave space for the BAT hook
#define ENVRIONMENT_STRING ((char *) MEMORY_REGION_ENVIRONMENT_STRING_ADRR)

95
wumsloader/src/link.ld Normal file
View File

@ -0,0 +1,95 @@
OUTPUT(loader.elf);
ENTRY(_start);
SECTIONS {
. = 0x00809000;
.text ALIGN(32) : {
KEEP (*(.crt0))
KEEP (*(SORT_NONE(.init)))
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(SORT(.text.sorted.*))
*(.text .stub .text.* .gnu.linkonce.t.*)
*(.gnu.warning)
*(.glink)
KEEP (*(SORT_NONE(.fini)))
}
.rodata : {
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
*(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.rodata1)
*(.gcc_except_table .gcc_except_table.*)
*(.gnu_extab*)
. = ALIGN(4);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
PROVIDE_HIDDEN (__init_array_end = .);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
KEEP (*(.jcr))
*(.fixup)
*(.got1)
*(.got2)
*(.branch_lt)
*(.got)
*(.plt)
*(.tm_clone_table)
}
.eh_frame : {
*(.eh_frame_hdr)
*(.eh_frame_entry .eh_frame_entry.*)
KEEP (*(.eh_frame))
*(.eh_frame.*)
}
.data : {
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
*(.data1)
*(.sdata .sdata.* .gnu.linkonce.s.*)
}
.bss (NOLOAD) : {
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
}
/DISCARD/ : {
*(*);
}
}
ASSERT((SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.rodata) + SIZEOF(.eh_frame) + SIZEOF(.bss)) < 0x130000, "Memory overlapping with modules.");

View File

@ -6,9 +6,9 @@
class ExportData {
public:
ExportData(wums_entry_type_t type, const std::string &name, const void *address) {
ExportData(wums_entry_type_t type, std::string name, const void *address) {
this->type = type;
this->name = name;
this->name = std::move(name);
this->address = address;
}
@ -20,7 +20,7 @@ public:
return address;
}
[[nodiscard]] const std::string getName() const {
[[nodiscard]] const std::string &getName() const {
return name;
}

View File

@ -24,7 +24,7 @@ class FunctionSymbolData {
public:
FunctionSymbolData(const FunctionSymbolData &o2) = default;
FunctionSymbolData(const char *name, void *address, uint32_t size) : name(name),
FunctionSymbolData(std::string name, void *address, uint32_t size) : name(std::move(name)),
address(address),
size(size) {
}
@ -32,10 +32,10 @@ public:
virtual ~FunctionSymbolData() = default;
bool operator<(const FunctionSymbolData &rhs) const {
return (uint32_t) address < (uint32_t) rhs.address; //assume that you compare the record based on a
return (uint32_t) address < (uint32_t) rhs.address;
}
[[nodiscard]] const char *getName() const {
[[nodiscard]] const std::string &getName() const {
return name;
}
@ -47,9 +47,8 @@ public:
return size;
}
private:
const char *name;
std::string name;
void *address;
uint32_t size;
};

View File

@ -18,6 +18,7 @@
#pragma once
#include "utils/logger.h"
#include <coreinit/debug.h>
#include <memory>
#include <optional>
#include <string>
@ -26,44 +27,27 @@
class ImportRPLInformation {
public:
explicit ImportRPLInformation(std::string name, bool isData = false) {
this->name = std::move(name);
this->_isData = isData;
explicit ImportRPLInformation(std::string rawSectionName) {
this->name = std::move(rawSectionName);
}
~ImportRPLInformation() = default;
static std::optional<std::shared_ptr<ImportRPLInformation>> createImportRPLInformation(std::string rawSectionName) {
std::string fimport = ".fimport_";
std::string dimport = ".dimport_";
bool data = false;
std::string rplName;
if (rawSectionName.size() < fimport.size()) {
return std::nullopt;
} 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());
data = true;
} else {
DEBUG_FUNCTION_LINE("invalid section name\n");
return std::nullopt;
}
return std::make_shared<ImportRPLInformation>(rplName, data);
}
[[nodiscard]] std::string getName() const {
[[nodiscard]] const std::string &getName() const {
return name;
}
[[nodiscard]] const char *getRPLName() const {
if (name.max_size() < strlen("._import_") + 1) {
OSFatal("Invalid RPLName, is too short to be valid");
}
return name.c_str() + strlen("._import_");
}
[[nodiscard]] bool isData() const {
return _isData;
return name.starts_with(".dimport_");
}
private:
std::string name;
bool _isData = false;
};

View File

@ -54,51 +54,43 @@ public:
this->entrypoint = addr;
}
void setStartAddress(uint32_t addr) {
this->startAddress = addr;
void addRelocationData(std::unique_ptr<RelocationData> relocation_data) {
relocation_data_list.push_back(std::move(relocation_data));
}
void setEndAddress(uint32_t _endAddress) {
this->endAddress = _endAddress;
}
void addRelocationData(const std::shared_ptr<RelocationData> &relocation_data) {
relocation_data_list.push_back(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 addExportData(const std::shared_ptr<ExportData> &data) {
export_data_list.push_back(data);
void addExportData(std::unique_ptr<ExportData> data) {
export_data_list.push_back(std::move(data));
}
[[nodiscard]] const std::vector<std::shared_ptr<ExportData>> &getExportDataList() const {
[[nodiscard]] const std::vector<std::unique_ptr<ExportData>> &getExportDataList() const {
return export_data_list;
}
void addHookData(const std::shared_ptr<HookData> &data) {
hook_data_list.push_back(data);
void addHookData(std::unique_ptr<HookData> data) {
hook_data_list.push_back(std::move(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 addSectionInfo(const std::shared_ptr<SectionInfo> &sectionInfo) {
section_info_list[sectionInfo->getName()] = sectionInfo;
void addSectionInfo(std::shared_ptr<SectionInfo> sectionInfo) {
section_info_list[sectionInfo->getName()] = std::move(sectionInfo);
}
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;
}
[[nodiscard]] const std::map<std::string, std::shared_ptr<SectionInfo>> &getSectionInfoList() const {
[[nodiscard]] const std::map<std::string_view, std::shared_ptr<SectionInfo>> &getSectionInfoList() const {
return section_info_list;
}
@ -106,10 +98,10 @@ public:
if (getSectionInfoList().count(sectionName) > 0) {
return section_info_list.at(sectionName);
}
return std::nullopt;
return {};
}
[[nodiscard]] uint32_t getBSSAddr() const {
[[nodiscard]] uint32_t getBSSAddress() const {
return bssAddr;
}
@ -117,7 +109,7 @@ public:
return bssSize;
}
[[nodiscard]] uint32_t getSBSSAddr() const {
[[nodiscard]] uint32_t getSBSSAddress() const {
return sbssAddr;
}
@ -125,25 +117,23 @@ public:
return sbssSize;
}
[[nodiscard]] uint32_t getStartAddress() const {
return reinterpret_cast<uint32_t>(dataPtr.get());
}
[[nodiscard]] uint32_t getEndAddress() const {
return reinterpret_cast<uint32_t>(dataPtr.get()) + this->totalSize;
}
[[nodiscard]] uint32_t getEntrypoint() const {
return entrypoint;
}
[[nodiscard]] uint32_t getStartAddress() const {
return startAddress;
void setExportName(std::string name) {
this->export_name = std::move(name);
}
[[nodiscard]] uint32_t getEndAddress() const {
return endAddress;
}
[[nodiscard]] std::string toString() const;
void setExportName(const std::string &name) {
this->export_name = name;
}
[[nodiscard]] std::string getExportName() const {
[[nodiscard]] const std::string &getExportName() const {
return this->export_name;
}
@ -163,24 +153,33 @@ public:
this->skipInitFini = value;
}
bool relocationsDone = false;
void setDataPtr(std::unique_ptr<uint8_t[]> ptr, uint32_t size) {
this->dataPtr = std::move(ptr);
this->totalSize = size;
}
std::unique_ptr<hook_data_t[]> hookDataStruct;
std::unique_ptr<export_data_t[]> exportDataStruct;
std::unique_ptr<module_function_symbol_data_t[]> functionSymbolDataStruct;
std::unique_ptr<dyn_linking_import_t[]> rplDataStruct;
std::unique_ptr<dyn_linking_relocation_entry_t[]> relocationDataStruct;
private:
std::vector<std::shared_ptr<RelocationData>> relocation_data_list;
std::vector<std::shared_ptr<ExportData>> export_data_list;
std::vector<std::shared_ptr<HookData>> hook_data_list;
std::vector<std::unique_ptr<RelocationData>> relocation_data_list;
std::vector<std::unique_ptr<ExportData>> export_data_list;
std::vector<std::unique_ptr<HookData>> hook_data_list;
std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> symbol_data_list;
std::map<std::string, std::shared_ptr<SectionInfo>> section_info_list;
std::map<std::string_view, std::shared_ptr<SectionInfo>> section_info_list;
std::unique_ptr<uint8_t[]> dataPtr;
std::string export_name;
uint32_t bssAddr = 0;
uint32_t bssSize = 0;
uint32_t sbssAddr = 0;
uint32_t sbssSize = 0;
uint32_t startAddress = 0;
uint32_t endAddress = 0;
uint32_t entrypoint = 0;
uint32_t totalSize = 0;
bool initBeforeRelocationDoneHook = false;
bool skipInitFini = false;
};

View File

@ -1,5 +1,5 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
* Copyright (C) 2022 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
@ -16,54 +16,86 @@
****************************************************************************/
#include "ModuleDataFactory.h"
#include "ElfUtils.h"
#include "utils/FileUtils.h"
#include "utils/utils.h"
#include "fs/FileUtils.h"
#include "utils/ElfUtils.h"
#include "utils/logger.h"
#include <coreinit/cache.h>
#include <coreinit/memdefaultheap.h>
#include <map>
#include <string>
#include <vector>
#include <wums.h>
using namespace ELFIO;
std::optional<std::shared_ptr<ModuleData>>
ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_ptr, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length) {
std::optional<std::shared_ptr<ModuleData>> ModuleDataFactory::load(const std::string &path) {
elfio reader;
std::shared_ptr<ModuleData> moduleData = std::make_shared<ModuleData>();
auto moduleData = std::make_shared<ModuleData>();
if (!moduleData) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc module data");
return {};
}
uint8_t *buffer = nullptr;
uint32_t fsize = 0;
if (LoadFileToMem(path.c_str(), &buffer, &fsize) < 0) {
DEBUG_FUNCTION_LINE("Failed to load file");
if (LoadFileToMem(path, &buffer, &fsize) < 0) {
DEBUG_FUNCTION_LINE_ERR("Failed to load file");
return {};
}
// Load ELF data
if (!reader.load(reinterpret_cast<char *>(buffer), fsize)) {
DEBUG_FUNCTION_LINE("Can't find or process %s", path.c_str());
free(buffer);
DEBUG_FUNCTION_LINE_ERR("Can't find or process %s", path.c_str());
MEMFreeToDefaultHeap(buffer);
return {};
}
uint32_t sec_num = reader.sections.size();
auto destinations = std::make_unique<uint8_t *[]>(sec_num);
if (!destinations) {
DEBUG_FUNCTION_LINE_ERR("Failed alloc memory for destinations array");
MEMFreeToDefaultHeap(buffer);
return {};
}
uint32_t sec_num = reader.sections.size();
uint32_t totalSize = 0;
auto **destinations = (uint8_t **) malloc(sizeof(uint8_t *) * sec_num);
uint32_t text_size = 0;
uint32_t data_size = 0;
if (!destinations) {
DEBUG_FUNCTION_LINE("Failed to alloc memory for destinations");
free(buffer);
for (uint32_t i = 0; i < sec_num; ++i) {
auto *psec = reader.sections[i];
if (psec->get_type() == 0x80000002) {
continue;
}
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
uint32_t sectionSize = psec->get_size();
auto address = (uint32_t) psec->get_address();
if ((address >= 0x02000000) && address < 0x10000000) {
text_size += sectionSize;
} else if ((address >= 0x10000000) && address < 0xC0000000) {
data_size += sectionSize;
}
if (psec->get_name().rfind(".wums.", 0) == 0) {
data_size += sectionSize;
}
}
}
uint32_t baseOffset = *destination_address_ptr;
auto data = std::make_unique<uint8_t[]>(text_size + data_size);
if (!data) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes)", text_size);
MEMFreeToDefaultHeap(buffer);
return {};
}
uint32_t offset_text = baseOffset;
uint32_t offset_data = offset_text;
DEBUG_FUNCTION_LINE("Allocated %d kb", (text_size + data_size) / 1024);
uint32_t entrypoint = offset_text + (uint32_t) reader.get_entry() - 0x02000000;
void *text_data = data.get();
void *data_data = (void *) ((uint32_t) data.get() + text_size);
auto baseOffset = (uint32_t) data.get();
uint32_t totalSize = 0;
uint32_t endAddress = 0;
uint32_t entrypoint = (uint32_t) text_data + (uint32_t) reader.get_entry() - 0x02000000;
for (uint32_t i = 0; i < sec_num; ++i) {
section *psec = reader.sections[i];
@ -75,12 +107,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
uint32_t sectionSize = psec->get_size();
totalSize += sectionSize;
if (totalSize > maximum_size) {
DEBUG_FUNCTION_LINE("Couldn't load setup module because it's too big.");
free(destinations);
free(buffer);
return {};
}
auto address = (uint32_t) psec->get_address();
@ -91,7 +117,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
destination -= 0x02000000;
destinations[psec->get_index()] -= 0x02000000;
baseOffset += sectionSize;
offset_data += sectionSize;
} else if ((address >= 0x10000000) && address < 0xC0000000) {
destination -= 0x10000000;
destinations[psec->get_index()] -= 0x10000000;
@ -99,9 +124,8 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
destination -= 0xC0000000;
destinations[psec->get_index()] -= 0xC0000000;
} else {
DEBUG_FUNCTION_LINE("Unhandled case");
free(destinations);
free(buffer);
DEBUG_FUNCTION_LINE_ERR("Unhandled case");
MEMFreeToDefaultHeap(buffer);
return std::nullopt;
}
@ -115,10 +139,10 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
memcpy((void *) destination, p, sectionSize);
}
//nextAddress = ROUNDUP(destination + sectionSize, 0x100);
if (psec->get_name() == ".bss") {
moduleData->setBSSLocation(destination, sectionSize);
memset(reinterpret_cast<void *>(destination), 0, sectionSize);
} else if (psec->get_name() == ".sbss") {
moduleData->setSBSSLocation(destination, sectionSize);
memset(reinterpret_cast<void *>(destination), 0, sectionSize);
@ -127,10 +151,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
moduleData->addSectionInfo(sectionInfo);
DEBUG_FUNCTION_LINE("Saved %s section info. Location: %08X size: %08X", psec->get_name().c_str(), destination, sectionSize);
if (endAddress < destination + sectionSize) {
endAddress = destination + sectionSize;
}
DCFlushRange((void *) destination, sectionSize);
ICInvalidateRange((void *) destination, sectionSize);
}
@ -140,19 +160,14 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
section *psec = reader.sections[i];
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
DEBUG_FUNCTION_LINE("Linking (%d)... %s", i, psec->get_name().c_str());
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], offset_text, offset_data, trampoline_data, trampoline_data_length)) {
DEBUG_FUNCTION_LINE("elfLink failed");
free(destinations);
free(buffer);
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], (uint32_t) text_data, (uint32_t) data_data, nullptr, 0)) {
DEBUG_FUNCTION_LINE_ERR("elfLink failed");
MEMFreeToDefaultHeap(buffer);
return std::nullopt;
}
}
}
auto relocationData = getImportRelocationData(reader, destinations);
for (auto const &reloc : relocationData) {
moduleData->addRelocationData(reloc);
}
getImportRelocationData(moduleData, reader, destinations.get());
auto secInfo = moduleData->getSectionInfo(".wums.exports");
if (secInfo && secInfo.value()->getSize() > 0) {
@ -161,9 +176,12 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
if (entries != nullptr) {
for (size_t j = 0; j < entries_count; j++) {
wums_entry_t *exp = &entries[j];
DEBUG_FUNCTION_LINE("Saving export of type %08X, name %s, target: %08X" /*,pluginData.getPluginInformation()->getName().c_str()*/, exp->type, exp->name, (void *) exp->address);
auto exportData = std::make_shared<ExportData>(exp->type, exp->name, exp->address);
moduleData->addExportData(exportData);
DEBUG_FUNCTION_LINE("Saving export of type %08X, name %s, target: %08X", exp->type, exp->name, exp->address);
auto exportData = std::make_unique<ExportData>(exp->type, exp->name, exp->address);
if (!exportData) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc ExportData");
}
moduleData->addExportData(std::move(exportData));
}
}
}
@ -175,9 +193,12 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
if (hooks != nullptr) {
for (size_t j = 0; j < entries_count; j++) {
wums_hook_t *hook = &hooks[j];
DEBUG_FUNCTION_LINE("Saving hook of type %08X, target: %08X" /*,pluginData.getPluginInformation()->getName().c_str()*/, hook->type, hook->target);
auto hookData = std::make_shared<HookData>(hook->type, hook->target);
moduleData->addHookData(hookData);
DEBUG_FUNCTION_LINE("Saving hook of type %08X, target: %08X", hook->type, hook->target);
auto hookData = std::make_unique<HookData>(hook->type, hook->target);
if (!hookData) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc HookData");
}
moduleData->addHookData(std::move(hookData));
}
}
}
@ -201,7 +222,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
std::string value(curEntry + firstFound + 1);
if (key == "export_name") {
DEBUG_FUNCTION_LINE("export_name = %s", value.c_str());
moduleData->setExportName(value);
} else if (key == "skipInitFini") {
if (value == "true") {
@ -219,9 +239,8 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
}
} else if (key == "wums") {
if (value != "0.3") {
DEBUG_FUNCTION_LINE("Warning: Ignoring module - Unsupported WUMS version: %s.\n", value.c_str());
free(destinations);
free(buffer);
DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring module - Unsupported WUMS version: %s.", value.c_str());
MEMFreeToDefaultHeap(buffer);
return std::nullopt;
}
}
@ -231,9 +250,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
}
}
char *strTable = (char *) endAddress;
uint32_t strOffset = 0;
// Get the symbol for functions.
Elf_Half n = reader.sections.size();
for (Elf_Half i = 0; i < n; ++i) {
@ -258,14 +274,13 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
if (!sectionOpt.has_value()) {
continue;
}
auto finalAddress = offsetVal + sectionOpt.value()->getAddress();
uint32_t stringSize = name.size() + 1;
memcpy(strTable + strOffset, name.c_str(), stringSize);
moduleData->addFunctionSymbolData(std::make_shared<FunctionSymbolData>(strTable + strOffset, (void *) finalAddress, (uint32_t) size));
strOffset += stringSize;
totalSize += stringSize;
endAddress += stringSize;
auto finalAddress = offsetVal + sectionOpt.value()->getAddress();
auto functionSymbolData = std::make_shared<FunctionSymbolData>(name, (void *) finalAddress, (uint32_t) size);
if (!functionSymbolData) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc FunctionSymbolData");
} else {
moduleData->addFunctionSymbolData(std::move(functionSymbolData));
}
}
}
}
@ -274,41 +289,44 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
}
}
DCFlushRange((void *) *destination_address_ptr, totalSize);
ICInvalidateRange((void *) *destination_address_ptr, totalSize);
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);
free(buffer);
if (totalSize > text_size + data_size) {
DEBUG_FUNCTION_LINE_ERR("We didn't allocate enough memory!!");
OSFatal("We didn't allocate enough memory!!");
}
moduleData->setDataPtr(std::move(data), totalSize);
moduleData->setEntrypoint(entrypoint);
moduleData->setStartAddress(*destination_address_ptr);
moduleData->setEndAddress(endAddress);
DEBUG_FUNCTION_LINE("Saved entrypoint as %08X", entrypoint);
DEBUG_FUNCTION_LINE("Saved startAddress as %08X", *destination_address_ptr);
DEBUG_FUNCTION_LINE("Saved endAddress as %08X", endAddress);
DEBUG_FUNCTION_LINE("Saved startAddress as %08X", (uint32_t) data.get());
DEBUG_FUNCTION_LINE("Saved endAddress as %08X", (uint32_t) data.get() + totalSize);
*destination_address_ptr = (*destination_address_ptr + totalSize + 0x100) & 0xFFFFFF00;
DEBUG_FUNCTION_LINE("Loaded %s size: %d kilobytes", path.c_str(), totalSize / 1024);
MEMFreeToDefaultHeap(buffer);
return moduleData;
}
std::vector<std::shared_ptr<RelocationData>> ModuleDataFactory::getImportRelocationData(elfio &reader, uint8_t **destinations) {
std::vector<std::shared_ptr<RelocationData>> result;
std::map<uint32_t, std::string> infoMap;
void ModuleDataFactory::getImportRelocationData(std::shared_ptr<ModuleData> &moduleData, ELFIO::elfio &reader, 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();
infoMap[i] = std::make_shared<ImportRPLInformation>(psec->get_name());
}
}
for (uint32_t i = 0; i < sec_num; ++i) {
section *psec = reader.sections[i];
if (psec->get_type() == SHT_RELA || psec->get_type() == SHT_REL) {
DEBUG_FUNCTION_LINE("Found relocation section %s", psec->get_name().c_str());
relocation_section_accessor rel(reader, psec);
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
Elf64_Addr offset;
@ -319,30 +337,39 @@ std::vector<std::shared_ptr<RelocationData>> ModuleDataFactory::getImportRelocat
Elf_Half sym_section_index;
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
DEBUG_FUNCTION_LINE("Failed to get relocation");
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
OSFatal("Failed to get relocation");
break;
}
// uint32_t adjusted_sym_value = (uint32_t) sym_value;
if (infoMap.count(sym_section_index) == 0) {
auto adjusted_sym_value = (uint32_t) sym_value;
if (adjusted_sym_value < 0xC0000000) {
continue;
}
auto rplInfo = ImportRPLInformation::createImportRPLInformation(infoMap[sym_section_index]);
if (!rplInfo) {
DEBUG_FUNCTION_LINE("Failed to create import information");
break;
}
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());
OSFatal("Relocation is referencing a unknown section.");
}
// When these relocations are performed, we don't need the 0xC0000000 offset anymore.
auto relocationData = std::make_shared<RelocationData>(type, offset - 0x02000000, addend, (void *) (destinations[section_index] + 0x02000000), sym_name, rplInfo.value());
//relocationData->printInformation();
result.push_back(relocationData);
auto relocationData = std::make_unique<RelocationData>(type,
offset - 0x02000000,
addend,
(void *) (destinations[section_index] + 0x02000000),
sym_name,
infoMap[sym_section_index]);
if (!relocationData) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc relocation data");
OSFatal("Failed to alloc relocation data");
continue;
}
moduleData->addRelocationData(std::move(relocationData));
}
}
}
return result;
}
bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
@ -352,7 +379,7 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3
for (uint32_t i = 0; i < sec_num; ++i) {
section *psec = reader.sections[i];
if (psec->get_info() == section_index) {
DEBUG_FUNCTION_LINE("Found relocation section %s", psec->get_name().c_str());
DEBUG_FUNCTION_LINE_VERBOSE("Found relocation section %s", psec->get_name().c_str());
relocation_section_accessor rel(reader, psec);
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
Elf64_Addr offset;
@ -363,7 +390,8 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3
Elf_Half sym_section_index;
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
DEBUG_FUNCTION_LINE("Failed to get relocation");
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
OSFatal("Failed to get relocation");
break;
}
@ -380,23 +408,21 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3
} else if (adjusted_sym_value == 0x0) {
//
} else {
DEBUG_FUNCTION_LINE("Unhandled case %08X", adjusted_sym_value);
DEBUG_FUNCTION_LINE_ERR("Unhandled case %08X", adjusted_sym_value);
return false;
}
if (sym_section_index == SHN_ABS) {
//
} else if (sym_section_index > SHN_LORESERVE) {
DEBUG_FUNCTION_LINE("NOT IMPLEMENTED: %04X", sym_section_index);
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED: %04X", sym_section_index);
return false;
}
if (!ElfUtils::elfLinkOne(type, offset, addend, destination, adjusted_sym_value, trampoline_data, trampoline_data_length, RELOC_TYPE_FIXED)) {
DEBUG_FUNCTION_LINE("Link failed");
DEBUG_FUNCTION_LINE_ERR("Link failed");
return false;
}
}
DEBUG_FUNCTION_LINE("done");
}
}
return true;

View File

@ -1,5 +1,5 @@
/****************************************************************************
* Copyright (C) 2019 Maschell
* Copyright (C) 2022 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
@ -19,6 +19,7 @@
#include "ModuleData.h"
#include "elfio/elfio.hpp"
#include <coreinit/memheap.h>
#include <map>
#include <string>
#include <vector>
@ -26,11 +27,15 @@
class ModuleDataFactory {
public:
static std::optional<std::shared_ptr<ModuleData>>
load(const std::string &path, uint32_t *destination_address_ptr, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length);
static std::optional<std::shared_ptr<ModuleData>> load(const std::string &path);
static bool linkSection(ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
static bool linkSection(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);
static std::vector<std::shared_ptr<RelocationData>> getImportRelocationData(ELFIO::elfio &reader, uint8_t **destinations);
static void getImportRelocationData(std::shared_ptr<ModuleData> &moduleData, ELFIO::elfio &reader, uint8_t **destinations);
};

View File

@ -0,0 +1,211 @@
#include "ModuleDataPersistence.h"
#include "globals.h"
#include <coreinit/cache.h>
bool ModuleDataPersistence::saveModuleData(module_information_t *moduleInformation, const std::vector<std::shared_ptr<ModuleData>> &moduleList) {
auto module_data_list = std::make_unique<module_information_single_t[]>(moduleList.size());
if (!module_data_list) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory to persist module data");
return false;
}
moduleInformation->modules = module_data_list.get();
uint32_t i = 0;
for (auto &module : moduleList) {
auto &module_data = module_data_list[i];
module_data = {};
if (!saveModuleData(module_data, module)) {
module->relocationDataStruct.reset();
module->hookDataStruct.reset();
module->exportDataStruct.reset();
module->functionSymbolDataStruct.reset();
module->rplDataStruct.reset();
DEBUG_FUNCTION_LINE_ERR("Failed to persist data for module. No memory?");
OSFatal("Failed to persist data for module. No memory?");
continue;
} else {
moduleInformation->number_modules++;
i++;
}
}
gModuleDataInfo = std::move(module_data_list);
OSMemoryBarrier();
return true;
}
bool ModuleDataPersistence::saveModuleData(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module) {
if (!saveRelocationDataForModule(module_data, module)) {
DEBUG_FUNCTION_LINE_ERR("Failed to store relocation data of module");
return false;
}
if (!saveHookDataForModule(module_data, module)) {
DEBUG_FUNCTION_LINE_ERR("Failed to store hook data of module");
return false;
}
if (!saveExportDataForModule(module_data, module)) {
DEBUG_FUNCTION_LINE_ERR("Failed to store export data of module");
return false;
}
if (!saveFunctionSymbolDataForModule(module_data, module)) {
DEBUG_FUNCTION_LINE_ERR("Failed to store function symbol data of module");
return false;
}
module_data.module_export_name = (char *) module->getExportName().c_str();
module_data.bssAddr = module->getBSSAddress();
module_data.bssSize = module->getBSSSize();
module_data.sbssAddr = module->getSBSSAddress();
module_data.sbssSize = module->getSBSSSize();
module_data.startAddress = module->getStartAddress();
module_data.endAddress = module->getEndAddress();
module_data.entrypoint = module->getEntrypoint();
module_data.skipInitFini = module->isSkipInitFini();
module_data.initBeforeRelocationDoneHook = module->isInitBeforeRelocationDoneHook();
return true;
}
bool ModuleDataPersistence::saveFunctionSymbolDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module) {
uint32_t entryCount = module->getFunctionSymbolDataList().size();
auto function_symbol_data = std::make_unique<module_function_symbol_data_t[]>(entryCount);
if (!function_symbol_data) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the function symbol data.");
return false;
}
uint32_t i = 0;
for (auto &curFuncSym : module->getFunctionSymbolDataList()) {
if (i >= entryCount) {
DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for.");
OSFatal("We tried to write more entries than we have space for.");
}
function_symbol_data[i].address = curFuncSym->getAddress();
function_symbol_data[i].name = (char *) curFuncSym->getName().c_str();
function_symbol_data[i].size = curFuncSym->getSize();
i++;
}
module_data.function_symbol_entries = function_symbol_data.get();
module_data.number_function_symbols = i;
module->functionSymbolDataStruct = std::move(function_symbol_data);
return true;
}
bool ModuleDataPersistence::saveExportDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module) {
auto export_data = std::make_unique<export_data_t[]>(module->getExportDataList().size());
if (!export_data) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the export data.");
return false;
}
uint32_t exportCount = 0;
for (auto const &export_ : module->getExportDataList()) {
if (exportCount >= module->getExportDataList().size()) {
DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for.");
OSFatal("We tried to write more entries than we have space for.");
}
auto *curExport = &export_data[exportCount++];
curExport->type = export_->getType();
curExport->name = export_->getName().c_str();
curExport->address = (uint32_t) export_->getAddress();
}
module_data.export_entries = export_data.get();
module_data.number_export_entries = exportCount;
module->exportDataStruct = std::move(export_data);
return true;
}
bool ModuleDataPersistence::saveHookDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module) {
auto hook_data = std::make_unique<hook_data_t[]>(module->getHookDataList().size());
if (!hook_data) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the hook data.");
return false;
}
uint32_t hookCount = 0;
for (auto const &hook : module->getHookDataList()) {
if (hookCount >= module->getHookDataList().size()) {
DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for.");
OSFatal("We tried to write more entries than we have space for.");
}
auto *curHook = &hook_data[hookCount++];
curHook->type = hook->getType();
curHook->target = (uint32_t) hook->getTarget();
}
module_data.hook_entries = hook_data.get();
module_data.number_hook_entries = hookCount;
module->hookDataStruct = std::move(hook_data);
return true;
}
bool ModuleDataPersistence::saveRelocationDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module) {
auto relocation_data = std::make_unique<dyn_linking_relocation_entry_t[]>(module->getRelocationDataList().size());
if (!relocation_data) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the relocation data.");
return false;
}
// Determine how many dyn_linking_import_t entries we need.
std::set<std::string_view> rplInfoCountSet;
for (auto const &reloc : module->getRelocationDataList()) {
rplInfoCountSet.insert(reloc->getImportRPLInformation()->getName());
}
uint32_t rplInfoTotalCount = rplInfoCountSet.size();
rplInfoCountSet.clear();
auto rpl_data = std::make_unique<dyn_linking_import_t[]>(rplInfoTotalCount);
if (!rpl_data) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the RPLInfos.");
return false;
}
uint32_t relocationCount = 0;
uint32_t rplInfoCount = 0;
std::map<std::string_view, dyn_linking_import_t *> rplInfoMap;
for (auto const &reloc : module->getRelocationDataList()) {
if (relocationCount >= module->getRelocationDataList().size()) {
DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for.");
OSFatal("We tried to write more entries than we have space for.");
}
auto *curReloc = &relocation_data[relocationCount++];
curReloc->destination = reloc->getDestination();
curReloc->offset = reloc->getOffset();
curReloc->addend = reloc->getAddend();
curReloc->type = reloc->getType();
curReloc->functionName = reloc->getName().c_str();
auto &rplInfo = reloc->getImportRPLInformation();
auto rplIt = rplInfoMap.find(rplInfo->getName());
if (rplIt != rplInfoMap.end()) {
curReloc->importEntry = rplIt->second;
} else {
if (rplInfoCount >= rplInfoTotalCount) {
DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for.");
OSFatal("We tried to write more entries than we have space for.");
}
auto *rplInfoPtr = &rpl_data[rplInfoCount++];
rplInfoPtr->isData = rplInfo->isData();
rplInfoPtr->importName = rplInfo->getName().c_str();
rplInfoMap[rplInfo->getName()] = rplInfoPtr;
curReloc->importEntry = rplInfoPtr;
}
}
module_data.linking_entries = relocation_data.get();
module_data.number_linking_entries = relocationCount;
module->relocationDataStruct = std::move(relocation_data);
module->rplDataStruct = std::move(rpl_data);
return true;
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "ModuleData.h"
#include <coreinit/memheap.h>
#include <wums.h>
class ModuleDataPersistence {
public:
static bool saveModuleData(module_information_t *moduleInformation, const std::vector<std::shared_ptr<ModuleData>> &moduleList);
static bool saveModuleData(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module);
static bool saveRelocationDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module);
static bool saveExportDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module);
static bool saveHookDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module);
static bool saveFunctionSymbolDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module);
};

View File

@ -51,16 +51,14 @@ public:
return destination;
}
[[nodiscard]] std::string getName() const {
[[nodiscard]] const std::string &getName() const {
return name;
}
[[nodiscard]] std::shared_ptr<ImportRPLInformation> getImportRPLInformation() const {
[[nodiscard]] const std::shared_ptr<ImportRPLInformation> &getImportRPLInformation() const {
return rplInfo;
}
[[nodiscard]] std::string toString() const;
private:
char type;
size_t offset;

View File

@ -1,5 +1,5 @@
/****************************************************************************
* Copyright (C) 2019 Maschell
* Copyright (C) 2022 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
@ -30,14 +30,10 @@ public:
SectionInfo() = default;
SectionInfo(const SectionInfo &o2) : name(o2.name),
address(o2.address),
sectionSize(o2.sectionSize) {
}
SectionInfo(const SectionInfo &o2) = default;
SectionInfo &operator=(const SectionInfo &other) = default;
virtual ~SectionInfo() = default;
[[nodiscard]] const std::string &getName() const {

View File

@ -1,4 +1,5 @@
#include <coreinit/cache.h>
#include <valarray>
#include "ElfUtils.h"
#include "utils/logger.h"
@ -9,6 +10,7 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
if (type == R_PPC_NONE) {
return true;
}
auto target = destination + offset;
auto value = symbol_addr + addend;
@ -30,7 +32,7 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
*((uint16_t *) (target)) = static_cast<uint16_t>((value + 0x8000) >> 16);
break;
case R_PPC_DTPMOD32:
DEBUG_FUNCTION_LINE("################IMPLEMENT ME\n");
DEBUG_FUNCTION_LINE_ERR("################IMPLEMENT ME");
//*((int32_t *)(target)) = tlsModuleIndex;
break;
case R_PPC_DTPREL32:
@ -48,18 +50,18 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
case R_PPC_REL14: {
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
if (distance > 0x7FFC || distance < -0x7FFC) {
DEBUG_FUNCTION_LINE("***14-bit relative branch cannot hit target.");
DEBUG_FUNCTION_LINE_ERR("***14-bit relative branch cannot hit target.");
return false;
}
if (distance & 3) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470040);
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470040);
return false;
}
if ((distance >= 0 && (distance & 0xFFFF8000)) ||
(distance < 0 && ((distance & 0xFFFF8000) != 0xFFFF8000))) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 17 bits before shift must all be the same.", -470040);
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: upper 17 bits before shift must all be the same.", -470040);
return false;
}
@ -74,8 +76,8 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) {
if (trampoline_data == nullptr) {
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline isn't provided\n");
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance);
DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline isn't provided");
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, distance);
return false;
} else {
relocation_trampoline_entry_t *freeSlot = nullptr;
@ -93,14 +95,20 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
}
}
if (freeSlot == nullptr) {
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline data list is full\n");
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0])));
DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline data list is full");
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, target - (uint32_t) & (freeSlot->trampoline[0]));
return false;
}
if (target - (uint32_t) & (freeSlot->trampoline[0]) > 0x1FFFFFC) {
DEBUG_FUNCTION_LINE("**Cannot link 24-bit jump (too far to tramp buffer).");
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0])));
auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]);
auto newValue = symbolValue + addend;
auto newDistance = static_cast<int32_t>(newValue) - static_cast<int32_t>(target);
if (newDistance > 0x1FFFFFC || newDistance < -0x1FFFFFC) {
DEBUG_FUNCTION_LINE_ERR("**Cannot link 24-bit jump (too far to tramp buffer).");
if (newDistance < 0) {
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance -%08X", newValue, target, abs(newDistance));
} else {
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", newValue, target, newDistance);
}
return false;
}
@ -117,24 +125,22 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
// Relocations for the imports may be overridden
freeSlot->status = RELOC_TRAMP_IMPORT_DONE;
}
auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]);
value = symbolValue + addend;
distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
distance = newDistance;
}
}
if (distance & 3) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470022);
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470022);
return false;
}
if (distance < 0 && (distance & 0xFE000000) != 0xFE000000) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (1).", -470040);
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: upper 7 bits before shift must all be the same (1).", -470040);
return false;
}
if (distance >= 0 && (distance & 0xFE000000)) {
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (0).", -470040);
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: upper 7 bits before shift must all be the same (0).", -470040);
return false;
}
@ -142,8 +148,10 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
break;
}
default:
DEBUG_FUNCTION_LINE("***ERROR: Unsupported Relocation_Add Type (%08X):", type);
DEBUG_FUNCTION_LINE_ERR("***ERROR: Unsupported Relocation_Add Type (%08X):", type);
return false;
}
ICInvalidateRange(reinterpret_cast<void *>(target), 4);
DCFlushRange(reinterpret_cast<void *>(target), 4);
return true;
}

View File

@ -0,0 +1,102 @@
#include "RelocationUtils.h"
#include "globals.h"
#include "utils/ElfUtils.h"
#include "utils/memory.h"
#include <coreinit/cache.h>
#include <coreinit/dynload.h>
bool ResolveRelocations(std::vector<std::shared_ptr<ModuleData>> &loadedModules, bool skipMemoryMappingModule) {
bool wasSuccessful = true;
for (auto &curModule : loadedModules) {
DEBUG_FUNCTION_LINE("Let's do the relocations for %s", curModule->getExportName().c_str());
auto &relocData = curModule->getRelocationDataList();
// On first usage we can't redirect the alloc functions to our custom heap
// because threads can't run it on it. In order to patch the kernel
// to fully support our memory region, we have to run the MemoryMapping once with the default heap.
// Afterwards we can just rely on the custom heap.
bool skipAllocFunction = skipMemoryMappingModule && (std::string_view(curModule->getExportName()) == "homebrew_memorymapping");
DEBUG_FUNCTION_LINE_VERBOSE("Skip alloc replace? %d", skipAllocFunction);
if (!doRelocation(gLoadedModules, relocData, nullptr, 0, skipAllocFunction)) {
wasSuccessful = false;
DEBUG_FUNCTION_LINE_ERR("Failed to do Relocations for %s", curModule->getExportName().c_str());
OSFatal("Failed to do Reloations");
}
}
DCFlushRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE);
ICInvalidateRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE);
return wasSuccessful;
}
bool doRelocation(const std::vector<std::shared_ptr<ModuleData>> &moduleList,
const std::vector<std::unique_ptr<RelocationData>> &relocData,
relocation_trampoline_entry_t *tramp_data,
uint32_t tramp_length,
bool skipAllocReplacement) {
std::map<std::string, OSDynLoad_Module> moduleCache;
for (auto const &curReloc : relocData) {
auto &functionName = curReloc->getName();
std::string rplName = curReloc->getImportRPLInformation()->getRPLName();
uint32_t functionAddress = 0;
for (auto &module : moduleList) {
if (rplName == module->getExportName()) {
for (auto &exportData : module->getExportDataList()) {
if (functionName == exportData->getName()) {
functionAddress = (uint32_t) exportData->getAddress();
}
}
}
}
if (!skipAllocReplacement) {
if (functionName == "MEMAllocFromDefaultHeap") {
functionAddress = reinterpret_cast<uint32_t>(&MEMAlloc);
} else if (functionName == "MEMAllocFromDefaultHeapEx") {
functionAddress = reinterpret_cast<uint32_t>(&MEMAllocEx);
} else if (functionName == "MEMFreeToDefaultHeap") {
functionAddress = reinterpret_cast<uint32_t>(&MEMFree);
}
}
if (functionAddress == 0) {
int32_t isData = curReloc->getImportRPLInformation()->isData();
OSDynLoad_Module rplHandle = nullptr;
if (moduleCache.count(rplName) == 0) {
OSDynLoad_Error err = OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle);
if (err != OS_DYNLOAD_OK || rplHandle == nullptr) {
DEBUG_FUNCTION_LINE_VERBOSE("%s is not yet loaded", rplName.c_str());
// only acquire if not already loaded.
err = OSDynLoad_Acquire(rplName.c_str(), &rplHandle);
if (err != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to acquire %s", rplName.c_str());
return false;
}
}
moduleCache[rplName] = rplHandle;
}
rplHandle = moduleCache.at(rplName);
OSDynLoad_FindExport(rplHandle, isData, functionName.c_str(), (void **) &functionAddress);
if (functionAddress == 0) {
DEBUG_FUNCTION_LINE_ERR("Failed to find export %s of %s", functionName.begin(), rplName.c_str());
OSFatal("Failed to find export");
return false;
}
}
if (!ElfUtils::elfLinkOne(curReloc->getType(), curReloc->getOffset(), curReloc->getAddend(), (uint32_t) curReloc->getDestination(), functionAddress, tramp_data, tramp_length,
RELOC_TYPE_IMPORT)) {
DEBUG_FUNCTION_LINE_ERR("Relocation failed");
return false;
}
}
if (tramp_data != nullptr) {
DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
}
return true;
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "module/ModuleData.h"
#include <vector>
bool ResolveRelocations(std::vector<std::shared_ptr<ModuleData>> &loadedModules,
bool skipMemoryMappingModule);
bool doRelocation(const std::vector<std::shared_ptr<ModuleData>> &moduleList,
const std::vector<std::unique_ptr<RelocationData>> &relocData,
relocation_trampoline_entry_t *tramp_data,
uint32_t tramp_length,
bool skipAllocReplacement);

View File

@ -0,0 +1,51 @@
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#include <cstring>
#include <string>
#include <strings.h>
#include <utils/StringTools.h>
#include <wut_types.h>
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
if (!string || !compare)
return -1;
char TokCopy[512];
strncpy(TokCopy, compare, sizeof(TokCopy));
TokCopy[511] = '\0';
char *strTok = strtok(TokCopy, separator);
while (strTok != nullptr) {
if (strcasecmp(string, strTok) == 0) {
return 0;
}
strTok = strtok(nullptr, separator);
}
return -1;
}

View File

@ -23,42 +23,55 @@
*
* for WiiXplorer 2010
***************************************************************************/
#ifndef __STRING_TOOLS_H
#define __STRING_TOOLS_H
#pragma once
#include <memory>
#include <string>
#include <vector>
#include <wut_types.h>
template<typename... Args>
std::string string_format(const std::string &format, Args... args) {
int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
auto size = static_cast<size_t>(size_s);
auto buf = std::make_unique<char[]>(size);
std::snprintf(buf.get(), size, format.c_str(), args...);
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}
class StringTools {
public:
static BOOL EndsWith(const std::string &a, const std::string &b);
static const char *byte_to_binary(int32_t x);
static std::string removeCharFromString(std::string &input, char toBeRemoved);
static const char *fmt(const char *format, ...);
static const wchar_t *wfmt(const char *format, ...);
static int32_t strprintf(std::string &str, const char *format, ...);
static std::string strfmt(const char *format, ...);
static BOOL char2wchar_t(const char *src, wchar_t *dest);
static int32_t strtokcmp(const char *string, const char *compare, const char *separator);
static int32_t strextcmp(const char *string, const char *extension, char seperator);
static char *str_replace(char *orig, char *rep, char *with);
static const char *FullpathToFilename(const char *path) {
if (!path)
return path;
static const char *FullpathToFilename(const char *path);
const char *ptr = path;
const char *Filename = ptr;
static void RemoveDoubleSlashs(std::string &str);
while (*ptr != '\0') {
if (ptr[0] == '/' && ptr[1] != '\0')
Filename = ptr + 1;
static std::vector<std::string> stringSplit(const std::string &value, const std::string &splitter);
};
++ptr;
}
#endif /* __STRING_TOOLS_H */
return Filename;
}
static void RemoveDoubleSlashs(std::string &str) {
uint32_t length = str.size();
//! clear path of double slashes
for (uint32_t i = 1; i < length; ++i) {
if (str[i - 1] == '/' && str[i] == '/') {
str.erase(i, 1);
i--;
length--;
}
}
}
};

View File

@ -21,6 +21,11 @@
} while (0)
#define IMPORT_END()
#define EXPORT_VAR(type, var) type var __attribute__((section(".data")));
EXPORT_VAR(uint32_t *, MEMAllocFromDefaultHeap);
EXPORT_VAR(uint32_t *, MEMAllocFromDefaultHeapEx);
EXPORT_VAR(uint32_t *, MEMFreeToDefaultHeap);
void InitFunctionPointers(void) {
OSDynLoad_Module handle;
@ -28,5 +33,16 @@ void InitFunctionPointers(void) {
addr_OSDynLoad_FindExport = (void *) 0x0102B828; // 0200f428 - 0xFE3C00
addr_OSDynLoad_IsModuleLoaded = (void *) 0x0102A59C; // 0200e19c - 0xFE3C00
OSDynLoad_Acquire("coreinit.rpl", &handle);
uint32_t **value = 0;
OSDynLoad_FindExport(handle, 1, "MEMAllocFromDefaultHeap", (void **) &value);
MEMAllocFromDefaultHeap = *value;
OSDynLoad_FindExport(handle, 1, "MEMAllocFromDefaultHeapEx", (void **) &value);
MEMAllocFromDefaultHeapEx = *value;
OSDynLoad_FindExport(handle, 1, "MEMFreeToDefaultHeap", (void **) &value);
MEMFreeToDefaultHeap = *value;
#include "imports.h"
// override failed __rplwrap_exit find export
OSDynLoad_FindExport(handle, 0, "exit", (void **) &addr___rplwrap_exit);
}

View File

@ -1,7 +1,11 @@
#include "hooks.h"
#include "globals.h"
#include "module/ModuleData.h"
#include "utils/logger.h"
#include <memory>
#include <wums.h>
#ifdef DEBUG
static const char **hook_names = (const char *[]){
"WUMS_HOOK_INIT_WUT_MALLOC",
"WUMS_HOOK_FINI_WUT_MALLOC",
@ -22,36 +26,32 @@ static const char **hook_names = (const char *[]){
"WUMS_HOOK_APPLICATION_ENDS",
"WUMS_HOOK_RELOCATIONS_DONE",
"WUMS_HOOK_APPLICATION_REQUESTS_EXIT"};
#endif
void CallHook(const std::vector<std::shared_ptr<ModuleDataMinimal>> &modules, wums_hook_type_t type, bool condition) {
void CallHook(const std::vector<std::shared_ptr<ModuleData>> &modules, wums_hook_type_t type, bool condition) {
if (condition) {
CallHook(modules, type);
}
}
void CallHook(const std::vector<std::shared_ptr<ModuleDataMinimal>> &modules, wums_hook_type_t type) {
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d] for all modules\n", hook_names[type], type);
void CallHook(const std::vector<std::shared_ptr<ModuleData>> &modules, wums_hook_type_t type) {
DEBUG_FUNCTION_LINE("Calling hook of type %s [%d] for all modules", hook_names[type], type);
for (auto &curModule : modules) {
CallHook(curModule, type);
}
}
void CallHook(const std::shared_ptr<ModuleDataMinimal> &module, wums_hook_type_t type, bool condition) {
void CallHook(const std::shared_ptr<ModuleData> &module, wums_hook_type_t type, bool condition) {
if (condition) {
CallHook(module, type);
}
}
void CallHook(const std::shared_ptr<ModuleDataMinimal> &module, wums_hook_type_t type) {
if (!module->relocationsDone) {
DEBUG_FUNCTION_LINE("Hook not called because the relocations failed\n");
return;
}
void CallHook(const std::shared_ptr<ModuleData> &module, wums_hook_type_t type) {
for (auto &curHook : module->getHookDataList()) {
auto func_ptr = (uint32_t) curHook->getTarget();
if (func_ptr == 0) {
DEBUG_FUNCTION_LINE("Hook ptr was NULL\n");
DEBUG_FUNCTION_LINE_ERR("Module %s: hook ptr was NULL", module->getExportName().c_str());
break;
}
@ -70,19 +70,19 @@ void CallHook(const std::shared_ptr<ModuleDataMinimal> &module, wums_hook_type_t
type == WUMS_HOOK_FINI_WUT_SOCKETS ||
type == WUMS_HOOK_INIT_WRAPPER ||
type == WUMS_HOOK_FINI_WRAPPER)) {
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d] %d for %s: %08X\n", hook_names[type], type, curHook->getType(), module->getExportName().c_str(), curHook->getTarget());
DEBUG_FUNCTION_LINE("Calling hook of type %s [%d] %d for %s: %08X", hook_names[type], type, curHook->getType(), module->getExportName().c_str(), curHook->getTarget());
((void (*)())((uint32_t *) func_ptr))();
break;
} else if (type == WUMS_HOOK_INIT ||
type == WUMS_HOOK_RELOCATIONS_DONE) {
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d] %d for %s: %08X\n", hook_names[type], type, curHook->getType(), module->getExportName().c_str(), curHook->getTarget());
DEBUG_FUNCTION_LINE("Calling hook of type %s [%d] %d for %s: %08X", hook_names[type], type, curHook->getType(), module->getExportName().c_str(), curHook->getTarget());
wums_app_init_args_t args;
args.module_information = gModuleData;
args.module_information = &gModuleInformation;
((void (*)(wums_app_init_args_t *))((uint32_t *) func_ptr))(&args);
} else {
DEBUG_FUNCTION_LINE("#########################################\n");
DEBUG_FUNCTION_LINE("#########HOOK NOT IMPLEMENTED %d#########\n", type);
DEBUG_FUNCTION_LINE("#########################################\n");
DEBUG_FUNCTION_LINE_ERR("#########################################");
DEBUG_FUNCTION_LINE_ERR("#########HOOK NOT IMPLEMENTED %d#########", type);
DEBUG_FUNCTION_LINE_ERR("#########################################");
}
break;
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "module/ModuleData.h"
#include <memory>
#include <vector>
#include <wums.h>
void CallHook(const std::vector<std::shared_ptr<ModuleData>> &modules, wums_hook_type_t type, bool condition);
void CallHook(const std::vector<std::shared_ptr<ModuleData>> &modules, wums_hook_type_t type);
void CallHook(const std::shared_ptr<ModuleData> &module, wums_hook_type_t type, bool condition);
void CallHook(const std::shared_ptr<ModuleData> &module, wums_hook_type_t type);

View File

@ -18,6 +18,53 @@ IMPORT(MEMCreateExpHeapEx);
IMPORT(OSUninterruptibleSpinLock_Acquire);
IMPORT(OSUninterruptibleSpinLock_Release);
IMPORT(OSReport);
IMPORT(MEMGetTotalFreeSizeForExpHeap);
IMPORT(OSMemoryBarrier);
IMPORT(OSInitMutex);
IMPORT(OSLockMutex);
IMPORT(OSUnlockMutex);
IMPORT(OSCompareAndSwapAtomicEx);
IMPORT(OSCompareAndSwapAtomic);
IMPORT(OSGetThreadSpecific);
IMPORT(OSSetThreadSpecific);
IMPORT(OSInitCond);
IMPORT(OSWaitCond);
IMPORT(OSSignalCond);
IMPORT(MEMAllocFromDefaultHeapEx);
IMPORT(MEMFreeToDefaultHeap);
IMPORT(FSTimeToCalendarTime);
IMPORT(FSInit);
IMPORT(FSShutdown);
IMPORT(FSAddClient);
IMPORT(FSAddClientEx);
IMPORT(FSDelClient);
IMPORT(FSInitCmdBlock);
IMPORT(FSChangeDir);
IMPORT(FSGetFreeSpaceSize);
IMPORT(FSGetStat);
IMPORT(FSRemove);
IMPORT(FSOpenFile);
IMPORT(FSCloseFile);
IMPORT(FSOpenDir);
IMPORT(FSMakeDir);
IMPORT(FSReadDir);
IMPORT(FSRewindDir);
IMPORT(FSCloseDir);
IMPORT(FSGetStatFile);
IMPORT(FSReadFile);
IMPORT(FSWriteFile);
IMPORT(FSSetPosFile);
IMPORT(FSFlushFile);
IMPORT(FSTruncateFile);
IMPORT(FSRename);
IMPORT(FSGetMountSource);
IMPORT(FSMount);
IMPORT(FSUnmount);
IMPORT(FSChangeMode);
IMPORT(FSGetPosFile);
IMPORT(OSTicksToCalendarTime);
IMPORT(__rplwrap_exit);
IMPORT_END();

View File

@ -0,0 +1,38 @@
#ifdef DEBUG
#include <nsysnet/_socket.h>
#include <stdint.h>
#include <whb/log_cafe.h>
#include <whb/log_module.h>
#include <whb/log_udp.h>
uint32_t moduleLogInit = false;
uint32_t cafeLogInit = false;
uint32_t udpLogInit = false;
#endif // DEBUG
void initLogging() {
#ifdef DEBUG
if (!(moduleLogInit = WHBLogModuleInit())) {
socket_lib_init();
cafeLogInit = WHBLogCafeInit();
udpLogInit = WHBLogUdpInit();
}
#endif // DEBUG
}
void deinitLogging() {
#ifdef DEBUG
if (moduleLogInit) {
WHBLogModuleDeinit();
moduleLogInit = false;
}
if (cafeLogInit) {
WHBLogCafeDeinit();
cafeLogInit = false;
}
if (udpLogInit) {
WHBLogUdpDeinit();
udpLogInit = false;
}
#endif // DEBUG
}

View File

@ -0,0 +1,57 @@
#pragma once
#include <coreinit/debug.h>
#include <string.h>
#include <whb/log.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LOG_APP_TYPE "M"
#define LOG_APP_NAME "WUMSLoader"
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX(LOG_FUNC, "", "", FMT, ##ARGS)
#define LOG_EX(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \
do { \
LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
} while (0)
#ifdef DEBUG
#ifdef VERBOSE_DEBUG
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#else
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#endif
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
#else
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
#endif
void initLogging();
void deinitLogging();
#ifdef __cplusplus
}
#endif

View File

@ -15,13 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "logger.h"
#include <cerrno>
#include <coreinit/cache.h>
#include <coreinit/memdefaultheap.h>
#include <coreinit/memexpheap.h>
#include <coreinit/memorymap.h>
#include <errno.h>
#include <cstring>
#include <malloc.h>
#include <string.h>
extern MEMHeapHandle gHeapHandle;
@ -32,11 +32,10 @@ void *MEMAllocSafe(uint32_t size, uint32_t align) {
return res;
}
void *MemoryAlloc(uint32_t size) {
void *res = MEMAllocSafe(size, 4);
if (res == nullptr) {
OSFatal_printf("Failed to MemoryAlloc %d", size);
OSFatal("Failed to MemoryAlloc");
}
return res;
}
@ -44,7 +43,7 @@ void *MemoryAlloc(uint32_t size) {
void *MemoryAllocEx(uint32_t size, uint32_t align) {
void *res = MEMAllocSafe(size, align);
if (res == nullptr) {
OSFatal_printf("Failed to MemoryAllocEX %d %d", size, align);
OSFatal("Failed to MemoryAllocEX");
}
return res;
}
@ -53,7 +52,7 @@ void MemoryFree(void *ptr) {
if (ptr) {
MEMFreeToExpHeap(gHeapHandle, ptr);
} else {
OSFatal_printf("Failed to free");
OSFatal("Failed to free");
}
}