[Debugger] Add unaligned write breakpoints
This commit is contained in:
parent
deada521bb
commit
076280b9ba
|
@ -26,6 +26,10 @@ __interface CDebugger
|
|||
virtual void FrameDrawn(void) = 0;
|
||||
virtual void WaitForStep(void) = 0;
|
||||
virtual bool ExecutionBP(uint32_t address) = 0;
|
||||
virtual bool WriteBP8(uint32_t address) = 0;
|
||||
virtual bool WriteBP16(uint32_t address) = 0;
|
||||
virtual bool WriteBP32(uint32_t address) = 0;
|
||||
virtual bool WriteBP64(uint32_t address) = 0;
|
||||
|
||||
virtual void CPUStepStarted(void) = 0;
|
||||
virtual void CPUStep(void) = 0;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <Project64-core/N64System/Mips/OpcodeName.h>
|
||||
#include <Project64-core/N64System/Interpreter/InterpreterCPU.h>
|
||||
#include <Project64-core/Logging.h>
|
||||
#include <Project64-core/Debugger.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
|
@ -1237,6 +1238,10 @@ void R4300iOp::LWU()
|
|||
void R4300iOp::SB()
|
||||
{
|
||||
uint32_t Address = _GPR[m_Opcode.base].UW[0] + (int16_t)m_Opcode.offset;
|
||||
if (HaveWriteBP() && g_Debugger->WriteBP8(Address) && MemoryBreakpoint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!g_MMU->SB_VAddr(Address, _GPR[m_Opcode.rt].UB[0]))
|
||||
{
|
||||
if (HaveDebugger())
|
||||
|
@ -1257,6 +1262,10 @@ void R4300iOp::SH()
|
|||
{
|
||||
ADDRESS_ERROR_EXCEPTION(Address, false);
|
||||
}
|
||||
if (HaveWriteBP() && g_Debugger->WriteBP16(Address) && MemoryBreakpoint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!g_MMU->SH_VAddr(Address, _GPR[m_Opcode.rt].UHW[0]))
|
||||
{
|
||||
if (HaveDebugger())
|
||||
|
@ -1275,6 +1284,10 @@ void R4300iOp::SWL()
|
|||
uint32_t Offset, Address, Value;
|
||||
|
||||
Address = _GPR[m_Opcode.base].UW[0] + (int16_t)m_Opcode.offset;
|
||||
if (HaveWriteBP() && g_Debugger->WriteBP32(Address) && MemoryBreakpoint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
Offset = Address & 3;
|
||||
|
||||
if (!g_MMU->LW_VAddr((Address & ~3), Value))
|
||||
|
@ -1313,6 +1326,10 @@ void R4300iOp::SW()
|
|||
{
|
||||
ADDRESS_ERROR_EXCEPTION(Address, false);
|
||||
}
|
||||
if (HaveWriteBP() && g_Debugger->WriteBP32(Address) && MemoryBreakpoint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (GenerateLog())
|
||||
{
|
||||
Log_SW((*_PROGRAM_COUNTER), Address, _GPR[m_Opcode.rt].UW[0]);
|
||||
|
@ -1346,6 +1363,10 @@ void R4300iOp::SDL()
|
|||
uint64_t Value;
|
||||
|
||||
Address = _GPR[m_Opcode.base].UW[0] + (int16_t)m_Opcode.offset;
|
||||
if (HaveWriteBP() && g_Debugger->WriteBP64(Address) && MemoryBreakpoint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
Offset = Address & 7;
|
||||
|
||||
if (!g_MMU->LD_VAddr((Address & ~7), Value))
|
||||
|
@ -1394,6 +1415,10 @@ void R4300iOp::SDR()
|
|||
uint64_t Value;
|
||||
|
||||
Address = _GPR[m_Opcode.base].UW[0] + (int16_t)m_Opcode.offset;
|
||||
if (HaveWriteBP() && g_Debugger->WriteBP64(Address) && MemoryBreakpoint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
Offset = Address & 7;
|
||||
|
||||
if (!g_MMU->LD_VAddr((Address & ~7), Value))
|
||||
|
@ -1430,6 +1455,10 @@ void R4300iOp::SWR()
|
|||
uint32_t Offset, Address, Value;
|
||||
|
||||
Address = _GPR[m_Opcode.base].UW[0] + (int16_t)m_Opcode.offset;
|
||||
if (HaveWriteBP() && g_Debugger->WriteBP32(Address) && MemoryBreakpoint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
Offset = Address & 3;
|
||||
|
||||
if (!g_MMU->LW_VAddr((Address & ~3), Value))
|
||||
|
@ -1518,6 +1547,10 @@ void R4300iOp::SC()
|
|||
{
|
||||
ADDRESS_ERROR_EXCEPTION(Address, false);
|
||||
}
|
||||
if (HaveWriteBP() && g_Debugger->WriteBP32(Address) && MemoryBreakpoint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
Log_SW((*_PROGRAM_COUNTER), Address, _GPR[m_Opcode.rt].UW[0]);
|
||||
if ((*_LLBit) == 1)
|
||||
{
|
||||
|
@ -1590,6 +1623,10 @@ void R4300iOp::SWC1()
|
|||
{
|
||||
ADDRESS_ERROR_EXCEPTION(Address, false);
|
||||
}
|
||||
if (HaveWriteBP() && g_Debugger->WriteBP32(Address) && MemoryBreakpoint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_MMU->SW_VAddr(Address, *(uint32_t *)_FPR_S[m_Opcode.ft]))
|
||||
{
|
||||
|
@ -1609,6 +1646,11 @@ void R4300iOp::SDC1()
|
|||
uint32_t Address = _GPR[m_Opcode.base].UW[0] + (int16_t)m_Opcode.offset;
|
||||
|
||||
TEST_COP1_USABLE_EXCEPTION();
|
||||
if (HaveWriteBP() && g_Debugger->WriteBP64(Address) && MemoryBreakpoint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((Address & 7) != 0)
|
||||
{
|
||||
ADDRESS_ERROR_EXCEPTION(Address, false);
|
||||
|
@ -1633,6 +1675,10 @@ void R4300iOp::SD()
|
|||
{
|
||||
ADDRESS_ERROR_EXCEPTION(Address, false);
|
||||
}
|
||||
if (HaveWriteBP() && g_Debugger->WriteBP64(Address) && MemoryBreakpoint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!g_MMU->SD_VAddr(Address, _GPR[m_Opcode.rt].UDW))
|
||||
{
|
||||
if (HaveDebugger())
|
||||
|
@ -2912,4 +2958,17 @@ void R4300iOp::UnknownOpcode()
|
|||
ExitThread(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool R4300iOp::MemoryBreakpoint()
|
||||
{
|
||||
g_Settings->SaveBool(Debugger_SteppingOps, true);
|
||||
g_Debugger->WaitForStep();
|
||||
if (SkipOp())
|
||||
{
|
||||
// Skip command if instructed by the debugger
|
||||
g_Settings->SaveBool(Debugger_SkipOp, false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -225,6 +225,8 @@ protected:
|
|||
static void COP1_W();
|
||||
static void COP1_L();
|
||||
|
||||
static bool MemoryBreakpoint();
|
||||
|
||||
static Func Jump_Opcode[64];
|
||||
static Func Jump_Special[64];
|
||||
static Func Jump_Regimm[32];
|
||||
|
|
|
@ -25,6 +25,7 @@ bool CDebugSettings::m_bShowTLBMisses = false;
|
|||
bool CDebugSettings::m_bShowDivByZero = false;
|
||||
bool CDebugSettings::m_RecordExecutionTimes = false;
|
||||
bool CDebugSettings::m_HaveExecutionBP = false;
|
||||
bool CDebugSettings::m_HaveWriteBP = false;
|
||||
|
||||
CDebugSettings::CDebugSettings()
|
||||
{
|
||||
|
@ -40,6 +41,7 @@ CDebugSettings::CDebugSettings()
|
|||
g_Settings->RegisterChangeCB(Debugger_SteppingOps, this, (CSettings::SettingChangedFunc)StaticRefreshSettings);
|
||||
g_Settings->RegisterChangeCB(Debugger_SkipOp, this, (CSettings::SettingChangedFunc)StaticRefreshSettings);
|
||||
g_Settings->RegisterChangeCB(Debugger_HaveExecutionBP, this, (CSettings::SettingChangedFunc)StaticRefreshSettings);
|
||||
g_Settings->RegisterChangeCB(Debugger_WriteBPExists, this, (CSettings::SettingChangedFunc)StaticRefreshSettings);
|
||||
g_Settings->RegisterChangeCB(Debugger_WaitingForStep, this, (CSettings::SettingChangedFunc)StaticRefreshSettings);
|
||||
|
||||
RefreshSettings();
|
||||
|
@ -59,6 +61,7 @@ CDebugSettings::~CDebugSettings()
|
|||
g_Settings->UnregisterChangeCB(Debugger_SteppingOps, this, (CSettings::SettingChangedFunc)StaticRefreshSettings);
|
||||
g_Settings->UnregisterChangeCB(Debugger_SkipOp, this, (CSettings::SettingChangedFunc)StaticRefreshSettings);
|
||||
g_Settings->UnregisterChangeCB(Debugger_HaveExecutionBP, this, (CSettings::SettingChangedFunc)StaticRefreshSettings);
|
||||
g_Settings->UnregisterChangeCB(Debugger_WriteBPExists, this, (CSettings::SettingChangedFunc)StaticRefreshSettings);
|
||||
g_Settings->UnregisterChangeCB(Debugger_WaitingForStep, this, (CSettings::SettingChangedFunc)StaticRefreshSettings);
|
||||
}
|
||||
}
|
||||
|
@ -69,11 +72,12 @@ void CDebugSettings::RefreshSettings()
|
|||
m_bRecordRecompilerAsm = m_HaveDebugger && g_Settings->LoadBool(Debugger_RecordRecompilerAsm);
|
||||
m_bShowTLBMisses = m_HaveDebugger && g_Settings->LoadBool(Debugger_ShowTLBMisses);
|
||||
m_bShowDivByZero = m_HaveDebugger && g_Settings->LoadBool(Debugger_ShowDivByZero);
|
||||
m_RecordExecutionTimes = g_Settings->LoadBool(Debugger_RecordExecutionTimes);
|
||||
m_Stepping = g_Settings->LoadBool(Debugger_SteppingOps);
|
||||
m_SkipOp = g_Settings->LoadBool(Debugger_SkipOp);
|
||||
m_RecordExecutionTimes = m_HaveDebugger && g_Settings->LoadBool(Debugger_RecordExecutionTimes);
|
||||
m_Stepping = m_HaveDebugger && g_Settings->LoadBool(Debugger_SteppingOps);
|
||||
m_SkipOp = m_HaveDebugger && g_Settings->LoadBool(Debugger_SkipOp);
|
||||
m_WaitingForStep = g_Settings->LoadBool(Debugger_WaitingForStep);
|
||||
m_HaveExecutionBP = g_Settings->LoadBool(Debugger_HaveExecutionBP);
|
||||
m_HaveExecutionBP = m_HaveDebugger && g_Settings->LoadBool(Debugger_HaveExecutionBP);
|
||||
m_HaveWriteBP = m_HaveDebugger && g_Settings->LoadBool(Debugger_WriteBPExists);
|
||||
|
||||
m_Debugging = m_HaveDebugger && (m_HaveExecutionBP || m_WaitingForStep);
|
||||
m_Debugging = m_HaveDebugger && (m_HaveExecutionBP || m_WaitingForStep || m_HaveWriteBP);
|
||||
}
|
|
@ -28,6 +28,7 @@ public:
|
|||
static inline bool bShowDivByZero(void) { return m_bShowDivByZero; }
|
||||
static inline bool bRecordExecutionTimes(void) { return m_RecordExecutionTimes; }
|
||||
static inline bool HaveExecutionBP(void) { return m_HaveExecutionBP; }
|
||||
static inline bool HaveWriteBP(void) { return m_HaveWriteBP; }
|
||||
|
||||
private:
|
||||
static void StaticRefreshSettings(CDebugSettings * _this)
|
||||
|
@ -47,6 +48,7 @@ private:
|
|||
static bool m_bShowDivByZero;
|
||||
static bool m_RecordExecutionTimes;
|
||||
static bool m_HaveExecutionBP;
|
||||
static bool m_HaveWriteBP;
|
||||
|
||||
static int32_t m_RefCount;
|
||||
static bool m_Registered;
|
||||
|
|
|
@ -232,6 +232,7 @@ enum SettingID
|
|||
Debugger_SteppingOps,
|
||||
Debugger_SkipOp,
|
||||
Debugger_HaveExecutionBP,
|
||||
Debugger_WriteBPExists,
|
||||
Debugger_WaitingForStep,
|
||||
|
||||
//Trace
|
||||
|
|
|
@ -317,6 +317,7 @@ void CSettings::AddHowToHandleSetting(const char * BaseDirectory)
|
|||
AddHandler(Debugger_SteppingOps, new CSettingTypeTempBool(false));
|
||||
AddHandler(Debugger_SkipOp, new CSettingTypeTempBool(false));
|
||||
AddHandler(Debugger_HaveExecutionBP, new CSettingTypeTempBool(false));
|
||||
AddHandler(Debugger_WriteBPExists, new CSettingTypeTempBool(false));
|
||||
AddHandler(Debugger_WaitingForStep, new CSettingTypeTempBool(false));
|
||||
AddHandler(Debugger_DebugLanguage, new CSettingTypeApplication("Debugger", "Debug Language", false));
|
||||
AddHandler(Debugger_ShowDivByZero, new CSettingTypeApplication("Debugger", "Show Div by zero", false));
|
||||
|
|
|
@ -36,6 +36,11 @@ bool CBreakpoints::WBPAdd(uint32_t address)
|
|||
if (!WriteBPExists8(address))
|
||||
{
|
||||
m_WriteMem.insert(breakpoints_t::value_type(address, false));
|
||||
UpdateAlignedWriteBP();
|
||||
if (!HaveWriteBP())
|
||||
{
|
||||
g_Settings->SaveBool(Debugger_WriteBPExists, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -71,6 +76,11 @@ void CBreakpoints::WBPRemove(uint32_t address)
|
|||
if (itr != m_WriteMem.end())
|
||||
{
|
||||
m_WriteMem.erase(itr);
|
||||
UpdateAlignedWriteBP();
|
||||
if (m_Execution.size() == 0)
|
||||
{
|
||||
g_Settings->SaveBool(Debugger_WriteBPExists, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,6 +129,8 @@ void CBreakpoints::RBPClear()
|
|||
void CBreakpoints::WBPClear()
|
||||
{
|
||||
m_WriteMem.clear();
|
||||
UpdateAlignedWriteBP();
|
||||
g_Settings->SaveBool(Debugger_WriteBPExists, false);
|
||||
}
|
||||
|
||||
void CBreakpoints::EBPClear()
|
||||
|
@ -153,6 +165,36 @@ CBreakpoints::BPSTATE CBreakpoints::WriteBPExists8(uint32_t address)
|
|||
return BP_NOT_SET;
|
||||
}
|
||||
|
||||
CBreakpoints::BPSTATE CBreakpoints::WriteBPExists16(uint32_t address)
|
||||
{
|
||||
breakpoints_t::const_iterator itr = m_WriteMem16.find(address);
|
||||
if (itr != m_WriteMem16.end())
|
||||
{
|
||||
return BP_SET;
|
||||
}
|
||||
return BP_NOT_SET;
|
||||
}
|
||||
|
||||
CBreakpoints::BPSTATE CBreakpoints::WriteBPExists32(uint32_t address)
|
||||
{
|
||||
breakpoints_t::const_iterator itr = m_WriteMem16.find(address);
|
||||
if (itr != m_WriteMem16.end())
|
||||
{
|
||||
return BP_SET;
|
||||
}
|
||||
return BP_NOT_SET;
|
||||
}
|
||||
|
||||
CBreakpoints::BPSTATE CBreakpoints::WriteBPExists64(uint32_t address)
|
||||
{
|
||||
breakpoints_t::const_iterator itr = m_WriteMem16.find(address);
|
||||
if (itr != m_WriteMem16.end())
|
||||
{
|
||||
return BP_SET;
|
||||
}
|
||||
return BP_NOT_SET;
|
||||
}
|
||||
|
||||
CBreakpoints::BPSTATE CBreakpoints::ExecutionBPExists(uint32_t address, bool bRemoveTemp)
|
||||
{
|
||||
breakpoints_t::const_iterator itr = m_Execution.find(address);
|
||||
|
@ -169,4 +211,18 @@ CBreakpoints::BPSTATE CBreakpoints::ExecutionBPExists(uint32_t address, bool bRe
|
|||
return BP_SET;
|
||||
}
|
||||
return BP_NOT_SET;
|
||||
}
|
||||
}
|
||||
|
||||
void CBreakpoints::UpdateAlignedWriteBP()
|
||||
{
|
||||
m_WriteMem16.clear();
|
||||
m_WriteMem32.clear();
|
||||
m_WriteMem64.clear();
|
||||
|
||||
for (breakpoints_t::const_iterator itr = m_WriteMem.begin(); itr != m_WriteMem.end(); itr++)
|
||||
{
|
||||
m_WriteMem16.insert(breakpoints_t::value_type((itr->first & ~0x1), false));
|
||||
m_WriteMem32.insert(breakpoints_t::value_type((itr->first & ~0x3), false));
|
||||
m_WriteMem64.insert(breakpoints_t::value_type((itr->first & ~0x7), false));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ public:
|
|||
|
||||
BPSTATE ReadBPExists(uint32_t address);
|
||||
BPSTATE WriteBPExists8(uint32_t address);
|
||||
BPSTATE WriteBPExists16(uint32_t address);
|
||||
BPSTATE WriteBPExists32(uint32_t address);
|
||||
BPSTATE WriteBPExists64(uint32_t address);
|
||||
BPSTATE ExecutionBPExists(uint32_t address, bool bRemoveTemp = false);
|
||||
|
||||
bool RBPAdd(uint32_t address);
|
||||
|
@ -54,7 +57,9 @@ public:
|
|||
void BPClear();
|
||||
|
||||
private:
|
||||
void UpdateAlignedWriteBP(void);
|
||||
|
||||
breakpoints_t m_ReadMem;
|
||||
breakpoints_t m_WriteMem;
|
||||
breakpoints_t m_WriteMem, m_WriteMem16, m_WriteMem32, m_WriteMem64;
|
||||
breakpoints_t m_Execution;
|
||||
};
|
|
@ -414,11 +414,6 @@ void CDebuggerUI::CPUStepStarted()
|
|||
{
|
||||
m_ScriptSystem->HookCPUWrite()->InvokeByParamInRange(memoryAddress);
|
||||
|
||||
if (m_Breakpoints->WriteBPExists8(memoryAddress))
|
||||
{
|
||||
goto breakpoint_hit;
|
||||
}
|
||||
|
||||
// Catch cart -> rdram dma
|
||||
if (memoryAddress == 0xA460000C) // PI_WR_LEN_REG
|
||||
{
|
||||
|
@ -539,3 +534,24 @@ bool CDebuggerUI::ExecutionBP(uint32_t address)
|
|||
{
|
||||
return m_Breakpoints != NULL && m_Breakpoints->ExecutionBPExists(address, true) != CBreakpoints::BP_NOT_SET;
|
||||
}
|
||||
|
||||
bool CDebuggerUI::WriteBP8(uint32_t address)
|
||||
{
|
||||
return m_Breakpoints != NULL && m_Breakpoints->WriteBPExists8(address) != CBreakpoints::BP_NOT_SET;
|
||||
}
|
||||
|
||||
bool CDebuggerUI::WriteBP16(uint32_t address)
|
||||
{
|
||||
return m_Breakpoints != NULL && m_Breakpoints->WriteBPExists16(address) != CBreakpoints::BP_NOT_SET;
|
||||
}
|
||||
|
||||
bool CDebuggerUI::WriteBP32(uint32_t address)
|
||||
{
|
||||
return m_Breakpoints != NULL && m_Breakpoints->WriteBPExists32(address) != CBreakpoints::BP_NOT_SET;
|
||||
}
|
||||
|
||||
bool CDebuggerUI::WriteBP64(uint32_t address)
|
||||
{
|
||||
return m_Breakpoints != NULL && m_Breakpoints->WriteBPExists64(address) != CBreakpoints::BP_NOT_SET;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,10 @@ public:
|
|||
void OpenDMALogWindow(void);
|
||||
|
||||
bool ExecutionBP(uint32_t address);
|
||||
bool WriteBP8(uint32_t address);
|
||||
bool WriteBP16(uint32_t address);
|
||||
bool WriteBP32(uint32_t address);
|
||||
bool WriteBP64(uint32_t address);
|
||||
void WaitForStep(void);
|
||||
|
||||
CBreakpoints* Breakpoints();
|
||||
|
|
Loading…
Reference in New Issue