mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2026-08-11 20:25:49 -05:00
First iteration of the WUPS-Backend as a .rpx/module for the SetupPayload
- Function replacements are not implemented yet - Serveral features like the config menu are missing Still WIP
This commit is contained in:
159
source/utils/ElfUtils.cpp
Normal file
159
source/utils/ElfUtils.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <coreinit/cache.h>
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include "elfio/elfio.hpp"
|
||||
#include "ElfUtils.h"
|
||||
|
||||
// See https://github.com/decaf-emu/decaf-emu/blob/43366a34e7b55ab9d19b2444aeb0ccd46ac77dea/src/libdecaf/src/cafe/loader/cafe_loader_reloc.cpp#L144
|
||||
bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampolin_entry_t * trampolin_data, uint32_t trampolin_data_length, RelocationType reloc_type, uint8_t trampolinId) {
|
||||
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(trampolin_data == NULL) {
|
||||
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampolin isn't provided\n");
|
||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance);
|
||||
return false;
|
||||
} else {
|
||||
relocation_trampolin_entry_t * freeSlot = NULL;
|
||||
for(uint32_t i = 0; i < trampolin_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(trampolin_data[i].status == RELOC_TRAMP_FREE ||
|
||||
trampolin_data[i].status == RELOC_TRAMP_IMPORT_DONE) {
|
||||
freeSlot = &(trampolin_data[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(freeSlot != NULL) {
|
||||
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampolin data list is full\n");
|
||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance);
|
||||
return false;
|
||||
}
|
||||
if(target - (uint32_t)&(freeSlot->trampolin[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, distance);
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("freeSlot = %08X", freeSlot);
|
||||
|
||||
freeSlot->trampolin[0] = 0x3D600000 | ((((uint32_t) value) >> 16) & 0x0000FFFF); // lis r11, real_addr@h
|
||||
freeSlot->trampolin[1] = 0x616B0000 | (((uint32_t) value) & 0x0000ffff); // ori r11, r11, real_addr@l
|
||||
freeSlot->trampolin[2] = 0x7D6903A6; // mtctr r11
|
||||
freeSlot->trampolin[3] = 0x4E800420; // bctr
|
||||
DCFlushRange((void*)freeSlot->trampolin, sizeof(freeSlot->trampolin));
|
||||
ICInvalidateRange((unsigned char*)freeSlot->trampolin, sizeof(freeSlot->trampolin));
|
||||
|
||||
freeSlot->id = trampolinId;
|
||||
DCFlushRange((void*)&freeSlot->id, sizeof(freeSlot->id));
|
||||
ICInvalidateRange((unsigned char*)&freeSlot->id, sizeof(freeSlot->id));
|
||||
|
||||
if(reloc_type == RELOC_TYPE_FIXED) {
|
||||
freeSlot->status = RELOC_TRAMP_FIXED;
|
||||
} else {
|
||||
// Relocations for the imports may be overridden
|
||||
freeSlot->status = RELOC_TRAMP_IMPORT_IN_PROGRESS;
|
||||
}
|
||||
uint32_t symbolValue = (uint32_t)&(freeSlot->trampolin[0]);
|
||||
value = symbolValue + addend;
|
||||
distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
||||
DEBUG_FUNCTION_LINE("Created tramp\n");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
50
source/utils/ElfUtils.h
Normal file
50
source/utils/ElfUtils.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "common/relocation_defines.h"
|
||||
|
||||
#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_trampolin_entry_t * trampolin_data, uint32_t trampolin_data_length, RelocationType reloc_type, uint8_t trampolinId);
|
||||
};
|
||||
211
source/utils/StringTools.cpp
Normal file
211
source/utils/StringTools.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
/***************************************************************************
|
||||
* 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 <vector>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <strings.h>
|
||||
#include <wut_types.h>
|
||||
#include <stdio.h>
|
||||
#include <utils/StringTools.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;
|
||||
}
|
||||
80
source/utils/StringTools.h
Normal file
80
source/utils/StringTools.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/***************************************************************************
|
||||
* 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
|
||||
***************************************************************************/
|
||||
#ifndef __STRING_TOOLS_H
|
||||
#define __STRING_TOOLS_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <wut_types.h>
|
||||
|
||||
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 const char * 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;
|
||||
}
|
||||
|
||||
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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<std::string> stringSplit(const std::string & value, const std::string & splitter);
|
||||
};
|
||||
|
||||
#endif /* __STRING_TOOLS_H */
|
||||
|
||||
87
source/utils/function_patcher.h
Normal file
87
source/utils/function_patcher.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2016-2020 Maschell
|
||||
* With code from chadderz and dimok
|
||||
*
|
||||
* 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/>.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _FUNCTION_HOOKS_H_
|
||||
#define _FUNCTION_HOOKS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <coreinit/dynload.h>
|
||||
|
||||
/* Macros for libs */
|
||||
#define LIB_CORE_INIT 0
|
||||
#define LIB_NSYSNET 1
|
||||
#define LIB_GX2 2
|
||||
#define LIB_AOC 3
|
||||
#define LIB_AX 4
|
||||
#define LIB_FS 5
|
||||
#define LIB_OS 6
|
||||
#define LIB_PADSCORE 7
|
||||
#define LIB_SOCKET 8
|
||||
#define LIB_SYS 9
|
||||
#define LIB_VPAD 10
|
||||
#define LIB_NN_ACP 11
|
||||
#define LIB_SYSHID 12
|
||||
#define LIB_VPADBASE 13
|
||||
#define LIB_AX_OLD 14
|
||||
#define LIB_PROC_UI 15
|
||||
#define LIB_NTAG 16
|
||||
#define LIB_NFP 17
|
||||
#define LIB_SAVE 18
|
||||
#define LIB_ACT 19
|
||||
#define LIB_NIM 20
|
||||
|
||||
// functions types
|
||||
#define STATIC_FUNCTION 0
|
||||
#define DYNAMIC_FUNCTION 1
|
||||
|
||||
//Orignal code by Chadderz.
|
||||
#define DECL(res, name, ...) \
|
||||
res (* real_ ## name)(__VA_ARGS__) __attribute__((section(".data"))); \
|
||||
res my_ ## name(__VA_ARGS__)
|
||||
|
||||
#define FUNCTION_PATCHER_METHOD_STORE_SIZE 7
|
||||
|
||||
typedef struct {
|
||||
const uint32_t replaceAddr;
|
||||
const uint32_t replaceCall;
|
||||
const uint32_t library;
|
||||
const char functionName[50];
|
||||
uint32_t realAddr;
|
||||
uint32_t restoreInstruction;
|
||||
uint8_t functionType;
|
||||
uint8_t alreadyPatched;
|
||||
} hooks_magic_t;
|
||||
|
||||
void PatchInvidualMethodHooks(hooks_magic_t hook_information[],int32_t hook_information_size, volatile uint32_t dynamic_method_calls[]);
|
||||
void RestoreInvidualInstructions(hooks_magic_t hook_information[],int32_t hook_information_size);
|
||||
uint32_t GetAddressOfFunction(const char * functionName,uint32_t library);
|
||||
int32_t isDynamicFunction(uint32_t physicalAddress);
|
||||
void resetLibs();
|
||||
|
||||
//Orignal code by Chadderz.
|
||||
#define MAKE_MAGIC(x, lib,functionType) { (uint32_t) my_ ## x, (uint32_t) &real_ ## x, lib, # x,0,0,functionType,0}
|
||||
#define MAKE_MAGIC_NAME(x,y, lib,functionType) { (uint32_t) my_ ## x, (uint32_t) &real_ ## x, lib, # y,0,0,functionType,0}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FS_H */
|
||||
568
source/utils/function_patcher_.cpp
Normal file
568
source/utils/function_patcher_.cpp
Normal file
@@ -0,0 +1,568 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2016 Maschell
|
||||
* With code from chadderz and dimok
|
||||
*
|
||||
* 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 <vector>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <coreinit/memorymap.h>
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/dynload.h>
|
||||
|
||||
#include "kernel/kernel_utils.h"
|
||||
#include "function_patcher.h"
|
||||
#include "logger.h"
|
||||
|
||||
#define LIB_CODE_RW_BASE_OFFSET 0xC1000000
|
||||
#define CODE_RW_BASE_OFFSET 0x00000000
|
||||
#define DEBUG_LOG_DYN 0
|
||||
|
||||
OSDynLoad_Module acp_handle_internal = 0;
|
||||
OSDynLoad_Module aoc_handle_internal = 0;
|
||||
OSDynLoad_Module sound_handle_internal = 0;
|
||||
OSDynLoad_Module sound_handle_internal_old = 0;
|
||||
OSDynLoad_Module libcurl_handle_internal = 0;
|
||||
OSDynLoad_Module gx2_handle_internal = 0;
|
||||
OSDynLoad_Module nfp_handle_internal = 0;
|
||||
OSDynLoad_Module nn_act_handle_internal = 0;
|
||||
OSDynLoad_Module nn_nim_handle_internal = 0;
|
||||
OSDynLoad_Module nn_save_handle_internal = 0;
|
||||
OSDynLoad_Module ntag_handle_internal = 0;
|
||||
OSDynLoad_Module coreinit_handle_internal = 0;
|
||||
OSDynLoad_Module padscore_handle_internal = 0;
|
||||
OSDynLoad_Module proc_ui_handle_internal = 0;
|
||||
OSDynLoad_Module nsysnet_handle_internal = 0;
|
||||
OSDynLoad_Module sysapp_handle_internal = 0;
|
||||
OSDynLoad_Module syshid_handle_internal = 0;
|
||||
OSDynLoad_Module vpad_handle_internal = 0;
|
||||
OSDynLoad_Module vpadbase_handle_internal = 0;
|
||||
|
||||
/*
|
||||
* Patches a function that is loaded at the start of each application. Its not required to restore, at least when they are really dynamic.
|
||||
* "normal" functions should be patch with the normal patcher. Current Code by Maschell with the help of dimok. Orignal code by Chadderz.
|
||||
*/
|
||||
void PatchInvidualMethodHooks(hooks_magic_t method_hooks[],int32_t hook_information_size, volatile uint32_t dynamic_method_calls[]) {
|
||||
resetLibs();
|
||||
|
||||
DEBUG_FUNCTION_LINE("Patching %d given functions",hook_information_size);
|
||||
/* Patch branches to it. */
|
||||
volatile uint32_t *space = &dynamic_method_calls[0];
|
||||
|
||||
int32_t method_hooks_count = hook_information_size;
|
||||
|
||||
uint32_t skip_instr = 1;
|
||||
uint32_t my_instr_len = 6;
|
||||
uint32_t instr_len = my_instr_len + skip_instr;
|
||||
uint32_t flush_len = 4*instr_len;
|
||||
for(int32_t i = 0; i < method_hooks_count; i++) {
|
||||
log_printf("Patching %s ...",method_hooks[i].functionName);
|
||||
if(method_hooks[i].functionType == STATIC_FUNCTION && method_hooks[i].alreadyPatched == 1) {
|
||||
if(isDynamicFunction((uint32_t)OSEffectiveToPhysical(method_hooks[i].realAddr))) {
|
||||
log_printf("The function %s is a dynamic function. Please fix that <3", method_hooks[i].functionName);
|
||||
method_hooks[i].functionType = DYNAMIC_FUNCTION;
|
||||
} else {
|
||||
log_printf("Skipping %s, its already patched", method_hooks[i].functionName);
|
||||
space += instr_len;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t physical = 0;
|
||||
uint32_t repl_addr = (uint32_t)method_hooks[i].replaceAddr;
|
||||
uint32_t call_addr = (uint32_t)method_hooks[i].replaceCall;
|
||||
|
||||
uint32_t real_addr = GetAddressOfFunction(method_hooks[i].functionName,method_hooks[i].library);
|
||||
|
||||
if(!real_addr) {
|
||||
log_printf("");
|
||||
DEBUG_FUNCTION_LINE("OSDynLoad_FindExport failed for %s", method_hooks[i].functionName);
|
||||
space += instr_len;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("%s is located at %08X!", method_hooks[i].functionName,real_addr);
|
||||
}
|
||||
|
||||
physical = (uint32_t)OSEffectiveToPhysical(real_addr);
|
||||
if(!physical) {
|
||||
log_printf("Error. Something is wrong with the physical address");
|
||||
space += instr_len;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("%s physical is located at %08X!", method_hooks[i].functionName,physical);
|
||||
}
|
||||
|
||||
*(volatile uint32_t *)(call_addr) = (uint32_t)(space) - CODE_RW_BASE_OFFSET;
|
||||
|
||||
|
||||
uint32_t targetAddr = (uint32_t)space;
|
||||
if(targetAddr < 0x00800000 || targetAddr >= 0x01000000) {
|
||||
targetAddr = (uint32_t) OSEffectiveToPhysical(targetAddr);
|
||||
} else {
|
||||
targetAddr = targetAddr + 0x30800000 - 0x00800000;
|
||||
}
|
||||
|
||||
KernelCopyData(targetAddr, physical, 4);
|
||||
|
||||
ICInvalidateRange((void*)(space), 4);
|
||||
DCFlushRange((void*)(space), 4);
|
||||
space++;
|
||||
|
||||
//Only works if skip_instr == 1
|
||||
if(skip_instr == 1) {
|
||||
// fill the restore instruction section
|
||||
method_hooks[i].realAddr = real_addr;
|
||||
method_hooks[i].restoreInstruction = *(space-1);
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("method_hooks[i].realAddr = %08X!", method_hooks[i].realAddr);
|
||||
}
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("method_hooks[i].restoreInstruction = %08X!",method_hooks[i].restoreInstruction) ;
|
||||
}
|
||||
} else {
|
||||
log_printf("Error. Can't save %s for restoring!", method_hooks[i].functionName);
|
||||
}
|
||||
|
||||
//adding jump to real function thx @ dimok for the assembler code
|
||||
/*
|
||||
90 61 ff e0 stw r3,-32(r1)
|
||||
3c 60 12 34 lis r3,4660
|
||||
60 63 56 78 ori r3,r3,22136
|
||||
7c 69 03 a6 mtctr r3
|
||||
80 61 ff e0 lwz r3,-32(r1)
|
||||
4e 80 04 20 bctr*/
|
||||
*space = 0x9061FFE0;
|
||||
space++;
|
||||
*space = 0x3C600000 | (((real_addr + (skip_instr * 4)) >> 16) & 0x0000FFFF); // lis r3, real_addr@h
|
||||
space++;
|
||||
*space = 0x60630000 | ((real_addr + (skip_instr * 4)) & 0x0000ffff); // ori r3, r3, real_addr@l
|
||||
space++;
|
||||
*space = 0x7C6903A6; // mtctr r3
|
||||
space++;
|
||||
*space = 0x8061FFE0; // lwz r3,-32(r1)
|
||||
space++;
|
||||
*space = 0x4E800420; // bctr
|
||||
space++;
|
||||
DCFlushRange((void*)(space - instr_len), flush_len);
|
||||
ICInvalidateRange((unsigned char*)(space - instr_len), flush_len);
|
||||
|
||||
//setting jump back
|
||||
uint32_t replace_instr = 0x48000002 | (repl_addr & 0x03fffffc);
|
||||
DCFlushRange(&replace_instr, 4);
|
||||
|
||||
KernelCopyData(physical, (uint32_t)OSEffectiveToPhysical((uint32_t)&replace_instr), 4);
|
||||
ICInvalidateRange((void*)(real_addr), 4);
|
||||
|
||||
method_hooks[i].alreadyPatched = 1;
|
||||
log_printf("done!\n");
|
||||
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("Done with patching given functions!");
|
||||
}
|
||||
|
||||
/* ****************************************************************** */
|
||||
/* RESTORE ORIGINAL INSTRUCTIONS */
|
||||
/* ****************************************************************** */
|
||||
void RestoreInvidualInstructions(hooks_magic_t method_hooks[],int32_t hook_information_size) {
|
||||
resetLibs();
|
||||
DEBUG_FUNCTION_LINE("Restoring given functions!");
|
||||
int32_t method_hooks_count = hook_information_size;
|
||||
for(int32_t i = 0; i < method_hooks_count; i++) {
|
||||
DEBUG_FUNCTION_LINE("Restoring %s... ",method_hooks[i].functionName);
|
||||
if(method_hooks[i].restoreInstruction == 0 || method_hooks[i].realAddr == 0) {
|
||||
log_printf("I dont have the information for the restore =( skip");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t real_addr = GetAddressOfFunction(method_hooks[i].functionName,method_hooks[i].library);
|
||||
|
||||
if(!real_addr) {
|
||||
log_printf("OSDynLoad_FindExport failed for %s", method_hooks[i].functionName);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t physical = (uint32_t)OSEffectiveToPhysical(real_addr);
|
||||
if(!physical) {
|
||||
log_printf("Something is wrong with the physical address");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isDynamicFunction(physical)) {
|
||||
log_printf("Its a dynamic function. We don't need to restore it!",method_hooks[i].functionName);
|
||||
} else {
|
||||
physical = (uint32_t)OSEffectiveToPhysical(method_hooks[i].realAddr); //When its an static function, we need to use the old location
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("Restoring %08X to %08X",(uint32_t)method_hooks[i].restoreInstruction,physical);
|
||||
}
|
||||
uint32_t targetAddr = (uint32_t)&method_hooks[i].restoreInstruction;
|
||||
if(targetAddr < 0x00800000 || targetAddr >= 0x01000000) {
|
||||
targetAddr = (uint32_t) OSEffectiveToPhysical(targetAddr);
|
||||
} else {
|
||||
targetAddr = targetAddr + 0x30800000 - 0x00800000;
|
||||
}
|
||||
|
||||
KernelCopyData(physical,targetAddr, 4);
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("ICInvalidateRange %08X",(void*)method_hooks[i].realAddr);
|
||||
}
|
||||
ICInvalidateRange((void*)method_hooks[i].realAddr, 4);
|
||||
log_printf("done");
|
||||
}
|
||||
method_hooks[i].alreadyPatched = 0; // In case a
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Done with restoring given functions!");
|
||||
}
|
||||
|
||||
int32_t isDynamicFunction(uint32_t physicalAddress) {
|
||||
if((physicalAddress & 0x80000000) == 0x80000000) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t GetAddressOfFunction(const char * functionName,uint32_t library) {
|
||||
uint32_t real_addr = 0;
|
||||
|
||||
/*
|
||||
if(strcmp(functionName, "OSDynLoad_Acquire") == 0) {
|
||||
memcpy(&real_addr, &OSDynLoad_Acquire, 4);
|
||||
return real_addr;
|
||||
} else if(strcmp(functionName, "LiWaitOneChunk") == 0) {
|
||||
real_addr = (uint32_t)addr_LiWaitOneChunk;
|
||||
return real_addr;
|
||||
} else if(strcmp(functionName, "LiBounceOneChunk") == 0) {
|
||||
//! not required on firmwares above 3.1.0
|
||||
if(OS_FIRMWARE >= 400)
|
||||
return 0;
|
||||
|
||||
uint32_t addr_LiBounceOneChunk = 0x010003A0;
|
||||
real_addr = (uint32_t)addr_LiBounceOneChunk;
|
||||
return real_addr;
|
||||
}
|
||||
*/
|
||||
|
||||
OSDynLoad_Module rpl_handle = 0;
|
||||
if(library == LIB_CORE_INIT) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_CORE_INIT", functionName);
|
||||
}
|
||||
if(coreinit_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("coreinit.rpl", &coreinit_handle_internal);
|
||||
}
|
||||
if(coreinit_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_CORE_INIT failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = coreinit_handle_internal;
|
||||
} else if(library == LIB_NSYSNET) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_NSYSNET", functionName);
|
||||
}
|
||||
if(nsysnet_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("nsysnet.rpl", &nsysnet_handle_internal);
|
||||
}
|
||||
if(nsysnet_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_NSYSNET failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = nsysnet_handle_internal;
|
||||
} else if(library == LIB_GX2) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_GX2", functionName);
|
||||
}
|
||||
if(gx2_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("gx2.rpl", &gx2_handle_internal);
|
||||
}
|
||||
if(gx2_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_GX2 failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = gx2_handle_internal;
|
||||
} else if(library == LIB_AOC) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_AOC", functionName);
|
||||
}
|
||||
if(aoc_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("nn_aoc.rpl", &aoc_handle_internal);
|
||||
}
|
||||
if(aoc_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_AOC failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = aoc_handle_internal;
|
||||
} else if(library == LIB_AX) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_AX", functionName);
|
||||
}
|
||||
if(sound_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("sndcore2.rpl", &sound_handle_internal);
|
||||
}
|
||||
if(sound_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_AX failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = sound_handle_internal;
|
||||
} else if(library == LIB_AX_OLD) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_AX_OLD", functionName);
|
||||
}
|
||||
if(sound_handle_internal_old == 0) {
|
||||
OSDynLoad_Acquire("snd_core.rpl", &sound_handle_internal_old);
|
||||
}
|
||||
if(sound_handle_internal_old == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_AX_OLD failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = sound_handle_internal_old;
|
||||
} else if(library == LIB_FS) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_FS", functionName);
|
||||
}
|
||||
if(coreinit_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("coreinit.rpl", &coreinit_handle_internal);
|
||||
}
|
||||
if(coreinit_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_FS failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = coreinit_handle_internal;
|
||||
} else if(library == LIB_OS) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_OS", functionName);
|
||||
}
|
||||
if(coreinit_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("coreinit.rpl", &coreinit_handle_internal);
|
||||
}
|
||||
if(coreinit_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_OS failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = coreinit_handle_internal;
|
||||
} else if(library == LIB_PADSCORE) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_PADSCORE", functionName);
|
||||
}
|
||||
if(padscore_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("padscore.rpl", &padscore_handle_internal);
|
||||
}
|
||||
if(padscore_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_PADSCORE failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = padscore_handle_internal;
|
||||
} else if(library == LIB_SOCKET) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_SOCKET", functionName);
|
||||
}
|
||||
if(nsysnet_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("nsysnet.rpl", &nsysnet_handle_internal);
|
||||
}
|
||||
if(nsysnet_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_SOCKET failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = nsysnet_handle_internal;
|
||||
} else if(library == LIB_SYS) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_SYS", functionName);
|
||||
}
|
||||
if(sysapp_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("sysapp.rpl", &sysapp_handle_internal);
|
||||
}
|
||||
if(sysapp_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_SYS failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = sysapp_handle_internal;
|
||||
} else if(library == LIB_VPAD) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_VPAD", functionName);
|
||||
}
|
||||
if(vpad_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("vpad.rpl", &vpad_handle_internal);
|
||||
}
|
||||
if(vpad_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_VPAD failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = vpad_handle_internal;
|
||||
} else if(library == LIB_NN_ACP) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_NN_ACP", functionName);
|
||||
}
|
||||
if(acp_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("nn_acp.rpl", &acp_handle_internal);
|
||||
}
|
||||
if(acp_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_NN_ACP failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = acp_handle_internal;
|
||||
} else if(library == LIB_SYSHID) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_SYSHID", functionName);
|
||||
}
|
||||
if(syshid_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("nsyshid.rpl", &syshid_handle_internal);
|
||||
}
|
||||
if(syshid_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_SYSHID failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = syshid_handle_internal;
|
||||
} else if(library == LIB_VPADBASE) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_VPADBASE", functionName);
|
||||
}
|
||||
if(vpadbase_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("vpadbase.rpl", &vpadbase_handle_internal);
|
||||
}
|
||||
if(vpadbase_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_VPADBASE failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = vpadbase_handle_internal;
|
||||
} else if(library == LIB_PROC_UI) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
DEBUG_FUNCTION_LINE("FindExport of %s! From LIB_PROC_UI", functionName);
|
||||
}
|
||||
if(proc_ui_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("proc_ui.rpl", &proc_ui_handle_internal);
|
||||
}
|
||||
if(proc_ui_handle_internal == 0) {
|
||||
DEBUG_FUNCTION_LINE("LIB_PROC_UI failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = proc_ui_handle_internal;
|
||||
} else if(library == LIB_NTAG) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
log_printf("FindExport of %s! From LIB_NTAG", functionName);
|
||||
}
|
||||
if(ntag_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("ntag.rpl", &ntag_handle_internal);
|
||||
}
|
||||
if(ntag_handle_internal == 0) {
|
||||
log_print("LIB_NTAG failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = ntag_handle_internal;
|
||||
} else if(library == LIB_NFP) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
log_printf("FindExport of %s! From LIB_NFP", functionName);
|
||||
}
|
||||
if(nfp_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("nn_nfp.rpl", &nfp_handle_internal);
|
||||
}
|
||||
if(nfp_handle_internal == 0) {
|
||||
log_print("LIB_NFP failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = nfp_handle_internal;
|
||||
} else if(library == LIB_SAVE) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
log_printf("FindExport of %s! From LIB_SAVE", functionName);
|
||||
}
|
||||
if(nn_save_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("nn_save.rpl", &nn_save_handle_internal);
|
||||
}
|
||||
if(nn_save_handle_internal == 0) {
|
||||
log_print("LIB_SAVE failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = nn_save_handle_internal;
|
||||
} else if(library == LIB_ACT) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
log_printf("FindExport of %s! From LIB_ACT", functionName);
|
||||
}
|
||||
if(nn_act_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("nn_act.rpl", &nn_act_handle_internal);
|
||||
}
|
||||
if(nn_act_handle_internal == 0) {
|
||||
log_print("LIB_ACT failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = nn_act_handle_internal;
|
||||
} else if(library == LIB_NIM) {
|
||||
if(DEBUG_LOG_DYN) {
|
||||
log_printf("FindExport of %s! From LIB_NIM", functionName);
|
||||
}
|
||||
if(nn_nim_handle_internal == 0) {
|
||||
OSDynLoad_Acquire("nn_nim.rpl", &nn_nim_handle_internal);
|
||||
}
|
||||
if(nn_nim_handle_internal == 0) {
|
||||
log_print("LIB_NIM failed to acquire");
|
||||
return 0;
|
||||
}
|
||||
rpl_handle = nn_nim_handle_internal;
|
||||
}
|
||||
|
||||
if(!rpl_handle) {
|
||||
DEBUG_FUNCTION_LINE("Failed to find the RPL handle for %s", functionName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
OSDynLoad_FindExport(rpl_handle, 0, functionName, (void**) &real_addr);
|
||||
|
||||
if(!real_addr) {
|
||||
OSDynLoad_FindExport(rpl_handle, 1, functionName, (void**) &real_addr);
|
||||
if(!real_addr) {
|
||||
DEBUG_FUNCTION_LINE("OSDynLoad_FindExport failed for %s", functionName);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if((library == LIB_NN_ACP) && (uint32_t)(*(volatile uint32_t*)(real_addr) & 0x48000002) == 0x48000000) {
|
||||
uint32_t address_diff = (uint32_t)(*(volatile uint32_t*)(real_addr) & 0x03FFFFFC);
|
||||
if((address_diff & 0x03000000) == 0x03000000) {
|
||||
address_diff |= 0xFC000000;
|
||||
}
|
||||
real_addr += (int32_t)address_diff;
|
||||
if((uint32_t)(*(volatile uint32_t*)(real_addr) & 0x48000002) == 0x48000000) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return real_addr;
|
||||
}
|
||||
|
||||
void resetLibs() {
|
||||
acp_handle_internal = 0;
|
||||
aoc_handle_internal = 0;
|
||||
sound_handle_internal = 0;
|
||||
sound_handle_internal_old = 0;
|
||||
libcurl_handle_internal = 0;
|
||||
gx2_handle_internal = 0;
|
||||
nfp_handle_internal = 0;
|
||||
nn_act_handle_internal = 0;
|
||||
nn_nim_handle_internal = 0;
|
||||
nn_save_handle_internal = 0;
|
||||
ntag_handle_internal = 0;
|
||||
coreinit_handle_internal = 0;
|
||||
padscore_handle_internal = 0;
|
||||
proc_ui_handle_internal = 0;
|
||||
nsysnet_handle_internal = 0;
|
||||
sysapp_handle_internal = 0;
|
||||
syshid_handle_internal = 0;
|
||||
vpad_handle_internal = 0;
|
||||
vpadbase_handle_internal = 0;
|
||||
}
|
||||
82
source/utils/logger.c
Normal file
82
source/utils/logger.c
Normal file
@@ -0,0 +1,82 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <utils/logger.h>
|
||||
#include <nsysnet/socket.h>
|
||||
#include <coreinit/debug.h>
|
||||
|
||||
#include <coreinit/systeminfo.h>
|
||||
#include <coreinit/thread.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;
|
||||
|
||||
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_print_(const char *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);
|
||||
}
|
||||
|
||||
38
source/utils/logger.h
Normal file
38
source/utils/logger.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#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 log_init() log_init_()
|
||||
//#define log_deinit() log_deinit_()
|
||||
#define log_print(str) log_print_(str)
|
||||
#define log_printf(FMT, ARGS...) log_printf_(FMT, ## ARGS);
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \
|
||||
log_printf("[%23s]%30s@L%04d: " FMT "\n",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \
|
||||
} while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
41
source/utils/utils.c
Normal file
41
source/utils/utils.c
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include "utils/logger.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("0x%08X (0x0000): ", data);
|
||||
for (i = 0; i < size; ++i) {
|
||||
log_printf("%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) {
|
||||
log_printf(" ");
|
||||
if ((i+1) % 16 == 0) {
|
||||
log_printf("| %s \n", ascii);
|
||||
if(i + 1 < size) {
|
||||
DEBUG_FUNCTION_LINE("0x%08X (0x%04X); ", data + i + 1,i+1);
|
||||
}
|
||||
} else if (i+1 == size) {
|
||||
ascii[(i+1) % 16] = '\0';
|
||||
if ((i+1) % 16 <= 8) {
|
||||
log_printf(" ");
|
||||
}
|
||||
for (j = (i+1) % 16; j < 16; ++j) {
|
||||
log_printf(" ");
|
||||
}
|
||||
log_printf("| %s \n", ascii);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
source/utils/utils.h
Normal file
40
source/utils/utils.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#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_
|
||||
Reference in New Issue
Block a user