Cemu/src/Cafe/HW/Espresso/Debugger/Debugger.h

126 lines
No EOL
3.6 KiB
C++

#pragma once
#include <set>
#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<uint8> data;
std::vector<uint8> origData;
};
struct PPCSnapshot
{
uint32 gpr[32];
FPR_t fpr[32];
uint8 cr[32];
uint32 spr_lr;
};
typedef struct
{
bool breakOnEntry;
// breakpoints
std::vector<DebuggerBreakpoint*> breakpoints;
std::vector<DebuggerPatch*> 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<uint8> 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);