mirror of
https://github.com/wiiu-env/gdbstub_plugin.git
synced 2024-11-25 21:14:23 +01:00
WIP
This commit is contained in:
parent
5a3bae8616
commit
60a0679699
22
main.py
22
main.py
@ -116,6 +116,7 @@ COMMAND_TOGGLE_BREAKPOINT = 8
|
|||||||
COMMAND_POKE_REGISTERS = 9
|
COMMAND_POKE_REGISTERS = 9
|
||||||
COMMAND_RECEIVE_MESSAGES = 10
|
COMMAND_RECEIVE_MESSAGES = 10
|
||||||
COMMAND_SEND_MESSAGE = 11
|
COMMAND_SEND_MESSAGE = 11
|
||||||
|
COMMAND_DISASM = 12
|
||||||
|
|
||||||
class Debugger:
|
class Debugger:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -157,6 +158,12 @@ class Debugger:
|
|||||||
self.sendall(struct.pack(">II", addr, num))
|
self.sendall(struct.pack(">II", addr, num))
|
||||||
data = self.recvall(num)
|
data = self.recvall(num)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def disasm(self, addr, num):
|
||||||
|
self.sendbyte(COMMAND_DISASM)
|
||||||
|
self.sendall(struct.pack(">II", addr, num))
|
||||||
|
length = struct.unpack(">I", self.recvall(4))[0]
|
||||||
|
return self.recvall(length).decode("ascii")
|
||||||
|
|
||||||
def write(self, addr, data):
|
def write(self, addr, data):
|
||||||
self.sendbyte(COMMAND_WRITE)
|
self.sendbyte(COMMAND_WRITE)
|
||||||
@ -503,18 +510,11 @@ class DisassemblyWidget(QTextEdit):
|
|||||||
self.updateText()
|
self.updateText()
|
||||||
self.updateHighlight()
|
self.updateHighlight()
|
||||||
|
|
||||||
def updateText(self):
|
def updateText(self):
|
||||||
if debugger.connected:
|
|
||||||
blob = debugger.read(self.base, 0x60)
|
|
||||||
else:
|
|
||||||
blob = b"\x00" * 0x60
|
|
||||||
|
|
||||||
text = ""
|
text = ""
|
||||||
for i in range(24):
|
if debugger.connected:
|
||||||
address = self.base + i * 4
|
text = debugger.disasm(self.base, 0x60)
|
||||||
value = struct.unpack_from(">I", blob, i * 4)[0]
|
|
||||||
instr = disassemble.disassemble(value, address)
|
|
||||||
text += "%08X: %08X %s\n" %(address, value, instr)
|
|
||||||
self.setPlainText(text)
|
self.setPlainText(text)
|
||||||
|
|
||||||
def updateHighlight(self):
|
def updateHighlight(self):
|
||||||
|
160
src/debugger.cpp
160
src/debugger.cpp
@ -7,20 +7,27 @@
|
|||||||
#include <coreinit/debug.h>
|
#include <coreinit/debug.h>
|
||||||
#include <coreinit/dynload.h>
|
#include <coreinit/dynload.h>
|
||||||
#include <coreinit/exception.h>
|
#include <coreinit/exception.h>
|
||||||
|
#include <coreinit/interrupts.h>
|
||||||
#include <coreinit/memory.h>
|
#include <coreinit/memory.h>
|
||||||
|
#include <coreinit/scheduler.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <gx2/context.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <sysapp/switch.h>
|
||||||
#include <vpad/input.h>
|
#include <vpad/input.h>
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
Debugger *debugger;
|
Debugger *debugger;
|
||||||
|
bool initDebugState = false;
|
||||||
|
|
||||||
bool BreakPoint::isRange(uint32_t addr, uint32_t length) const {
|
bool BreakPoint::isRange(uint32_t addr, uint32_t length) const {
|
||||||
return address >= addr && address <= addr + length - 1;
|
return address >= addr && address <= addr + length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BreakPoint *BreakPointMgr::find(uint32_t addr, bool includeSpecial) {
|
BreakPoint *BreakPointMgr::find(uint32_t addr, bool includeSpecial) {
|
||||||
BreakPoint *bp = breakpoints.find(addr);
|
BreakPoint *bp = breakpoints.find(addr);
|
||||||
if (!bp && includeSpecial) {
|
if (!bp && includeSpecial) {
|
||||||
@ -280,7 +287,6 @@ bool ExceptionState::isBreakpoint() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ExceptionState::resume() {
|
void ExceptionState::resume() {
|
||||||
DEBUG_FUNCTION_LINE("OSLoadContext");
|
|
||||||
OSLoadContext(&context);
|
OSLoadContext(&context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,30 +546,26 @@ void Debugger::handleBreakPoint(ExceptionState *state) {
|
|||||||
if (firstTrap) {
|
if (firstTrap) {
|
||||||
firstTrap = false;
|
firstTrap = false;
|
||||||
|
|
||||||
Screen screen;
|
auto *screen = new Screen;
|
||||||
screen.init();
|
|
||||||
Screen::drawText(
|
Screen::drawText(
|
||||||
0, 0, "Waiting for debugger connection.\n"
|
0, 0, "Waiting for debugger connection.\n"
|
||||||
"Press the home button to continue without debugger.\n"
|
"Press the home button to continue without debugger.\n"
|
||||||
"You can still connect while the game is running.");
|
"You can still connect while the game is running.");
|
||||||
Screen::flip();
|
Screen::flip();
|
||||||
|
delete screen;
|
||||||
|
|
||||||
while (!connected) {
|
while (!connected) {
|
||||||
uint32_t buttons = GetInput(VPAD_BUTTON_HOME);
|
uint32_t buttons = GetInput(VPAD_BUTTON_HOME);
|
||||||
if (buttons) {
|
if (buttons) {
|
||||||
DEBUG_FUNCTION_LINE("Pressed home");
|
|
||||||
state->context.srr0 += 4;
|
state->context.srr0 += 4;
|
||||||
state->resume();
|
state->resume();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("stepper.handleBreakPoint(state);");
|
|
||||||
|
|
||||||
stepper.handleBreakPoint(state);
|
stepper.handleBreakPoint(state);
|
||||||
|
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
DEBUG_FUNCTION_LINE("if (!connected) {");
|
|
||||||
handleFatalCrash(&state->context, state->type);
|
handleFatalCrash(&state->context, state->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -671,10 +673,6 @@ void Debugger::cleanup() {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void OSRestoreInterrupts(int state);
|
|
||||||
extern "C" void __OSLockScheduler(void *);
|
|
||||||
extern "C" void __OSUnlockScheduler(void *);
|
|
||||||
extern "C" int OSDisableInterrupts();
|
|
||||||
|
|
||||||
static const char **commandNames = (const char *[]){
|
static const char **commandNames = (const char *[]){
|
||||||
"COMMAND_CLOSE",
|
"COMMAND_CLOSE",
|
||||||
@ -688,15 +686,49 @@ static const char **commandNames = (const char *[]){
|
|||||||
"COMMAND_TOGGLE_BREAKPOINT",
|
"COMMAND_TOGGLE_BREAKPOINT",
|
||||||
"COMMAND_POKE_REGISTERS",
|
"COMMAND_POKE_REGISTERS",
|
||||||
"COMMAND_RECEIVE_MESSAGES",
|
"COMMAND_RECEIVE_MESSAGES",
|
||||||
"COMMAND_SEND_MESSAGE"};
|
"COMMAND_SEND_MESSAGE",
|
||||||
|
"COMMAND_DISASM"};
|
||||||
|
|
||||||
|
|
||||||
|
#define LOG_DISASSEMBLY_SIZE (4096)
|
||||||
|
|
||||||
|
static char
|
||||||
|
sDisassemblyBuffer[LOG_DISASSEMBLY_SIZE];
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
sDisassemblyLength = 0;
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
disassemblyPrintCallback(const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
sDisassemblyLength += vsprintf(sDisassemblyBuffer + sDisassemblyLength,
|
||||||
|
fmt, args);
|
||||||
|
sDisassemblyBuffer[sDisassemblyLength] = 0;
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void eraseAllSubStr(std::string & mainStr, const std::string & toErase)
|
||||||
|
{
|
||||||
|
size_t pos = std::string::npos;
|
||||||
|
// Search for the substring in string in a loop untill nothing is found
|
||||||
|
while ((pos = mainStr.find(toErase) )!= std::string::npos)
|
||||||
|
{
|
||||||
|
// If found then erase it from string
|
||||||
|
mainStr.erase(pos, toErase.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#define OSIopShell_Command_Disassemble ((void (*)(void*, uint32_t))(0x101C400 + 0x173e0))
|
||||||
|
#define __os_printf ((void (*)(char*, ...))(0x101C400 + 0x012e88))
|
||||||
|
|
||||||
void Debugger::mainLoop(Client *client) {
|
void Debugger::mainLoop(Client *client) {
|
||||||
DEBUG_FUNCTION_LINE("About to enter mainLoop while");
|
|
||||||
while (!stopRunning) {
|
while (!stopRunning) {
|
||||||
uint8_t cmd;
|
uint8_t cmd;
|
||||||
if (!client->recvall(&cmd, 1)) return;
|
if (!client->recvall(&cmd, 1)) return;
|
||||||
|
|
||||||
if (cmd <= 11) {
|
if (cmd <= 12 && cmd != 10) {
|
||||||
DEBUG_FUNCTION_LINE("Recieved command %s %d", commandNames[cmd], cmd);
|
DEBUG_FUNCTION_LINE("Recieved command %s %d", commandNames[cmd], cmd);
|
||||||
}
|
}
|
||||||
if (cmd == COMMAND_CLOSE) {
|
if (cmd == COMMAND_CLOSE) {
|
||||||
@ -713,6 +745,50 @@ void Debugger::mainLoop(Client *client) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
|
} else if (cmd == COMMAND_DISASM) {
|
||||||
|
uint32_t addr, length;
|
||||||
|
if (!client->recvall(&addr, 4)) return;
|
||||||
|
if (!client->recvall(&length, 4)) return;
|
||||||
|
|
||||||
|
|
||||||
|
char *buffer = new char[0x40];
|
||||||
|
|
||||||
|
auto addrAsPtr = (uint32_t *) (addr & 0xfffffffc);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DisassemblePPCRange(reinterpret_cast<void *>(addr + 0x20), reinterpret_cast<void *>(addr + length), reinterpret_cast<DisassemblyPrintFn>(__os_printf),OSGetSymbolName,
|
||||||
|
static_cast<DisassemblePPCFlags>(0x121));
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < length / 4; i++) {
|
||||||
|
DisassemblePPCOpcode(&addrAsPtr[i],
|
||||||
|
buffer,
|
||||||
|
0x40,
|
||||||
|
OSGetSymbolName,
|
||||||
|
static_cast<DisassemblePPCFlags>(0x121));
|
||||||
|
disassemblyPrintCallback("0x%08x 0x%08x %s\n",&addrAsPtr[i],addrAsPtr[i],buffer);
|
||||||
|
}
|
||||||
|
delete[] buffer;
|
||||||
|
|
||||||
|
|
||||||
|
std::string shit(sDisassemblyBuffer);
|
||||||
|
eraseAllSubStr(shit, "(null)");
|
||||||
|
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE("done");
|
||||||
|
|
||||||
|
auto length_ = shit.length() + 1;
|
||||||
|
if (!client->sendall(&length_, 4)) {
|
||||||
|
sDisassemblyLength = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!client->sendall(shit.c_str(), length_)) {
|
||||||
|
sDisassemblyLength = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sDisassemblyLength = 0;
|
||||||
} else if (cmd == COMMAND_WRITE) {
|
} else if (cmd == COMMAND_WRITE) {
|
||||||
uint32_t addr, length;
|
uint32_t addr, length;
|
||||||
if (!client->recvall(&addr, 4)) return;
|
if (!client->recvall(&addr, 4)) return;
|
||||||
@ -733,15 +809,18 @@ void Debugger::mainLoop(Client *client) {
|
|||||||
} else if (cmd == COMMAND_GET_MODULE_NAME) {
|
} else if (cmd == COMMAND_GET_MODULE_NAME) {
|
||||||
char name[0x40];
|
char name[0x40];
|
||||||
int length = 0x40;
|
int length = 0x40;
|
||||||
OSDynLoad_GetModuleName(reinterpret_cast<OSDynLoad_Module>(-1), name, &length);
|
if(OSDynLoad_GetModuleName(reinterpret_cast<OSDynLoad_Module>(-1), name, &length) != OS_DYNLOAD_OK){
|
||||||
|
strncat(name, "ERROR", sizeof(name) -1);
|
||||||
|
}
|
||||||
length = strlen(name);
|
length = strlen(name);
|
||||||
|
|
||||||
if (!client->sendall(&length, 4)) return;
|
if (!client->sendall(&length, 4)) return;
|
||||||
if (!client->sendall(name, length)) return;
|
if (!client->sendall(name, length)) return;
|
||||||
} else if (cmd == COMMAND_GET_MODULE_LIST) {
|
} else if (cmd == COMMAND_GET_MODULE_LIST) {
|
||||||
|
|
||||||
int num_rpls = OSDynLoad_GetNumberOfRPLs();
|
int num_rpls = OSDynLoad_GetNumberOfRPLs();
|
||||||
if (num_rpls == 0) {
|
if (num_rpls == 0) {
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<OSDynLoad_NotifyData> rpls;
|
std::vector<OSDynLoad_NotifyData> rpls;
|
||||||
@ -749,7 +828,7 @@ void Debugger::mainLoop(Client *client) {
|
|||||||
|
|
||||||
bool ret = OSDynLoad_GetRPLInfo(0, num_rpls, rpls.data());
|
bool ret = OSDynLoad_GetRPLInfo(0, num_rpls, rpls.data());
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[0x1000]; //This should be enough
|
char buffer[0x1000]; //This should be enough
|
||||||
@ -784,6 +863,7 @@ void Debugger::mainLoop(Client *client) {
|
|||||||
OSThread *current = ThreadList;
|
OSThread *current = ThreadList;
|
||||||
while (current) {
|
while (current) {
|
||||||
const char *name = OSGetThreadName(current);
|
const char *name = OSGetThreadName(current);
|
||||||
|
OSReport("name %s", name);
|
||||||
|
|
||||||
uint32_t namelen = 0;
|
uint32_t namelen = 0;
|
||||||
if (name) {
|
if (name) {
|
||||||
@ -795,7 +875,7 @@ void Debugger::mainLoop(Client *client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int priority = current->basePriority;
|
int priority = current->basePriority;
|
||||||
int type = *(uint32_t *) (current->__unk11);
|
int type = *((uint32_t *) current->__unk11);
|
||||||
if (type == 1) {
|
if (type == 1) {
|
||||||
priority -= 0x20;
|
priority -= 0x20;
|
||||||
} else if (type == 2) {
|
} else if (type == 2) {
|
||||||
@ -905,24 +985,20 @@ void Debugger::mainLoop(Client *client) {
|
|||||||
|
|
||||||
void Debugger::threadFunc() {
|
void Debugger::threadFunc() {
|
||||||
DEBUG_FUNCTION_LINE("Hello from debugger thread :)!");
|
DEBUG_FUNCTION_LINE("Hello from debugger thread :)!");
|
||||||
OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_DSI, dsiHandler);
|
prevDsiHandler = OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_DSI, dsiHandler);
|
||||||
OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_ISI, isiHandler);
|
prevIsiHandler = OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_ISI, isiHandler);
|
||||||
OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_PROGRAM, programHandler);
|
prevProgramHandler = OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_PROGRAM, programHandler);
|
||||||
DEBUG_FUNCTION_LINE("Callback init done.!");
|
|
||||||
|
|
||||||
Server server;
|
Server server;
|
||||||
Client client;
|
Client client;
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Set initialized = true");
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
while (!stopRunning) {
|
while (!stopRunning) {
|
||||||
if (!server.init(Socket::TCP)) continue;
|
if (!server.init(Socket::TCP)) continue;
|
||||||
if (!server.bind(1560)) continue;
|
if (!server.bind(1560)) continue;
|
||||||
if (!server.accept(&client)) continue;
|
if (!server.accept(&client)) continue;
|
||||||
DEBUG_FUNCTION_LINE("Accepted a connection");
|
|
||||||
connected = true;
|
connected = true;
|
||||||
mainLoop(&client);
|
mainLoop(&client);
|
||||||
DEBUG_FUNCTION_LINE("Lets do some cleanup");
|
|
||||||
cleanup();
|
cleanup();
|
||||||
connected = false;
|
connected = false;
|
||||||
client.close();
|
client.close();
|
||||||
@ -931,55 +1007,55 @@ void Debugger::threadFunc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Debugger::threadEntry(int argc, const char **argv) {
|
int Debugger::threadEntry(int argc, const char **argv) {
|
||||||
DEBUG_FUNCTION_LINE("threadEntry");
|
|
||||||
debugger->threadFunc();
|
debugger->threadFunc();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Debugger::start() {
|
void Debugger::start() {
|
||||||
initialized = false;
|
initialized = false;
|
||||||
connected = false;
|
connected = false;
|
||||||
firstTrap = true;
|
firstTrap = true;
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("OSInitMessageQueue");
|
|
||||||
OSInitMessageQueue(&eventQueue, eventMessages, MESSAGE_COUNT);
|
OSInitMessageQueue(&eventQueue, eventMessages, MESSAGE_COUNT);
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("init breakpoints");
|
|
||||||
breakpoints.init();
|
breakpoints.init();
|
||||||
DEBUG_FUNCTION_LINE("init exceptions");
|
|
||||||
exceptions.init();
|
exceptions.init();
|
||||||
DEBUG_FUNCTION_LINE("init stepper");
|
|
||||||
stepper.init();
|
stepper.init();
|
||||||
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Alloc thread");
|
|
||||||
serverThread = (OSThread *) memalign(0x20, sizeof(OSThread));
|
serverThread = (OSThread *) memalign(0x20, sizeof(OSThread));
|
||||||
DEBUG_FUNCTION_LINE("Alloc stack");
|
serverStack = (char *) memalign(0x20, STACK_SIZE);
|
||||||
serverStack = (char *) memalign(0x20, STACK_SIZE);
|
|
||||||
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Create thread");
|
|
||||||
OSCreateThread(
|
OSCreateThread(
|
||||||
serverThread, threadEntry, 0, 0,
|
serverThread, threadEntry, 0, 0,
|
||||||
serverStack + STACK_SIZE, STACK_SIZE,
|
serverStack + STACK_SIZE, STACK_SIZE,
|
||||||
0, 12);
|
0, OS_THREAD_ATTRIB_AFFINITY_CPU2 | OS_THREAD_ATTRIB_DETACHED);
|
||||||
DEBUG_FUNCTION_LINE("Set thread name");
|
|
||||||
OSSetThreadName(serverThread, "Debug Server");
|
OSSetThreadName(serverThread, "Debug Server");
|
||||||
DEBUG_FUNCTION_LINE("Resume thread");
|
|
||||||
OSResumeThread(serverThread);
|
OSResumeThread(serverThread);
|
||||||
|
|
||||||
while (!initialized) {
|
while (!initialized) {
|
||||||
DEBUG_FUNCTION_LINE("Wait for thread init");
|
|
||||||
OSSleepTicks(OSMillisecondsToTicks(20));
|
OSSleepTicks(OSMillisecondsToTicks(20));
|
||||||
}
|
}
|
||||||
|
initDebugState = true;
|
||||||
|
DCFlushRange(&initDebugState, sizeof(initDebugState));
|
||||||
DEBUG_FUNCTION_LINE("Thread init done! Exit start()");
|
DEBUG_FUNCTION_LINE("Thread init done! Exit start()");
|
||||||
}
|
}
|
||||||
|
|
||||||
Debugger::~Debugger() {
|
Debugger::~Debugger() {
|
||||||
stopRunning = true;
|
stopRunning = true;
|
||||||
|
DCFlushRange(&stopRunning, sizeof(stopRunning));
|
||||||
OSJoinThread(serverThread, nullptr);
|
OSJoinThread(serverThread, nullptr);
|
||||||
free(serverStack);
|
free(serverStack);
|
||||||
serverStack = nullptr;
|
serverStack = nullptr;
|
||||||
free(serverThread);
|
free(serverThread);
|
||||||
serverThread = nullptr;
|
serverThread = nullptr;
|
||||||
|
|
||||||
|
initialized = false;
|
||||||
|
connected = false;
|
||||||
|
firstTrap = true;
|
||||||
|
|
||||||
|
// Restore exceptions.
|
||||||
|
OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_DSI, prevDsiHandler);
|
||||||
|
OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_ISI, prevIsiHandler);
|
||||||
|
OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_PROGRAM, prevProgramHandler);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <coreinit/mutex.h>
|
#include <coreinit/mutex.h>
|
||||||
#include <coreinit/thread.h>
|
#include <coreinit/thread.h>
|
||||||
|
|
||||||
|
#include <coreinit/exception.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -233,7 +234,8 @@ private:
|
|||||||
COMMAND_TOGGLE_BREAKPOINT,
|
COMMAND_TOGGLE_BREAKPOINT,
|
||||||
COMMAND_POKE_REGISTERS,
|
COMMAND_POKE_REGISTERS,
|
||||||
COMMAND_RECEIVE_MESSAGES,
|
COMMAND_RECEIVE_MESSAGES,
|
||||||
COMMAND_SEND_MESSAGE
|
COMMAND_SEND_MESSAGE,
|
||||||
|
COMMAND_DISASM
|
||||||
};
|
};
|
||||||
|
|
||||||
static int threadEntry(int argc, const char **argv);
|
static int threadEntry(int argc, const char **argv);
|
||||||
@ -269,6 +271,11 @@ private:
|
|||||||
bool initialized{};
|
bool initialized{};
|
||||||
bool connected{};
|
bool connected{};
|
||||||
bool firstTrap{};
|
bool firstTrap{};
|
||||||
|
|
||||||
|
OSExceptionCallbackFn prevDsiHandler = nullptr;
|
||||||
|
OSExceptionCallbackFn prevIsiHandler = nullptr;
|
||||||
|
OSExceptionCallbackFn prevProgramHandler = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" Debugger *debugger;
|
extern "C" Debugger *debugger;
|
||||||
|
extern bool initDebugState;
|
||||||
|
55
src/main.cpp
55
src/main.cpp
@ -1,28 +1,65 @@
|
|||||||
#include "debugger.h"
|
#include "debugger.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
#include <coreinit/cache.h>
|
||||||
#include <coreinit/debug.h>
|
#include <coreinit/debug.h>
|
||||||
|
#include <coreinit/dynload.h>
|
||||||
|
#include <coreinit/memorymap.h>
|
||||||
|
#include <kernel/kernel.h>
|
||||||
#include <wups.h>
|
#include <wups.h>
|
||||||
|
|
||||||
OSThread **pThreadList;
|
OSThread **pThreadList;
|
||||||
|
|
||||||
|
|
||||||
WUPS_PLUGIN_NAME("Debugger");
|
WUPS_PLUGIN_NAME("Debugger");
|
||||||
WUPS_PLUGIN_DESCRIPTION("FTP Server");
|
WUPS_PLUGIN_DESCRIPTION("Wii U Debugger");
|
||||||
WUPS_PLUGIN_VERSION("0.1");
|
WUPS_PLUGIN_VERSION("0.1");
|
||||||
WUPS_PLUGIN_AUTHOR("Kinnay");
|
WUPS_PLUGIN_AUTHOR("Kinnay, Maschell");
|
||||||
WUPS_PLUGIN_LICENSE("GPL");
|
WUPS_PLUGIN_LICENSE("GPL");
|
||||||
|
|
||||||
WUPS_USE_WUT_DEVOPTAB();
|
WUPS_USE_WUT_DEVOPTAB();
|
||||||
|
|
||||||
INITIALIZE_PLUGIN() {
|
/* https://github.com/QuarkTheAwesome/CafeBinPatch/blob/main/src/runtime-patcher.cpp#L58 */
|
||||||
InstallExceptionHandlers();
|
bool PatchInstruction(void *instr, uint32_t original, uint32_t replacement) {
|
||||||
|
uint32_t current = *(uint32_t *) instr;
|
||||||
|
if (current != original) return current == replacement;
|
||||||
|
|
||||||
|
KernelCopyData(OSEffectiveToPhysical((uint32_t) instr), OSEffectiveToPhysical((uint32_t) &replacement), sizeof(replacement));
|
||||||
|
//Only works on AROMA! WUPS 0.1's KernelCopyData is uncached, needs DCInvalidate here instead
|
||||||
|
DCFlushRange(instr, 4);
|
||||||
|
ICInvalidateRange(instr, 4);
|
||||||
|
|
||||||
|
current = *(uint32_t *) instr;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* https://github.com/QuarkTheAwesome/CafeBinPatch/blob/main/src/runtime-patcher.cpp#L74 */
|
||||||
|
bool PatchDynLoadFunctions() {
|
||||||
|
uint32_t *patch1 = ((uint32_t *) &OSDynLoad_GetNumberOfRPLs) + 6;
|
||||||
|
uint32_t *patch2 = ((uint32_t *) &OSDynLoad_GetRPLInfo) + 22;
|
||||||
|
|
||||||
|
if (!PatchInstruction(patch1, 0x41820038 /* beq +38 */, 0x60000000 /*nop*/)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!PatchInstruction(patch2, 0x41820100 /* beq +100 */, 0x60000000 /*nop*/)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
INITIALIZE_PLUGIN() {
|
||||||
|
PatchDynLoadFunctions();
|
||||||
|
}
|
||||||
|
|
||||||
ON_APPLICATION_START() {
|
ON_APPLICATION_START() {
|
||||||
initLogging();
|
initLogging();
|
||||||
DEBUG_FUNCTION_LINE("Started Debugger plugin");
|
DEBUG_FUNCTION_LINE("Hello from Debugger plugin");
|
||||||
pThreadList = (OSThread **) 0x100567F8;
|
pThreadList = (OSThread **) 0x100567F8; // 100567f8
|
||||||
debugger = new Debugger();
|
debugger = new Debugger();
|
||||||
|
DCFlushRange(&debugger, 4);
|
||||||
|
DCFlushRange(debugger, sizeof(Debugger));
|
||||||
DEBUG_FUNCTION_LINE("Created Debugger");
|
DEBUG_FUNCTION_LINE("Created Debugger");
|
||||||
debugger->start();
|
debugger->start();
|
||||||
DEBUG_FUNCTION_LINE("Started Debugger thread");
|
DEBUG_FUNCTION_LINE("Started Debugger thread");
|
||||||
@ -34,3 +71,7 @@ ON_APPLICATION_REQUESTS_EXIT() {
|
|||||||
DEBUG_FUNCTION_LINE("Deleted Debugger thread");
|
DEBUG_FUNCTION_LINE("Deleted Debugger thread");
|
||||||
deinitLogging();
|
deinitLogging();
|
||||||
}
|
}
|
||||||
|
ON_APPLICATION_ENDS() {
|
||||||
|
initDebugState = false;
|
||||||
|
DCFlushRange(&initDebugState, sizeof(initDebugState));
|
||||||
|
}
|
||||||
|
@ -1,17 +1,35 @@
|
|||||||
|
#include "logger.h"
|
||||||
|
#include <coreinit/exception.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <wups.h>
|
#include <wups.h>
|
||||||
|
|
||||||
DECL_FUNCTION(int, OSSetExceptionCallback) {
|
extern bool initDebugState;
|
||||||
return 0;
|
|
||||||
|
DECL_FUNCTION(OSExceptionCallbackFn, OSSetExceptionCallback,
|
||||||
|
OSExceptionType exceptionType,
|
||||||
|
OSExceptionCallbackFn callback) {
|
||||||
|
if (initDebugState) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
return real_OSSetExceptionCallback(exceptionType, callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DECL_FUNCTION(int, OSSetExceptionCallbackEx) {
|
DECL_FUNCTION(OSExceptionCallbackFn, OSSetExceptionCallbackEx,
|
||||||
return 0;
|
OSExceptionMode mode,
|
||||||
|
OSExceptionType exceptionType,
|
||||||
|
OSExceptionCallbackFn callback) {
|
||||||
|
if (initDebugState) {
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
return real_OSSetExceptionCallbackEx(mode, exceptionType, callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DECL_FUNCTION(int, OSIsDebuggerInitialized) {
|
DECL_FUNCTION(int, OSIsDebuggerInitialized) {
|
||||||
return true;
|
return initDebugState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OSSetExceptionCallbackEx is just a branch to another function.
|
||||||
WUPS_MUST_REPLACE(OSSetExceptionCallback, WUPS_LOADER_LIBRARY_COREINIT, OSSetExceptionCallback);
|
// Instead of "fixing" the FunctionPatcher, we use this hacky solution :)
|
||||||
WUPS_MUST_REPLACE(OSSetExceptionCallbackEx, WUPS_LOADER_LIBRARY_COREINIT, OSSetExceptionCallbackEx);
|
WUPS_MUST_REPLACE_PHYSICAL_FOR_PROCESS(OSSetExceptionCallbackEx, (0x3201C400 + 0x286b0), (0x101C400 + 0x286b0), WUPS_FP_TARGET_PROCESS_GAME_AND_MENU);
|
||||||
WUPS_MUST_REPLACE(OSIsDebuggerInitialized, WUPS_LOADER_LIBRARY_COREINIT, OSIsDebuggerInitialized);
|
WUPS_MUST_REPLACE_FOR_PROCESS(OSSetExceptionCallback, WUPS_LOADER_LIBRARY_COREINIT, OSSetExceptionCallback, WUPS_FP_TARGET_PROCESS_GAME_AND_MENU);
|
||||||
|
WUPS_MUST_REPLACE_FOR_PROCESS(OSIsDebuggerInitialized, WUPS_LOADER_LIBRARY_COREINIT, OSIsDebuggerInitialized, WUPS_FP_TARGET_PROCESS_GAME_AND_MENU);
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
|
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include <coreinit/debug.h>
|
||||||
|
#include <gx2/state.h>
|
||||||
|
|
||||||
#include <memory/mappedmemory.h>
|
#include <memory/mappedmemory.h>
|
||||||
|
|
||||||
Screen::Screen() : screenBuffer(nullptr) {}
|
Screen::Screen() : screenBuffer(nullptr) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
Screen::~Screen() {
|
Screen::~Screen() {
|
||||||
if (screenBuffer) {
|
destroyBuffer();
|
||||||
MEMFreeToMappedMemory(screenBuffer);
|
|
||||||
screenBuffer = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::init() {
|
void Screen::init() {
|
||||||
@ -17,6 +19,9 @@ void Screen::init() {
|
|||||||
uint32_t bufferSize0 = OSScreenGetBufferSizeEx(SCREEN_TV);
|
uint32_t bufferSize0 = OSScreenGetBufferSizeEx(SCREEN_TV);
|
||||||
uint32_t bufferSize1 = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
uint32_t bufferSize1 = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
||||||
screenBuffer = MEMAllocFromMappedMemoryForGX2Ex(bufferSize0 + bufferSize1, 0x100);
|
screenBuffer = MEMAllocFromMappedMemoryForGX2Ex(bufferSize0 + bufferSize1, 0x100);
|
||||||
|
if (screenBuffer == nullptr) {
|
||||||
|
OSFatal("Failed to allocate screenbuffer");
|
||||||
|
}
|
||||||
OSScreenSetBufferEx(SCREEN_TV, screenBuffer);
|
OSScreenSetBufferEx(SCREEN_TV, screenBuffer);
|
||||||
OSScreenSetBufferEx(SCREEN_DRC, (char *) screenBuffer + bufferSize0);
|
OSScreenSetBufferEx(SCREEN_DRC, (char *) screenBuffer + bufferSize0);
|
||||||
|
|
||||||
@ -86,3 +91,11 @@ void Screen::flip() {
|
|||||||
flip(SCREEN_TV);
|
flip(SCREEN_TV);
|
||||||
flip(SCREEN_DRC);
|
flip(SCREEN_DRC);
|
||||||
}
|
}
|
||||||
|
void Screen::destroyBuffer() {
|
||||||
|
if (screenBuffer) {
|
||||||
|
MEMFreeToMappedMemory(screenBuffer);
|
||||||
|
screenBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
GX2Init(nullptr);
|
||||||
|
}
|
||||||
|
@ -22,6 +22,8 @@ public:
|
|||||||
static void drawText(OSScreenID screen, int x, int y, const char *text);
|
static void drawText(OSScreenID screen, int x, int y, const char *text);
|
||||||
static void flip(OSScreenID screen);
|
static void flip(OSScreenID screen);
|
||||||
|
|
||||||
|
void destroyBuffer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void *screenBuffer;
|
void *screenBuffer;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user