diff --git a/src/common/cafe.h b/src/common/cafe.h new file mode 100644 index 0000000..b6b6d1c --- /dev/null +++ b/src/common/cafe.h @@ -0,0 +1,106 @@ +#ifndef TCPGECKO_STACK_H +#define TCPGECKO_STACK_H + +#include "kernel_types.h" + +typedef struct OSThread; + +typedef struct OSThreadLink { + OSThread *next; + OSThread *prev; +} OSThreadLink; + +typedef struct OSThreadQueue { + OSThread *head; + OSThread *tail; + void *parentStruct; + u32 reserved; +} OSThreadQueue; + +typedef struct OSMessage { + u32 message; + u32 data0; + u32 data1; + u32 data2; +} OSMessage; + +typedef struct OSMessageQueue { + u32 tag; + char *name; + u32 reserved; + + OSThreadQueue sendQueue; + OSThreadQueue recvQueue; + OSMessage *messages; + int msgCount; + int firstIndex; + int usedCount; +} OSMessageQueue; + +typedef struct OSContext { + char tag[8]; + + u32 gpr[32]; + + u32 cr; + u32 lr; + u32 ctr; + u32 xer; + + u32 srr0; + u32 srr1; + + u32 ex0; + u32 ex1; + + u32 exception_type; + u32 reserved; + + double fpscr; + double fpr[32]; + + u16 spinLockCount; + u16 state; + + u32 gqr[8]; + u32 pir; + double psf[32]; + + u64 coretime[3]; + u64 starttime; + + u32 error; + u32 attributes; + + u32 pmc1; + u32 pmc2; + u32 pmc3; + u32 pmc4; + u32 mmcr0; + u32 mmcr1; +} OSContext; + +typedef int (*ThreadFunc)(int argc, void *argv); + +typedef struct OSThread { + OSContext context; + + u32 txtTag; + u8 state; + u8 attr; + + short threadId; + int suspend; + int priority; + + char _[0x394 - 0x330]; + + void *stackBase; + void *stackEnd; + + ThreadFunc entryPoint; + + char _3A0[0x6A0 - 0x3A0]; +} OSThread; + +#endif \ No newline at end of file diff --git a/src/common/fs_defs.h b/src/common/fs_defs.h index 0b71bb3..c5aa881 100644 --- a/src/common/fs_defs.h +++ b/src/common/fs_defs.h @@ -2,12 +2,12 @@ #define FS_DEFS_H #include "types.h" +#include "kernel_types.h" #ifdef __cplusplus extern "C" { #endif - /* FS defines and types */ #define FS_MAX_LOCALPATH_SIZE 511 #define FS_MAX_MOUNTPATH_SIZE 128 @@ -31,7 +31,6 @@ extern "C" { #define FS_SOURCETYPE_EXTERNAL 0 #define FS_SOURCETYPE_HFIO 1 -#define FS_SOURCETYPE_HFIO 1 /* FS data buffer alignment */ #define FS_IO_BUFFER_ALIGN 64 diff --git a/src/common/kernel_types.h b/src/common/kernel_types.h new file mode 100644 index 0000000..3b04fb0 --- /dev/null +++ b/src/common/kernel_types.h @@ -0,0 +1,10 @@ +#pragma once + +typedef unsigned char u8; +// typedef unsigned int uint8_t; +typedef unsigned short u16; +// typedef unsigned int uint16_t; +typedef unsigned int u32; +typedef unsigned int uint32_t; +// typedef unsigned long uint64_t; +typedef unsigned long long u64; \ No newline at end of file diff --git a/src/common/os_defs.h b/src/common/os_defs.h index d171c3d..48a4c8f 100644 --- a/src/common/os_defs.h +++ b/src/common/os_defs.h @@ -5,106 +5,6 @@ extern "C" { #endif -/*struct OSThread; - -struct OSThreadLink { - OSThread *next; - OSThread *prev; -}; - -struct OSThreadQueue { - OSThread *head; - OSThread *tail; - void *parentStruct; - u32 reserved; -}; - -struct OSMessage { - u32 message; - u32 data0; - u32 data1; - u32 data2; -}; - -struct OSMessageQueue { - u32 tag; - char *name; - u32 reserved; - - OSThreadQueue sendQueue; - OSThreadQueue recvQueue; - OSMessage *messages; - int msgCount; - int firstIndex; - int usedCount; -}; - -struct OSContext { - char tag[8]; - - u32 gpr[32]; - - u32 cr; - u32 lr; - u32 ctr; - u32 xer; - - u32 srr0; - u32 srr1; - - u32 ex0; - u32 ex1; - - u32 exception_type; - u32 reserved; - - double fpscr; - double fpr[32]; - - u16 spinLockCount; - u16 state; - - u32 gqr[8]; - u32 pir; - double psf[32]; - - u64 coretime[3]; - u64 starttime; - - u32 error; - u32 attributes; - - u32 pmc1; - u32 pmc2; - u32 pmc3; - u32 pmc4; - u32 mmcr0; - u32 mmcr1; -}; - -typedef int (*ThreadFunc)(int argc, void *argv); - -struct OSThread { - OSContext context; - - u32 txtTag; - u8 state; - u8 attr; - - short threadId; - int suspend; - int priority; - - char _[0x394 - 0x330]; - - void *stackBase; - void *stackEnd; - - ThreadFunc entryPoint; - - char _3A0[0x6A0 - 0x3A0]; -};*/ - typedef struct _OsSpecifics { unsigned int addr_OSDynLoad_Acquire; diff --git a/src/common/retain_vars.c b/src/common/retain_vars.c index 36e1192..05585b2 100644 --- a/src/common/retain_vars.c +++ b/src/common/retain_vars.c @@ -1,4 +1,6 @@ #include +#include "fs_defs.h" + u8 gSettingLaunchPyGecko __attribute__((section(".data"))) = 0; u8 gSettingUseUpdatepath __attribute__((section(".data"))) = 0; u8 gSettingPadconMode __attribute__((section(".data"))) = 0; diff --git a/src/common/retain_vars.h b/src/common/retain_vars.h index 9a50978..e8c353f 100644 --- a/src/common/retain_vars.h +++ b/src/common/retain_vars.h @@ -1,6 +1,7 @@ #ifndef RETAINS_VARS_H_ #define RETAINS_VARS_H_ #include +#include "kernel_types.h" extern u8 gSettingLaunchPyGecko; extern u8 gSettingUseUpdatepath; diff --git a/src/dynamic_libs/aoc_functions.c b/src/dynamic_libs/aoc_functions.c index e3449e7..a9faeec 100644 --- a/src/dynamic_libs/aoc_functions.c +++ b/src/dynamic_libs/aoc_functions.c @@ -22,6 +22,7 @@ * distribution. ***************************************************************************/ #include "os_functions.h" +#include "../common/fs_defs.h" EXPORT_DECL(s32, AOC_Initialize, void); EXPORT_DECL(s32, AOC_Finalize, void); diff --git a/src/dynamic_libs/os_functions.c b/src/dynamic_libs/os_functions.c index ea07ea6..04f90bd 100644 --- a/src/dynamic_libs/os_functions.c +++ b/src/dynamic_libs/os_functions.c @@ -62,6 +62,8 @@ EXPORT_DECL(int, OSIsDebuggerPresent, void); EXPORT_DECL(void, OSRestoreInterrupts, void); +// EXPORT_DECL(bool, OSSendMessage, struct OSMessageQueue* mq, struct OSMessage* msg, s32 flags); + EXPORT_DECL(void, OSSetDABR, int, int, int, int); EXPORT_DECL(void, OSSetIABR, int, int); @@ -119,6 +121,8 @@ EXPORT_DECL(void, OSFatal, const char *msg); EXPORT_DECL(void, OSSetExceptionCallback, u8 exceptionType, exception_callback callback); +EXPORT_DECL(void, OSSetExceptionCallbackEx, u8 exceptionMode, u8 exceptionType, exception_callback callback); + EXPORT_DECL(void, __OSSetInterruptHandler, u8 exceptionType, exception_callback callback); EXPORT_DECL(void, DCFlushRange, const void *addr, u32 @@ -265,6 +269,7 @@ void InitOSFunctionPointers(void) { OS_FIND_EXPORT(coreinit_handle, OSFatal); OS_FIND_EXPORT(coreinit_handle, OSGetTitleID); OS_FIND_EXPORT(coreinit_handle, OSSetExceptionCallback); + OS_FIND_EXPORT(coreinit_handle, OSSetExceptionCallbackEx); OS_FIND_EXPORT(coreinit_handle, __OSSetInterruptHandler); OS_FIND_EXPORT(coreinit_handle, DCFlushRange); OS_FIND_EXPORT(coreinit_handle, ICInvalidateRange); @@ -300,6 +305,7 @@ void InitOSFunctionPointers(void) { OS_FIND_EXPORT(coreinit_handle, OSIsInterruptEnabled); OS_FIND_EXPORT(coreinit_handle, OSIsDebuggerPresent); OS_FIND_EXPORT(coreinit_handle, OSRestoreInterrupts); + // OS_FIND_EXPORT(coreinit_handle, OSSendMessage); OS_FIND_EXPORT(coreinit_handle, OSSetDABR); OS_FIND_EXPORT(coreinit_handle, OSSetIABR); OS_FIND_EXPORT(coreinit_handle, OSGetCurrentThread); diff --git a/src/dynamic_libs/os_functions.h b/src/dynamic_libs/os_functions.h index 6383b80..77d3d8c 100644 --- a/src/dynamic_libs/os_functions.h +++ b/src/dynamic_libs/os_functions.h @@ -26,6 +26,7 @@ #include #include "common/os_defs.h" +// #include "../cafe.h" #ifdef __cplusplus extern "C" { @@ -148,6 +149,8 @@ extern int (*OSIsInterruptEnabled)(void); extern int (*OSIsDebuggerPresent)(void); +// extern bool (*OSSendMessage)(struct OSMessageQueue*, struct OSMessage*, s32); + extern void (*OSRestoreInterrupts)(void); extern void (*OSSetDABR)(int, int, int, int); @@ -232,6 +235,8 @@ typedef unsigned char (*exception_callback)(void *interruptedContext); extern void (*OSSetExceptionCallback)(u8 exceptionType, exception_callback callback); +extern void (*OSSetExceptionCallbackEx)(u8 exceptionMode, u8 exceptionType, exception_callback callback); + extern void (*__OSSetInterruptHandler)(u8 interruptType, exception_callback callback); extern int (*OSAllocFromSystem)(unsigned int size, unsigned int align); diff --git a/src/game/memory_area_table.c b/src/game/memory_area_table.c index 20ea351..5978ab6 100644 --- a/src/game/memory_area_table.c +++ b/src/game/memory_area_table.c @@ -17,7 +17,7 @@ #include #include #include -#include "common/common.h" +#include "../common/common.h" #include "memory_area_table.h" typedef struct _memory_values_t diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 474238f..03bcca6 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -2,7 +2,6 @@ #include "../common/kernel_defs.h" #include "../common/common.h" #include "../dynamic_libs/os_functions.h" -#include "../utils/utils.h" #include "syscalls.h" extern void my_PrepareTitle_hook(void); diff --git a/src/pygecko.c b/src/pygecko.c index dc4df3f..cbed7b7 100644 --- a/src/pygecko.c +++ b/src/pygecko.c @@ -12,16 +12,12 @@ #include "dynamic_libs/gx2_functions.h" #include "kernel/syscalls.h" #include "dynamic_libs/fs_functions.h" -#include "system/exception_handler.h" #include "utils/logger.h" #include "system/memory.h" -#include "system/breakpoints.h" -#include "system/threads.h" +#include "system/hardware_breakpoints.h" #include "utils/linked_list.h" -#include "assertions.h" -#include "kernel.h" #include "address.h" -#include "disassembler.h" +#include "system/stack.h" void *client; void *commandBlock; @@ -58,7 +54,8 @@ struct pygecko_bss_t { #define COMMAND_FOLLOW_POINTER 0x60 #define COMMAND_REMOTE_PROCEDURE_CALL 0x70 #define COMMAND_GET_SYMBOL 0x71 -#define COMMAND_MEMORY_SEARCH 0x73 +#define COMMAND_MEMORY_SEARCH 0x72 +#define COMMAND_ADVANCED_MEMORY_SEARCH 0x73 #define COMMAND_EXECUTE_ASSEMBLY 0x81 #define COMMAND_PAUSE_CONSOLE 0x82 #define COMMAND_RESUME_CONSOLE 0x83 @@ -67,6 +64,10 @@ struct pygecko_bss_t { #define COMMAND_GET_OS_VERSION 0x9A #define COMMAND_SET_DATA_BREAKPOINT 0xA0 #define COMMAND_SET_INSTRUCTION_BREAKPOINT 0xA2 +#define COMMAND_TOGGLE_BREAKPOINT 0xA5 +#define COMMAND_REMOVE_ALL_BREAKPOINTS 0xA6 +#define COMMAND_POKE_REGISTERS 0xA7 +#define COMMAND_GET_STACK_TRACE 0xA8 #define COMMAND_RUN_KERNEL_COPY_SERVICE 0xCD #define COMMAND_IOSU_HAX_READ_FILE 0xD0 #define COMMAND_GET_VERSION_HASH 0xE0 @@ -104,7 +105,8 @@ unsigned char *memcpy_buffer[DATA_BUFFER_SIZE]; void pygecko_memcpy(unsigned char *destinationBuffer, unsigned char *sourceBuffer, unsigned int length) { memcpy(memcpy_buffer, sourceBuffer, length); - SC0x25_KernelCopyData((unsigned int) OSEffectiveToPhysical(destinationBuffer), (unsigned int) &memcpy_buffer, length); + SC0x25_KernelCopyData((unsigned int) OSEffectiveToPhysical(destinationBuffer), (unsigned int) &memcpy_buffer, + length); DCFlushRange(destinationBuffer, (u32) length); } @@ -121,7 +123,7 @@ unsigned long getConsoleStatePatchAddress() { // Acquire the RPL and function log_print("Acquiring...\n"); unsigned int avm_handle; - OSDynLoad_Acquire("avm.rpl", (u32 * ) & avm_handle); + OSDynLoad_Acquire("avm.rpl", (u32 *) &avm_handle); ASSERT_ALLOCATED(avm_handle, "avm.rpl") OSDynLoad_FindExport((u32) avm_handle, 0, "AVMGetDRCScanMode", &AVMGetDRCScanMode); ASSERT_ALLOCATED(AVMGetDRCScanMode, "AVMGetDRCScanMode") @@ -405,7 +407,6 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) { ret = sendByte(bss, clientfd, ONLY_ZEROS_READ); CHECK_ERROR(ret < 0) } else { - // TODO Compression of ptr, sending of status, compressed size and data, length: 1 + 4 + len(data) buffer[0] = NON_ZEROS_READ; if (useKernRead) { @@ -968,7 +969,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) { ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (thread count)"); // Send the thread addresses and data - struct node* currentThread = threads; + struct node *currentThread = threads; while (currentThread != NULL) { int data = (int) currentThread->data; log_printf("Thread data: %08x\n", data); @@ -1018,16 +1019,16 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) { break; } - /*case COMMAND_WRITE_SCREEN: { - char message[WRITE_SCREEN_MESSAGE_BUFFER_SIZE]; - ret = recvwait(bss, clientfd, buffer, 4); - ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (write screen seconds)") - int seconds = ((int *) buffer)[0]; - receiveString(bss, clientfd, message, WRITE_SCREEN_MESSAGE_BUFFER_SIZE); - writeScreen(message, seconds); + /*case COMMAND_WRITE_SCREEN: { + char message[WRITE_SCREEN_MESSAGE_BUFFER_SIZE]; + ret = recvwait(bss, clientfd, buffer, 4); + ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (write screen seconds)") + int seconds = ((int *) buffer)[0]; + receiveString(bss, clientfd, message, WRITE_SCREEN_MESSAGE_BUFFER_SIZE); + writeScreen(message, seconds); - break; - }*/ + break; + }*/ case COMMAND_FOLLOW_POINTER: { ret = recvwait(bss, clientfd, buffer, 8); ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (Pointer address and offsets count)") @@ -1130,6 +1131,27 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) { break; } case COMMAND_MEMORY_SEARCH: { + ret = recvwait(bss, clientfd, buffer, sizeof(int) * 3); + CHECK_ERROR(ret < 0); + int address = ((int *) buffer)[0]; + int value = ((int *) buffer)[1]; + int length = ((int *) buffer)[2]; + int index; + int foundAddress = 0; + for (index = address; index < address + length; index += sizeof(int)) { + if (*(int *) index == value) { + foundAddress = index; + break; + } + } + + ((int *) buffer)[0] = foundAddress; + ret = sendwait(bss, clientfd, buffer, sizeof(int)); + CHECK_ERROR(ret < 0) + + break; + } + case COMMAND_ADVANCED_MEMORY_SEARCH: { // Receive the initial data ret = recvwait(bss, clientfd, buffer, 4 * 6); ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (memory search information)") @@ -1263,6 +1285,57 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) { setInstructionAddressBreakPointRegister(address); break; + } + case COMMAND_TOGGLE_BREAKPOINT: { + // Read the address + ret = recvwait(bss, clientfd, buffer, sizeof(int)); + ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (toggle breakpoint)"); + u32 address = ((unsigned int *) buffer)[0]; + + struct Breakpoint *breakpoint = getBreakpoint(address, GENERAL_BREAKPOINTS_COUNT); + + if (breakpoint != NULL) { + breakpoint = removeBreakpoint(breakpoint); + } else { + breakpoint = allocateBreakpoint(); + + if (breakpoint != NULL) { + breakpoint = setBreakpoint(breakpoint, address); + } + } + + break; + } + case COMMAND_REMOVE_ALL_BREAKPOINTS: { + removeAllBreakpoints(); + break; + } + case COMMAND_GET_STACK_TRACE: { + log_print("Getting stack trace...\n"); + struct node *stackTrace = getStackTrace(NULL); + int stackTraceLength = length(stackTrace); + + // Let the client know the length beforehand + int bufferIndex = 0; + ((int *) buffer)[bufferIndex++] = stackTraceLength; + + struct node *currentStackTraceElement = stackTrace; + while (currentStackTraceElement != NULL) { + int address = (int) currentStackTraceElement->data; + log_printf("Stack trace element address: %08x\n", address); + ((int *) buffer)[bufferIndex++] = (int) currentStackTraceElement->data; + + currentStackTraceElement = currentStackTraceElement->next; + } + + log_printf("Sending stack trace with length %i\n", stackTraceLength); + ret = sendwait(bss, clientfd, buffer, sizeof(int) + stackTraceLength); + ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (stack trace)"); + + break; + } + case COMMAND_POKE_REGISTERS: { + } case COMMAND_RUN_KERNEL_COPY_SERVICE: { if (!kernelCopyServiceStarted) { @@ -1290,9 +1363,9 @@ struct sockaddr_in socketAddress; struct pygecko_bss_t *bss; static int runTCPGeckoServer(int argc, void *argv) { - bss = argv; + bss = (struct pygecko_bss_t *) argv; - // setup_os_exceptions(); + setup_os_exceptions(); socket_lib_init(); log_init(COMPUTER_IP_ADDRESS); @@ -1307,17 +1380,17 @@ static int runTCPGeckoServer(int argc, void *argv) { CHECK_ERROR(sockfd == -1) log_printf("bind()...\n"); - ret = bind(sockfd, (void *) &socketAddress, 16); + ret = bind(sockfd, (struct sockaddr *) &socketAddress, (s32) 16); CHECK_ERROR(ret < 0) log_printf("listen()...\n"); - ret = listen(sockfd, 20); + ret = listen(sockfd, (s32) 20); CHECK_ERROR(ret < 0) while (true) { log_printf("accept()...\n"); len = 16; - clientfd = accept(sockfd, (void *) &socketAddress, &len); + clientfd = accept(sockfd, (struct sockaddr *) &socketAddress, (s32 * ) & len); CHECK_ERROR(clientfd == -1) log_printf("commands()...\n"); ret = processCommands(bss, clientfd); diff --git a/src/system/exception_handler.c b/src/system/exception_handler.c index 9c7bee0..d3998bd 100644 --- a/src/system/exception_handler.c +++ b/src/system/exception_handler.c @@ -133,12 +133,12 @@ static unsigned char isi_exception_cb(void *context) { return exceptionCallback(context, 1); } -static unsigned char program_exception_cb(void *context) { +unsigned char program_exception_cb(void *context) { return exceptionCallback(context, 2); } void setup_os_exceptions() { OSSetExceptionCallback(OS_EXCEPTION_DSI, &dsi_exception_cb); OSSetExceptionCallback(OS_EXCEPTION_ISI, &isi_exception_cb); - OSSetExceptionCallback(OS_EXCEPTION_PROGRAM, &program_exception_cb); + // OSSetExceptionCallback(OS_EXCEPTION_PROGRAM, &program_exception_cb); } \ No newline at end of file diff --git a/src/system/exception_handler.h b/src/system/exception_handler.h index a464522..d1dac63 100644 --- a/src/system/exception_handler.h +++ b/src/system/exception_handler.h @@ -6,6 +6,7 @@ extern "C" { #endif #include "../utils/stringify.h" +#include "../common/kernel_types.h" #define OS_EXCEPTION_DSI 2 #define OS_EXCEPTION_ISI 3 diff --git a/src/system/software_breakpoints.h b/src/system/software_breakpoints.h new file mode 100644 index 0000000..28c5834 --- /dev/null +++ b/src/system/software_breakpoints.h @@ -0,0 +1,249 @@ +// https://github.com/Kinnay/DiiBugger/blob/master/wiiu_code/server.cpp + +#ifndef TCPGECKO_BREAKPOINT_EXECUTE_H +#define TCPGECKO_BREAKPOINT_EXECUTE_H + +#include "utilities.h" +#include "exception_handler.h" + +#define OS_EXCEPTION_DSI 2 +#define OS_EXCEPTION_ISI 3 +#define OS_EXCEPTION_PROGRAM 6 + +#define OS_EXCEPTION_MODE_THREAD 1 +#define OS_EXCEPTION_MODE_GLOBAL 2 +#define OS_EXCEPTION_MODE_THREAD_ALL_CORES 3 +#define OS_EXCEPTION_MODE_GLOBAL_ALL_CORES 4 + +struct Breakpoint { + u32 address; + u32 instruction; +}; + +#define INSTRUCTION_TRAP 0x7FE00008 // https://stackoverflow.com/a/10286705/3764804 +#define INSTRUCTION_NOP 0x60000000 + +#define STEP1 10 +#define STEP2 11 + +#define GENERAL_BREAKPOINTS_COUNT 10 +#define STEP_BREAKPOINTS_COUNT 2 + +unsigned char ProgramHandler_Debug(void *interruptedContext) { + OSFatal("Hi"); + + return 0; +} + +void installBreakpointHandler() { + OSSetExceptionCallbackEx((u8) OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, (u8) OS_EXCEPTION_PROGRAM, ProgramHandler_Debug); +} + +struct Breakpoint breakpoints[GENERAL_BREAKPOINTS_COUNT + STEP_BREAKPOINTS_COUNT]; + +struct Breakpoint *removeBreakpoint(struct Breakpoint *breakpoint) { + writeCode(breakpoint->address, breakpoint->instruction); + breakpoint->address = 0; + breakpoint->instruction = 0; + + return breakpoint; +} + +void removeAllBreakpoints() { + for (int index = 0; index < GENERAL_BREAKPOINTS_COUNT; index++) { + struct Breakpoint *breakpoint = &breakpoints[index]; + if (breakpoint->address != 0) { + removeBreakpoint(breakpoint); + } + } +} + +struct Breakpoint *setBreakpoint(struct Breakpoint *breakpoint, u32 address) { + breakpoint->address = address; + breakpoint->instruction = *(u32 *) address; + writeCode(address, (u32) INSTRUCTION_TRAP); + + return breakpoint; +} + +struct Breakpoint *getBreakpoint(u32 address, int size) { + for (int index = 0; index < GENERAL_BREAKPOINTS_COUNT; index++) { + if (breakpoints[index].address == address) { + return &breakpoints[index]; + } + } + + return NULL; +} + +void pokeRegisters(OSContext context, uint32_t gpr[32], double fpr[32]) { + memcpy(&context.gpr, &gpr, sizeof(gpr)); + // memcpy(&context.fpr, &fpr, sizeof(fpr)); +} + +struct Breakpoint *allocateBreakpoint() { + for (int breakpointsIndex = 0; breakpointsIndex < GENERAL_BREAKPOINTS_COUNT; breakpointsIndex++) { + if (breakpoints[breakpointsIndex].address == 0) { + return &breakpoints[breakpointsIndex]; + } + } + + return NULL; +} + +// TODO +u32 stepSource; + +void RestoreStepInstructions() { + writeCode(breakpoints[STEP1].address, breakpoints[STEP1].instruction); + breakpoints[STEP1].address = 0; + breakpoints[STEP1].instruction = 0; + if (breakpoints[STEP2].address) { + writeCode(breakpoints[STEP2].address, breakpoints[STEP2].instruction); + breakpoints[STEP2].address = 0; + breakpoints[STEP2].instruction = 0; + } + + struct Breakpoint *breakpoint = getBreakpoint(stepSource, GENERAL_BREAKPOINTS_COUNT); + if (breakpoint) { + writeCode(breakpoint->address, (u32) INSTRUCTION_TRAP); + } +} + +u32 getInstruction(u32 address) { + struct Breakpoint *breakpoint = getBreakpoint(address, GENERAL_BREAKPOINTS_COUNT + STEP_BREAKPOINTS_COUNT); + if (breakpoint != NULL) { + return breakpoint->instruction; + } + + return *(u32 *) address; +} + +struct Breakpoint *getBreakpointRange(u32 address, u32 length, struct Breakpoint *previousBreakpoint) { + unsigned long startingIndex = 0; + if (previousBreakpoint) { + startingIndex = (previousBreakpoint - breakpoints) + 1; + } + + for (unsigned long index = startingIndex; index < GENERAL_BREAKPOINTS_COUNT + STEP_BREAKPOINTS_COUNT; index++) { + struct Breakpoint breakpoint = breakpoints[index]; + + if (breakpoint.address >= address && breakpoint.address < address + length) { + return &breakpoints[index]; + } + } + + return NULL; +} + +// TODO +OSContext crashContext; + +void predictStepAddresses(bool stepOver) { + u32 currentAddress = crashContext.srr0; + u32 instruction = getInstruction(currentAddress); + + struct Breakpoint *step1 = &breakpoints[STEP1]; + struct Breakpoint *step2 = &breakpoints[STEP2]; + step1->address = currentAddress + 4; + step2->address = 0; + + u8 opcode = instruction >> 26; + if (opcode == 19) { + u16 XO = (instruction >> 1) & 0x3FF; + bool LK = instruction & 1; + if (!LK || !stepOver) { + if (XO == 16) step2->address = crashContext.lr; // bclr + if (XO == 528) step2->address = crashContext.ctr; // bcctr + } + } else if (opcode == 18) { //b + bool AA = instruction & 2; + bool LK = instruction & 1; + u32 LI = instruction & 0x3FFFFFC; + if (!LK || !stepOver) { + if (AA) step1->address = LI; + else { + if (LI & 0x2000000) LI -= 0x4000000; + step1->address = currentAddress + LI; + } + } + } else if (opcode == 16) { //bc + bool AA = instruction & 2; + bool LK = instruction & 1; + u32 BD = instruction & 0xFFFC; + if (!LK || !stepOver) { + if (AA) step2->address = BD; + else { + if (BD & 0x8000) BD -= 0x10000; + step2->address = currentAddress + BD; + } + } + } +} + +void ReportCrash(u32 msg) { + /*crashState = CRASH_STATE_UNRECOVERABLE; + + struct OSMessage messageStruct; + messageStruct.message = msg; + messageStruct.data0 = (u32) & crashContext; + messageStruct.data1 = sizeof(crashContext); + OSSendMessage(&serverQueue, &messageStruct, OS_MESSAGE_BLOCK); + while (true) { + OSSleepTicks((u64) 1000000); + }*/ +} + +/*void HandleProgram(OSContext crashContext) { + //Check if the exception was caused by a breakpoint + if (!(crashContext.srr1 & 0x20000)) { + ReportCrash(SERVER_MESSAGE_PROGRAM); + } + + // Special case, the twu instruction at the start + if (crashContext.srr0 == (u32) entryPoint + 0x48) { + writeCode(crashContext.srr0, (u32) INSTRUCTION_NOP); + } + + if (stepState == STEP_STATE_RUNNING || stepState == STEP_STATE_STEPPING) { + crashState = CRASH_STATE_BREAKPOINT; + + OSMessage message; + message.message = SERVER_MESSAGE_PROGRAM; + message.data0 = (u32) & crashContext; + message.data1 = sizeof(crashContext); + OSSendMessage(&serverQueue, &message, OS_MESSAGE_BLOCK); + OSReceiveMessage(&clientQueue, &message, OS_MESSAGE_BLOCK); + + if (stepState == STEP_STATE_STEPPING) { + RestoreStepInstructions(); + } + + Breakpoint *breakpoint = getBreakpoint(crashContext.srr0); + if (breakpoint != NULL) { + writeCode(breakpoint->address, breakpoint->instruction); + } + + PredictStepAddresses((u32) message.message == CLIENT_MESSAGE_STEP_OVER); + breakpoints[STEP1].instruction = *(u32 * )(breakpoints[STEP1].address); + writeCode(breakpoints[STEP1].address, TRAP); + if (breakpoints[STEP2].address) { + breakpoints[STEP2].instruction = *(u32 * )(breakpoints[STEP2].address); + writeCode(breakpoints[STEP2].address, TRAP); + } + + stepSource = crashContext.srr0; + + if ((u32) message.message == CLIENT_MESSAGE_CONTINUE) stepState = STEP_STATE_CONTINUE; + else stepState = STEP_STATE_STEPPING; + } else if (stepState == STEP_STATE_CONTINUE) { + RestoreStepInstructions(); + stepState = STEP_STATE_RUNNING; + crashState = CRASH_STATE_NONE; + } + + // Resume execution + OSLoadContext(&crashContext); +}*/ + +#endif \ No newline at end of file diff --git a/src/system/stack.h b/src/system/stack.h new file mode 100644 index 0000000..426b1b1 --- /dev/null +++ b/src/system/stack.h @@ -0,0 +1,30 @@ +#ifndef TCPGECKO_STACK_H +#define TCPGECKO_STACK_H + +#include "../utils/linked_list.h" +#include "../common/cafe.h" + +bool isValidStackPointer(u32 stackPointer) { + return stackPointer >= 0x10000000 && stackPointer < 0x20000000; +} + +struct node *getStackTrace(OSContext *context) { + struct node *stackTrace = NULL; + u32 stackPointer = context->gpr[1]; + u32 stackPointersCount = 0; + + while (isValidStackPointer(stackPointer)) { + stackPointer = *(u32 *) stackPointer; + if (!isValidStackPointer(stackPointer)) { + break; + } + + int data = *(u32 * )(stackPointer + 4); + stackTrace = insert(stackTrace, (void *) data); + stackPointersCount++; + } + + return stackTrace; +} + +#endif diff --git a/src/system/utilities.h b/src/system/utilities.h new file mode 100644 index 0000000..1f74cdf --- /dev/null +++ b/src/system/utilities.h @@ -0,0 +1,24 @@ +#ifndef TCPGECKO_UTILITIES_H +#define TCPGECKO_UTILITIES_H + +#include "../dynamic_libs/os_functions.h" +#include "../utils/logger.h" +#include "../kernel.h" +#include "../common/kernel_types.h" + +void writeCode(u32 address, u32 instruction) { + u32 *pointer = (u32 *) (address + 0xA0000000); + *pointer = instruction; + DCFlushRange(pointer, 4); + ICInvalidateRange(pointer, 4); +} + +void patchFunction(void *function, char *patchBytes, unsigned int patchBytesSize, int functionOffset) { + log_print("Patching function...\n"); + void *patchAddress = function + functionOffset; + log_printf("Patch address: %p\n", patchAddress); + kernelCopy((unsigned char *) patchAddress, (unsigned char *) patchBytes, patchBytesSize); + log_print("Successfully patched!\n"); +} + +#endif \ No newline at end of file diff --git a/tcpgecko.elf b/tcpgecko.elf index 71a64bf..423b2e3 100644 Binary files a/tcpgecko.elf and b/tcpgecko.elf differ