From 076280b9bac60db2134623c77f129245d1dea5d0 Mon Sep 17 00:00:00 2001 From: zilmar Date: Fri, 2 Feb 2018 04:28:08 +1100 Subject: [PATCH] [Debugger] Add unaligned write breakpoints --- Source/Project64-core/Debugger.h | 4 ++ .../N64System/Interpreter/InterpreterOps.cpp | 61 ++++++++++++++++++- .../N64System/Interpreter/InterpreterOps.h | 2 + .../Project64-core/Settings/DebugSettings.cpp | 14 +++-- .../Project64-core/Settings/DebugSettings.h | 2 + Source/Project64-core/Settings/Settings.h | 1 + .../Project64-core/Settings/SettingsClass.cpp | 1 + .../UserInterface/Debugger/Breakpoints.cpp | 58 +++++++++++++++++- .../UserInterface/Debugger/Breakpoints.h | 7 ++- .../UserInterface/Debugger/Debugger.cpp | 26 ++++++-- .../UserInterface/Debugger/debugger.h | 4 ++ 11 files changed, 167 insertions(+), 13 deletions(-) diff --git a/Source/Project64-core/Debugger.h b/Source/Project64-core/Debugger.h index bdf4b2e6d..6bb815126 100644 --- a/Source/Project64-core/Debugger.h +++ b/Source/Project64-core/Debugger.h @@ -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; diff --git a/Source/Project64-core/N64System/Interpreter/InterpreterOps.cpp b/Source/Project64-core/N64System/Interpreter/InterpreterOps.cpp index beaf09853..262862d10 100644 --- a/Source/Project64-core/N64System/Interpreter/InterpreterOps.cpp +++ b/Source/Project64-core/N64System/Interpreter/InterpreterOps.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -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 -} \ No newline at end of file +} + +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; +} diff --git a/Source/Project64-core/N64System/Interpreter/InterpreterOps.h b/Source/Project64-core/N64System/Interpreter/InterpreterOps.h index 4cd624e83..353c7dfbb 100644 --- a/Source/Project64-core/N64System/Interpreter/InterpreterOps.h +++ b/Source/Project64-core/N64System/Interpreter/InterpreterOps.h @@ -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]; diff --git a/Source/Project64-core/Settings/DebugSettings.cpp b/Source/Project64-core/Settings/DebugSettings.cpp index bc2ff84c9..adfc93c35 100644 --- a/Source/Project64-core/Settings/DebugSettings.cpp +++ b/Source/Project64-core/Settings/DebugSettings.cpp @@ -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); } \ No newline at end of file diff --git a/Source/Project64-core/Settings/DebugSettings.h b/Source/Project64-core/Settings/DebugSettings.h index ee3299370..204c402f7 100644 --- a/Source/Project64-core/Settings/DebugSettings.h +++ b/Source/Project64-core/Settings/DebugSettings.h @@ -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; diff --git a/Source/Project64-core/Settings/Settings.h b/Source/Project64-core/Settings/Settings.h index 42e27d8ff..d16a4c284 100644 --- a/Source/Project64-core/Settings/Settings.h +++ b/Source/Project64-core/Settings/Settings.h @@ -232,6 +232,7 @@ enum SettingID Debugger_SteppingOps, Debugger_SkipOp, Debugger_HaveExecutionBP, + Debugger_WriteBPExists, Debugger_WaitingForStep, //Trace diff --git a/Source/Project64-core/Settings/SettingsClass.cpp b/Source/Project64-core/Settings/SettingsClass.cpp index 9dbb60ea9..aca495770 100644 --- a/Source/Project64-core/Settings/SettingsClass.cpp +++ b/Source/Project64-core/Settings/SettingsClass.cpp @@ -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)); diff --git a/Source/Project64/UserInterface/Debugger/Breakpoints.cpp b/Source/Project64/UserInterface/Debugger/Breakpoints.cpp index 791c6306a..ba961c8ab 100644 --- a/Source/Project64/UserInterface/Debugger/Breakpoints.cpp +++ b/Source/Project64/UserInterface/Debugger/Breakpoints.cpp @@ -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; -} \ No newline at end of file +} + +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)); + } +} diff --git a/Source/Project64/UserInterface/Debugger/Breakpoints.h b/Source/Project64/UserInterface/Debugger/Breakpoints.h index 72d6c1e8d..1c5d60bb9 100644 --- a/Source/Project64/UserInterface/Debugger/Breakpoints.h +++ b/Source/Project64/UserInterface/Debugger/Breakpoints.h @@ -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; }; \ No newline at end of file diff --git a/Source/Project64/UserInterface/Debugger/Debugger.cpp b/Source/Project64/UserInterface/Debugger/Debugger.cpp index a9239b525..24c575779 100644 --- a/Source/Project64/UserInterface/Debugger/Debugger.cpp +++ b/Source/Project64/UserInterface/Debugger/Debugger.cpp @@ -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; +} + diff --git a/Source/Project64/UserInterface/Debugger/debugger.h b/Source/Project64/UserInterface/Debugger/debugger.h index b904d04c6..373f2cf9f 100644 --- a/Source/Project64/UserInterface/Debugger/debugger.h +++ b/Source/Project64/UserInterface/Debugger/debugger.h @@ -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();