Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source
build-binary:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: create version.h
run: |
git_hash=$(git rev-parse --short "$GITHUB_SHA")
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source
check-build-with-logging:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: build binary with logging
run: |
docker build . -t builder
Expand All @@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: create version.h
run: |
git_hash=$(git rev-parse --short "${{ github.event.pull_request.head.sha }}")
Expand Down
10 changes: 5 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM ghcr.io/wiiu-env/devkitppc:20240505
FROM ghcr.io/wiiu-env/devkitppc:20260225

COPY --from=ghcr.io/wiiu-env/libkernel:20230621 /artifacts $DEVKITPRO
COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO
COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20240424 /artifacts $DEVKITPRO
COPY --from=ghcr.io/wiiu-env/libkernel:20260331 /artifacts $DEVKITPRO
COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20260331 /artifacts $DEVKITPRO
COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20260418 /artifacts $DEVKITPRO

WORKDIR project
WORKDIR /project
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ INCLUDES := source
#-------------------------------------------------------------------------------
# options for code generation
#-------------------------------------------------------------------------------
CFLAGS := -Wall -Os -ffunction-sections\
CFLAGS := -Wall -Wextra -Werror -Os -ffunction-sections\
$(MACHDEP)

CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
Expand Down
2 changes: 1 addition & 1 deletion source/FunctionAddressProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ uint32_t FunctionAddressProvider::getEffectiveAddressOfFunction(function_replace
err = OSDynLoad_IsModuleLoaded((char *) rplHandle.rplname, &rplHandle.handle);
}
if (err != OS_DYNLOAD_OK || !rplHandle.handle) {
DEBUG_FUNCTION_LINE_VERBOSE("%s is not loaded yet", rplHandle.rplname, err, rplHandle.handle);
DEBUG_FUNCTION_LINE_VERBOSE("%s is not loaded yet. Err %d for handle %p", rplHandle.rplname, err, rplHandle.handle);
return 0;
}
rpl_handle = rplHandle.handle;
Expand Down
1 change: 1 addition & 0 deletions source/PatchedFunctionData.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "FunctionAddressProvider.h"
#include "PatchedFunctionData.h"
#include "fpatching_defines_legacy.h"
#include "utils/logger.h"
#include <coreinit/cache.h>
#include <coreinit/debug.h>
Expand Down
9 changes: 6 additions & 3 deletions source/export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
#include "PatchedFunctionData.h"
#include "function_patcher.h"
#include "utils/globals.h"

#include <mutex>
#include <ranges>
#include <vector>

#include <wums/exports.h>

WUT_CHECK_OFFSET(function_replacement_data_v2_t, 0x00, VERSION);
Expand Down Expand Up @@ -50,7 +53,7 @@ FunctionPatcherStatus FPAddFunctionPatch(function_replacement_data_t *function_d
}

{
std::lock_guard<std::mutex> lock(gPatchedFunctionsMutex);
std::lock_guard lock(gPatchedFunctionsMutex);
gPatchedFunctions.push_back(std::move(functionData));

OSMemoryBarrier();
Expand All @@ -64,7 +67,7 @@ bool FunctionPatcherPatchFunction(function_replacement_data_t *function_data, Pa
}

FunctionPatcherStatus FPRemoveFunctionPatch(PatchedFunctionHandle handle) {
std::lock_guard<std::mutex> lock(gPatchedFunctionsMutex);
std::lock_guard lock(gPatchedFunctionsMutex);
std::vector<std::shared_ptr<PatchedFunctionData>> toBeTempRestored;
bool found = false;
int32_t erasePosition = 0;
Expand Down Expand Up @@ -132,7 +135,7 @@ FunctionPatcherStatus FPIsFunctionPatched(PatchedFunctionHandle handle, bool *ou
if (outIsFunctionPatched == nullptr) {
return FUNCTION_PATCHER_RESULT_INVALID_ARGUMENT;
}
std::lock_guard<std::mutex> lock(gPatchedFunctionsMutex);
std::lock_guard lock(gPatchedFunctionsMutex);
for (auto &cur : gPatchedFunctions) {
if (cur->getHandle() == handle) {
*outIsFunctionPatched = cur->isPatched;
Expand Down
17 changes: 17 additions & 0 deletions source/fpatching_defines_legacy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

/* Types that are kept only for ABI compatibility. */

#include <function_patcher/fpatching_defines.h>
#include <stdint.h>

typedef struct function_replacement_data_v2_t {
uint32_t VERSION;
uint32_t physicalAddr; /* [needs to be filled] */
uint32_t virtualAddr; /* [needs to be filled] */
uint32_t replaceAddr; /* [needs to be filled] Address of our replacement function */
uint32_t *replaceCall; /* [needs to be filled] Address to access the real_function */
function_replacement_library_type_t library; /* [needs to be filled] rpl where the function we want to replace is. */
const char *function_name; /* [needs to be filled] name of the function we want to replace */
FunctionPatcherTargetProcess targetProcess; /* [will be filled] */
} function_replacement_data_v2_t;
18 changes: 18 additions & 0 deletions source/function_patcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@
#include "utils/CThread.h"
#include "utils/logger.h"
#include "utils/utils.h"

#include <coreinit/cache.h>
#include <coreinit/debug.h>
#include <coreinit/memorymap.h>

#include <kernel/kernel.h>

#include <memory>
#include <mutex>

static void writeDataAndFlushIC(CThread *thread, void *arg) {
(void) thread;
auto *data = (PatchedFunctionData *) arg;

uint32_t replace_instruction = data->replaceWithInstruction;
Expand All @@ -21,6 +26,19 @@ static void writeDataAndFlushIC(CThread *thread, void *arg) {

auto replace_instruction_physical = (uint32_t) &replace_instruction;

if (data->jumpData) {
DCFlushRange(data->jumpData, data->jumpDataSize * sizeof(uint32_t));
ICInvalidateRange(data->jumpData, data->jumpDataSize * sizeof(uint32_t));
}
if (data->jumpToOriginal) {
DCFlushRange(data->jumpToOriginal, 5 * sizeof(uint32_t));
ICInvalidateRange(data->jumpToOriginal, 5 * sizeof(uint32_t));
}
if (data->realCallFunctionAddressPtr) {
DCFlushRange(data->realCallFunctionAddressPtr, sizeof(uint32_t));
ICInvalidateRange(data->realCallFunctionAddressPtr, sizeof(uint32_t));
}

if (replace_instruction_physical < 0x00800000 || replace_instruction_physical >= 0x01000000) {
replace_instruction_physical = OSEffectiveToPhysical(replace_instruction_physical);
} else {
Expand Down
12 changes: 8 additions & 4 deletions source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
#include "utils/globals.h"
#include "utils/logger.h"
#include "utils/utils.h"

#include <coreinit/memdefaultheap.h>
#include <coreinit/memexpheap.h>
#include <kernel/kernel.h>
#include <mutex>
#include <ranges>
#include <set>
#include <wums.h>
Expand Down Expand Up @@ -41,7 +43,7 @@ void UpdateFunctionPointer() {
}

void CheckIfPatchedFunctionsAreStillInMemory() {
std::lock_guard<std::mutex> lock(gPatchedFunctionsMutex);
std::lock_guard lock(gPatchedFunctionsMutex);
// Check if rpl has been unloaded by comparing the instruction.
std::set<uint32_t> physicalAddressesUnchanged;
std::set<uint32_t> physicalAddressesChanged;
Expand Down Expand Up @@ -128,13 +130,15 @@ void notify_callback(OSDynLoad_Module module,
void *userContext,
OSDynLoad_NotifyReason reason,
OSDynLoad_NotifyData *infos) {
(void) userContext;
(void) infos;
if (reason == OS_DYNLOAD_NOTIFY_LOADED) {
std::lock_guard<std::mutex> lock(gPatchedFunctionsMutex);
std::lock_guard lock(gPatchedFunctionsMutex);
for (auto &cur : gPatchedFunctions) {
PatchFunction(cur);
}
} else if (reason == OS_DYNLOAD_NOTIFY_UNLOADED) {
std::lock_guard<std::mutex> lock(gPatchedFunctionsMutex);
std::lock_guard lock(gPatchedFunctionsMutex);
auto library = gFunctionAddressProvider->getTypeForHandle(module);
if (library != LIBRARY_OTHER) {
for (auto &cur : gPatchedFunctions) {
Expand Down Expand Up @@ -162,7 +166,7 @@ WUMS_APPLICATION_STARTS() {

initLogging();
{
std::lock_guard<std::mutex> lock(gPatchedFunctionsMutex);
std::lock_guard lock(gPatchedFunctionsMutex);
// reset function patch status if the rpl they were patching has been unloaded from memory.
CheckIfPatchedFunctionsAreStillInMemory();
DEBUG_FUNCTION_LINE_VERBOSE("Patch all functions");
Expand Down
1 change: 1 addition & 0 deletions source/utils/CThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ class CThread {

private:
static int32_t threadCallback(int32_t argc, void *arg) {
(void) argc;
//! After call to start() continue with the internal function
((CThread *) arg)->executeThread();
return 0;
Expand Down
2 changes: 1 addition & 1 deletion source/utils/globals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ char gJumpHeapData[JUMP_HEAP_DATA_SIZE] __attribute__((section(".data")));
MEMHeapHandle gJumpHeapHandle __attribute__((section(".data")));

std::shared_ptr<FunctionAddressProvider> gFunctionAddressProvider;
std::mutex gPatchedFunctionsMutex;
std::recursive_mutex gPatchedFunctionsMutex;
std::vector<std::shared_ptr<PatchedFunctionData>> gPatchedFunctions;

void *(*gMEMAllocFromDefaultHeapExForThreads)(uint32_t size, int align);
Expand Down
5 changes: 3 additions & 2 deletions source/utils/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
#include "version.h"
#include <coreinit/memheap.h>
#include <memory>
#include <mutex>
#include <vector>

#define MODULE_VERSION "v0.2.3"
#define MODULE_VERSION "v0.2.4"
#define MODULE_VERSION_FULL MODULE_VERSION MODULE_VERSION_EXTRA

#define JUMP_HEAP_DATA_SIZE (32 * 1024)
extern char gJumpHeapData[];
extern MEMHeapHandle gJumpHeapHandle;

extern std::shared_ptr<FunctionAddressProvider> gFunctionAddressProvider;
extern std::mutex gPatchedFunctionsMutex;
extern std::recursive_mutex gPatchedFunctionsMutex;
extern std::vector<std::shared_ptr<PatchedFunctionData>> gPatchedFunctions;

extern void *(*gMEMAllocFromDefaultHeapExForThreads)(uint32_t size, int align);
Expand Down
37 changes: 22 additions & 15 deletions source/utils/logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,24 @@
extern "C" {
#endif

#define LOG_APP_TYPE "M"
#define LOG_APP_NAME "function_patcher"
#define LOG_APP_TYPE "M"
#define LOG_APP_NAME "function_patcher"

#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
#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_DEFAULT(LOG_FUNC, "", "", FMT, ##ARGS)
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX_DEFAULT(LOG_FUNC, "", "", "", FMT, ##ARGS)

#define LOG_EX_DEFAULT(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) LOG_EX(__FILENAME__, __FUNCTION__, __LINE__, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ##ARGS)
#define CONSOLE_COLOR_RED "\033[31m"
#define CONSOLE_COLOR_YELLOW "\033[33m"
#define CONSOLE_COLOR_CYAN "\033[36m"
#define CONSOLE_COLOR_RESET "\033[0m"

#define LOG_EX(FILENAME, FUNCTION, LINE, 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); \
#define LOG_EX_DEFAULT(LOG_FUNC, LOG_COLOR, LOG_LEVEL, LINE_END, FMT, ARGS...) LOG_EX(__FILENAME__, __FUNCTION__, __LINE__, LOG_FUNC, LOG_COLOR, LOG_LEVEL, LINE_END, FMT, ##ARGS)

#define LOG_EX(FILENAME, FUNCTION, LINE, LOG_FUNC, LOG_COLOR, LOG_LEVEL, LINE_END, FMT, ARGS...) \
do { \
LOG_FUNC(LOG_COLOR "[(%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
Expand All @@ -37,10 +42,11 @@ extern "C" {

#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)

#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "## WARN## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, CONSOLE_COLOR_RED, "## ERROR## ", CONSOLE_COLOR_RESET, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, CONSOLE_COLOR_YELLOW, "##WARN ## ", CONSOLE_COLOR_RESET, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, CONSOLE_COLOR_CYAN, "##INFO ## ", CONSOLE_COLOR_RESET, FMT, ##ARGS)

#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS);
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, CONSOLE_COLOR_RED, "##ERROR## ", CONSOLE_COLOR_RESET, FMT, ##ARGS);

#else

Expand All @@ -52,10 +58,11 @@ extern "C" {

#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)

#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "## WARN## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, CONSOLE_COLOR_RED, "##ERROR## ", CONSOLE_COLOR_RESET "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, CONSOLE_COLOR_YELLOW, "##WARN ## ", CONSOLE_COLOR_RESET "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, CONSOLE_COLOR_CYAN, "##INFO ## ", CONSOLE_COLOR_RESET "\n", FMT, ##ARGS)

#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS);
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, CONSOLE_COLOR_RED, "##ERROR## ", CONSOLE_COLOR_RESET "\n", FMT, ##ARGS);

#endif

Expand Down