#pragma once #include #include "Cafe/HW/Espresso/PPCState.h" #define DEBUGGER_BP_T_NORMAL 0 // normal breakpoint #define DEBUGGER_BP_T_ONE_SHOT 1 // normal breakpoint, deletes itself after trigger (used for stepping) #define DEBUGGER_BP_T_MEMORY_READ 2 // memory breakpoint #define DEBUGGER_BP_T_MEMORY_WRITE 3 // memory breakpoint #define DEBUGGER_BP_T_LOGGING 4 // logging breakpoint, prints the breakpoint comment and stack trace whenever hit #define DEBUGGER_BP_T_GDBSTUB 1 // breakpoint created by GDBStub #define DEBUGGER_BP_T_DEBUGGER 2 // breakpoint created by Cemu's debugger #define DEBUGGER_BP_T_GDBSTUB_TW 0x7C010008 #define DEBUGGER_BP_T_DEBUGGER_TW 0x7C020008 struct DebuggerBreakpoint { uint32 address; uint32 originalOpcodeValue; mutable uint8 bpType; mutable bool enabled; mutable std::wstring comment; mutable uint8 dbType = DEBUGGER_BP_T_DEBUGGER; DebuggerBreakpoint(uint32 address, uint32 originalOpcode, uint8 bpType = 0, bool enabled = true, std::wstring comment = std::wstring()) :address(address), originalOpcodeValue(originalOpcode), bpType(bpType), enabled(enabled), comment(std::move(comment)) { next = nullptr; } bool operator<(const DebuggerBreakpoint& rhs) const { return address < rhs.address; } bool operator==(const DebuggerBreakpoint& rhs) const { return address == rhs.address; } bool isExecuteBP() const { return bpType == DEBUGGER_BP_T_NORMAL || bpType == DEBUGGER_BP_T_LOGGING || bpType == DEBUGGER_BP_T_ONE_SHOT; } bool isMemBP() const { return bpType == DEBUGGER_BP_T_MEMORY_READ || bpType == DEBUGGER_BP_T_MEMORY_WRITE; } DebuggerBreakpoint* next; }; struct DebuggerPatch { uint32 address; sint32 length; std::vector data; std::vector origData; }; struct PPCSnapshot { uint32 gpr[32]; FPR_t fpr[32]; uint8 cr[32]; uint32 spr_lr; }; typedef struct { bool breakOnEntry; // breakpoints std::vector breakpoints; std::vector patches; DebuggerBreakpoint* activeMemoryBreakpoint; // debugging state struct { volatile bool shouldBreak; // debugger window requests a break asap volatile bool isTrapped; // if set, breakpoint is active and stepping through the code is possible uint32 debuggedThreadMPTR; volatile uint32 instructionPointer; PPCInterpreter_t* hCPU; // step control volatile bool stepOver; volatile bool stepInto; volatile bool run; // snapshot of PPC state PPCSnapshot ppcSnapshot; }debugSession; }debuggerState_t; extern debuggerState_t debuggerState; // new API DebuggerBreakpoint* debugger_getFirstBP(uint32 address); void debugger_createCodeBreakpoint(uint32 address, uint8 bpType); void debugger_createExecuteBreakpoint(uint32 address); void debugger_toggleExecuteBreakpoint(uint32 address); // create/remove execute breakpoint void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* bp); void debugger_createMemoryBreakpoint(uint32 address, bool onRead, bool onWrite); void debugger_handleEntryBreakpoint(uint32 address); void debugger_deleteBreakpoint(DebuggerBreakpoint* bp); void debugger_updateExecutionBreakpoint(uint32 address, bool forceRestore = false); void debugger_createPatch(uint32 address, std::span patchData); bool debugger_hasPatch(uint32 address); void debugger_removePatch(uint32 address); void debugger_forceBreak(); // force breakpoint at the next possible instruction bool debugger_isTrapped(); void debugger_resume(); void debugger_enterTW(PPCInterpreter_t* hCPU); void debugger_shouldBreak(PPCInterpreter_t* hCPU); void debugger_addParserSymbols(class ExpressionParser& ep);