diff --git a/Core/Debugger/Breakpoints.cpp b/Core/Debugger/Breakpoints.cpp index 3dce267dbb33..a850df55db1a 100644 --- a/Core/Debugger/Breakpoints.cpp +++ b/Core/Debugger/Breakpoints.cpp @@ -23,6 +23,7 @@ #include "Core/Debugger/SymbolMap.h" #include "Core/Host.h" #include "Core/MIPS/MIPSAnalyst.h" +#include "Core/MIPS/MIPSDebugInterface.h" #include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/CoreTiming.h" @@ -37,13 +38,19 @@ MemCheck::MemCheck() numHits = 0; } -void MemCheck::Log(u32 addr, bool write, int size, u32 pc) -{ - if (result & MEMCHECK_LOG) - NOTICE_LOG(MEMMAP, "CHK %s%i at %08x (%s), PC=%08x (%s)", write ? "Write" : "Read", size * 8, addr, g_symbolMap->GetDescription(addr).c_str(), pc, g_symbolMap->GetDescription(pc).c_str()); +void MemCheck::Log(u32 addr, bool write, int size, u32 pc) { + if (result & BREAK_ACTION_LOG) { + if (logFormat.empty()) { + NOTICE_LOG(MEMMAP, "CHK %s%i at %08x (%s), PC=%08x (%s)", write ? "Write" : "Read", size * 8, addr, g_symbolMap->GetDescription(addr).c_str(), pc, g_symbolMap->GetDescription(pc).c_str()); + } else { + std::string formatted; + CBreakPoints::EvaluateLogFormat(currentDebugMIPS, logFormat, formatted); + NOTICE_LOG(MEMMAP, "CHK %s%i at %08x: %s", write ? "Write" : "Read", size * 8, addr, formatted.c_str()); + } + } } -void MemCheck::Action(u32 addr, bool write, int size, u32 pc) +BreakAction MemCheck::Action(u32 addr, bool write, int size, u32 pc) { int mask = write ? MEMCHECK_WRITE : MEMCHECK_READ; if (cond & mask) @@ -51,12 +58,16 @@ void MemCheck::Action(u32 addr, bool write, int size, u32 pc) ++numHits; Log(addr, write, size, pc); - if (result & MEMCHECK_BREAK) + if (result & BREAK_ACTION_PAUSE) { Core_EnableStepping(true); host->SetDebugMode(true); } + + return result; } + + return BREAK_ACTION_IGNORE; } void MemCheck::JitBefore(u32 addr, bool write, int size, u32 pc) @@ -93,7 +104,7 @@ void MemCheck::JitCleanup() } // Resume if it should not have gone to stepping, or if it did not change. - if ((!(result & MEMCHECK_BREAK) || !changed) && coreState == CORE_STEPPING) + if ((!(result & BREAK_ACTION_PAUSE) || !changed) && coreState == CORE_STEPPING) { CBreakPoints::SetSkipFirst(lastPC); Core_EnableStepping(false); @@ -110,7 +121,7 @@ size_t CBreakPoints::FindBreakpoint(u32 addr, bool matchTemp, bool temp) const auto &bp = breakPoints_[i]; if (bp.addr == addr && (!matchTemp || bp.temporary == temp)) { - if (bp.enabled) + if (bp.IsEnabled()) return i; // Hold out until the first enabled one. if (found == INVALID_BREAKPOINT) @@ -135,14 +146,15 @@ size_t CBreakPoints::FindMemCheck(u32 start, u32 end) bool CBreakPoints::IsAddressBreakPoint(u32 addr) { size_t bp = FindBreakpoint(addr); - return bp != INVALID_BREAKPOINT && breakPoints_[bp].enabled; + return bp != INVALID_BREAKPOINT && breakPoints_[bp].result != BREAK_ACTION_IGNORE; } bool CBreakPoints::IsAddressBreakPoint(u32 addr, bool* enabled) { size_t bp = FindBreakpoint(addr); if (bp == INVALID_BREAKPOINT) return false; - if (enabled != NULL) *enabled = breakPoints_[bp].enabled; + if (enabled != nullptr) + *enabled = breakPoints_[bp].IsEnabled(); return true; } @@ -170,16 +182,16 @@ void CBreakPoints::AddBreakPoint(u32 addr, bool temp) if (bp == INVALID_BREAKPOINT) { BreakPoint pt; - pt.enabled = true; + pt.result |= BREAK_ACTION_PAUSE; pt.temporary = temp; pt.addr = addr; breakPoints_.push_back(pt); Update(addr); } - else if (!breakPoints_[bp].enabled) + else if (!breakPoints_[bp].IsEnabled()) { - breakPoints_[bp].enabled = true; + breakPoints_[bp].result |= BREAK_ACTION_PAUSE; breakPoints_[bp].hasCond = false; Update(addr); } @@ -206,7 +218,20 @@ void CBreakPoints::ChangeBreakPoint(u32 addr, bool status) size_t bp = FindBreakpoint(addr); if (bp != INVALID_BREAKPOINT) { - breakPoints_[bp].enabled = status; + if (status) + breakPoints_[bp].result |= BREAK_ACTION_PAUSE; + else + breakPoints_[bp].result = BreakAction(breakPoints_[bp].result & ~BREAK_ACTION_PAUSE); + Update(addr); + } +} + +void CBreakPoints::ChangeBreakPoint(u32 addr, BreakAction result) +{ + size_t bp = FindBreakpoint(addr); + if (bp != INVALID_BREAKPOINT) + { + breakPoints_[bp].result = result; Update(addr); } } @@ -246,7 +271,7 @@ void CBreakPoints::ChangeBreakPointAddCond(u32 addr, const BreakPointCond &cond) { breakPoints_[bp].hasCond = true; breakPoints_[bp].cond = cond; - Update(); + Update(addr); } } @@ -256,7 +281,7 @@ void CBreakPoints::ChangeBreakPointRemoveCond(u32 addr) if (bp != INVALID_BREAKPOINT) { breakPoints_[bp].hasCond = false; - Update(); + Update(addr); } } @@ -268,7 +293,45 @@ BreakPointCond *CBreakPoints::GetBreakPointCondition(u32 addr) return NULL; } -void CBreakPoints::AddMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result) +void CBreakPoints::ChangeBreakPointLogFormat(u32 addr, const std::string &fmt) { + size_t bp = FindBreakpoint(addr, true, false); + if (bp != INVALID_BREAKPOINT) { + breakPoints_[bp].logFormat = fmt; + Update(addr); + } +} + +BreakAction CBreakPoints::ExecBreakPoint(u32 addr) { + size_t bp = FindBreakpoint(addr, false); + if (bp != INVALID_BREAKPOINT) { + if (breakPoints_[bp].hasCond) { + // Evaluate the breakpoint and abort if necessary. + auto cond = CBreakPoints::GetBreakPointCondition(currentMIPS->pc); + if (cond && !cond->Evaluate()) + return BREAK_ACTION_IGNORE; + } + + if (breakPoints_[bp].result & BREAK_ACTION_LOG) { + if (breakPoints_[bp].logFormat.empty()) { + NOTICE_LOG(JIT, "BKP PC=%08x (%s)", addr, g_symbolMap->GetDescription(addr).c_str()); + } else { + std::string formatted; + CBreakPoints::EvaluateLogFormat(currentDebugMIPS, breakPoints_[bp].logFormat, formatted); + NOTICE_LOG(JIT, "BKP PC=%08x: %s", addr, formatted.c_str()); + } + } + if (breakPoints_[bp].result & BREAK_ACTION_PAUSE) { + Core_EnableStepping(true); + host->SetDebugMode(true); + } + + return breakPoints_[bp].result; + } + + return BREAK_ACTION_IGNORE; +} + +void CBreakPoints::AddMemCheck(u32 start, u32 end, MemCheckCondition cond, BreakAction result) { // This will ruin any pending memchecks. cleanupMemChecks_.clear(); @@ -288,7 +351,7 @@ void CBreakPoints::AddMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCh else { memChecks_[mc].cond = (MemCheckCondition)(memChecks_[mc].cond | cond); - memChecks_[mc].result = (MemCheckResult)(memChecks_[mc].result | result); + memChecks_[mc].result = (BreakAction)(memChecks_[mc].result | result); Update(); } } @@ -306,7 +369,7 @@ void CBreakPoints::RemoveMemCheck(u32 start, u32 end) } } -void CBreakPoints::ChangeMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result) +void CBreakPoints::ChangeMemCheck(u32 start, u32 end, MemCheckCondition cond, BreakAction result) { size_t mc = FindMemCheck(start, end); if (mc != INVALID_MEMCHECK) @@ -329,6 +392,14 @@ void CBreakPoints::ClearAllMemChecks() } } +void CBreakPoints::ChangeMemCheckLogFormat(u32 start, u32 end, const std::string &fmt) { + size_t mc = FindMemCheck(start, end); + if (mc != INVALID_MEMCHECK) { + memChecks_[mc].logFormat = fmt; + Update(); + } +} + static inline u32 NotCached(u32 val) { // Remove the cached part of the address. @@ -357,14 +428,15 @@ MemCheck *CBreakPoints::GetMemCheck(u32 address, int size) return 0; } -void CBreakPoints::ExecMemCheck(u32 address, bool write, int size, u32 pc) +BreakAction CBreakPoints::ExecMemCheck(u32 address, bool write, int size, u32 pc) { auto check = GetMemCheck(address, size); if (check) - check->Action(address, write, size, pc); + return check->Action(address, write, size, pc); + return BREAK_ACTION_IGNORE; } -void CBreakPoints::ExecOpMemCheck(u32 address, u32 pc) +BreakAction CBreakPoints::ExecOpMemCheck(u32 address, u32 pc) { // Note: currently, we don't check "on changed" for HLE (ExecMemCheck.) // We'd need to more carefully specify memory changes in HLE for that. @@ -381,12 +453,13 @@ void CBreakPoints::ExecOpMemCheck(u32 address, u32 pc) int mask = MEMCHECK_WRITE | MEMCHECK_WRITE_ONCHANGE; if (write && (check->cond & mask) == mask) { if (MIPSAnalyst::OpWouldChangeMemory(pc, address, size)) { - check->Action(address, write, size, pc); + return check->Action(address, write, size, pc); } } else { - check->Action(address, write, size, pc); + return check->Action(address, write, size, pc); } } + return BREAK_ACTION_IGNORE; } void CBreakPoints::ExecMemCheckJitBefore(u32 address, bool write, int size, u32 pc) @@ -476,3 +549,56 @@ void CBreakPoints::Update(u32 addr) // Redraw in order to show the breakpoint. host->UpdateDisassembly(); } + +bool CBreakPoints::ValidateLogFormat(DebugInterface *cpu, const std::string &fmt) { + std::string ignore; + return EvaluateLogFormat(cpu, fmt, ignore); +} + +bool CBreakPoints::EvaluateLogFormat(DebugInterface *cpu, const std::string &fmt, std::string &result) { + PostfixExpression exp; + result.clear(); + + size_t pos = 0; + while (pos < fmt.size()) { + size_t next = fmt.find_first_of("{", pos); + if (next == fmt.npos) { + // End of the string. + result += fmt.substr(pos); + break; + } + if (next != pos) { + result += fmt.substr(pos, next - pos); + pos = next; + } + + size_t end = fmt.find_first_of("}", next + 1); + if (end == fmt.npos) { + // Invalid: every expression needs a { and a }. + return false; + } + + std::string expression = fmt.substr(next + 1, end - next - 1); + if (expression.empty()) { + result += "{}"; + } else { + if (!cpu->initExpression(expression.c_str(), exp)) { + return false; + } + + u32 expResult; + char resultString[32]; + if (!cpu->parseExpression(exp, expResult)) { + return false; + } + + snprintf(resultString, 32, "%08x", expResult); + result += resultString; + } + + // Skip the }. + pos = end + 1; + } + + return true; +} diff --git a/Core/Debugger/Breakpoints.h b/Core/Debugger/Breakpoints.h index afee9495eff0..934667914aff 100644 --- a/Core/Debugger/Breakpoints.h +++ b/Core/Debugger/Breakpoints.h @@ -21,15 +21,30 @@ #include "Core/Debugger/DebugInterface.h" +enum BreakAction +{ + BREAK_ACTION_IGNORE = 0x00, + BREAK_ACTION_LOG = 0x01, + BREAK_ACTION_PAUSE = 0x02, +}; + +static inline BreakAction &operator |= (BreakAction &lhs, const BreakAction &rhs) { + lhs = BreakAction(lhs | rhs); + return lhs; +} + +static inline BreakAction operator | (const BreakAction &lhs, const BreakAction &rhs) { + return BreakAction((u32)lhs | (u32)rhs); +} + struct BreakPointCond { DebugInterface *debug; PostfixExpression expression; - char expressionString[128]; + std::string expressionString; - BreakPointCond() : debug(NULL) + BreakPointCond() : debug(nullptr) { - expressionString[0] = '\0'; } u32 Evaluate() @@ -45,12 +60,18 @@ struct BreakPoint BreakPoint() : hasCond(false) {} u32 addr; - bool enabled; bool temporary; + BreakAction result; + std::string logFormat; + bool hasCond; BreakPointCond cond; + bool IsEnabled() const { + return (result & BREAK_ACTION_PAUSE) != 0; + } + bool operator == (const BreakPoint &other) const { return addr == other.addr; } @@ -68,15 +89,6 @@ enum MemCheckCondition MEMCHECK_READWRITE = 0x03, }; -enum MemCheckResult -{ - MEMCHECK_IGNORE = 0x00, - MEMCHECK_LOG = 0x01, - MEMCHECK_BREAK = 0x02, - - MEMCHECK_BOTH = 0x03, -}; - struct MemCheck { MemCheck(); @@ -84,7 +96,8 @@ struct MemCheck u32 end; MemCheckCondition cond; - MemCheckResult result; + BreakAction result; + std::string logFormat; u32 numHits; @@ -92,12 +105,16 @@ struct MemCheck u32 lastAddr; int lastSize; - void Action(u32 addr, bool write, int size, u32 pc); + BreakAction Action(u32 addr, bool write, int size, u32 pc); void JitBefore(u32 addr, bool write, int size, u32 pc); void JitCleanup(); void Log(u32 addr, bool write, int size, u32 pc); + bool IsEnabled() const { + return (result & BREAK_ACTION_PAUSE) != 0; + } + bool operator == (const MemCheck &other) const { return start == other.start && end == other.end; } @@ -119,6 +136,7 @@ class CBreakPoints static void AddBreakPoint(u32 addr, bool temp = false); static void RemoveBreakPoint(u32 addr); static void ChangeBreakPoint(u32 addr, bool enable); + static void ChangeBreakPoint(u32 addr, BreakAction result); static void ClearAllBreakPoints(); static void ClearTemporaryBreakPoints(); @@ -127,14 +145,20 @@ class CBreakPoints static void ChangeBreakPointRemoveCond(u32 addr); static BreakPointCond *GetBreakPointCondition(u32 addr); - static void AddMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result); + static void ChangeBreakPointLogFormat(u32 addr, const std::string &fmt); + + static BreakAction ExecBreakPoint(u32 addr); + + static void AddMemCheck(u32 start, u32 end, MemCheckCondition cond, BreakAction result); static void RemoveMemCheck(u32 start, u32 end); - static void ChangeMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result); + static void ChangeMemCheck(u32 start, u32 end, MemCheckCondition cond, BreakAction result); static void ClearAllMemChecks(); + static void ChangeMemCheckLogFormat(u32 start, u32 end, const std::string &fmt); + static MemCheck *GetMemCheck(u32 address, int size); - static void ExecMemCheck(u32 address, bool write, int size, u32 pc); - static void ExecOpMemCheck(u32 address, u32 pc); + static BreakAction ExecMemCheck(u32 address, bool write, int size, u32 pc); + static BreakAction ExecOpMemCheck(u32 address, u32 pc); // Executes memchecks but used by the jit. Cleanup finalizes after jit is done. static void ExecMemCheckJitBefore(u32 address, bool write, int size, u32 pc); @@ -153,6 +177,9 @@ class CBreakPoints static void Update(u32 addr = 0); + static bool ValidateLogFormat(DebugInterface *cpu, const std::string &fmt); + static bool EvaluateLogFormat(DebugInterface *cpu, const std::string &fmt, std::string &result); + private: static size_t FindBreakpoint(u32 addr, bool matchTemp = false, bool temp = false); // Finds exactly, not using a range check. diff --git a/Core/MIPS/IR/IRInterpreter.cpp b/Core/MIPS/IR/IRInterpreter.cpp index aca01aaee834..74e8c9892568 100644 --- a/Core/MIPS/IR/IRInterpreter.cpp +++ b/Core/MIPS/IR/IRInterpreter.cpp @@ -37,14 +37,8 @@ u32 RunBreakpoint(u32 pc) { if (CBreakPoints::CheckSkipFirst() == pc) return 0; - auto cond = CBreakPoints::GetBreakPointCondition(pc); - if (cond && !cond->Evaluate()) - return 0; - - Core_EnableStepping(true); - host->SetDebugMode(true); - - return 1; + CBreakPoints::ExecBreakPoint(currentMIPS->pc); + return coreState != CORE_RUNNING ? 1 : 0; } u32 RunMemCheck(u32 pc, u32 addr) { diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 4bfce6814e85..952da9627ac2 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -73,13 +73,10 @@ u32 JitBreakpoint() if (CBreakPoints::CheckSkipFirst() == currentMIPS->pc) return 0; - auto cond = CBreakPoints::GetBreakPointCondition(currentMIPS->pc); - if (cond && !cond->Evaluate()) + BreakAction result = CBreakPoints::ExecBreakPoint(currentMIPS->pc); + if ((result & BREAK_ACTION_PAUSE) == 0) return 0; - Core_EnableStepping(true); - host->SetDebugMode(true); - // There's probably a better place for this. if (USE_JIT_MISSMAP) { std::map notJitSorted; diff --git a/Windows/Debugger/BreakpointWindow.cpp b/Windows/Debugger/BreakpointWindow.cpp index 6f1e920a15f4..7c17fb64d515 100644 --- a/Windows/Debugger/BreakpointWindow.cpp +++ b/Windows/Debugger/BreakpointWindow.cpp @@ -1,6 +1,7 @@ #include #include "base/compat.h" +#include "util/text/utf8.h" #include "BreakpointWindow.h" #include "../resource.h" @@ -28,8 +29,7 @@ INT_PTR CALLBACK BreakpointWindow::dlgFunc(HWND hwnd, UINT iMsg, WPARAM wParam, EnableWindow(GetDlgItem(hwnd,IDC_BREAKPOINT_ONCHANGE),bp->memory); EnableWindow(GetDlgItem(hwnd,IDC_BREAKPOINT_SIZE),bp->memory); EnableWindow(GetDlgItem(hwnd,IDC_BREAKPOINT_CONDITION),!bp->memory); - EnableWindow(GetDlgItem(hwnd,IDC_BREAKPOINT_LOG),bp->memory); - + EnableWindow(GetDlgItem(hwnd,IDC_BREAKPOINT_LOG_FORMAT), bp->log); if (bp->address != -1) { @@ -38,9 +38,10 @@ INT_PTR CALLBACK BreakpointWindow::dlgFunc(HWND hwnd, UINT iMsg, WPARAM wParam, } snprintf(str, sizeof(str), "0x%08X", bp->size); - SetWindowTextA(GetDlgItem(hwnd,IDC_BREAKPOINT_SIZE),str); + SetWindowTextA(GetDlgItem(hwnd, IDC_BREAKPOINT_SIZE),str); - SetWindowTextA(GetDlgItem(hwnd,IDC_BREAKPOINT_CONDITION),bp->condition); + SetWindowTextW(GetDlgItem(hwnd, IDC_BREAKPOINT_CONDITION), ConvertUTF8ToWString(bp->condition).c_str()); + SetWindowTextW(GetDlgItem(hwnd, IDC_BREAKPOINT_LOG_FORMAT), ConvertUTF8ToWString(bp->logFormat).c_str()); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) @@ -55,7 +56,6 @@ INT_PTR CALLBACK BreakpointWindow::dlgFunc(HWND hwnd, UINT iMsg, WPARAM wParam, EnableWindow(GetDlgItem(hwnd,IDC_BREAKPOINT_ONCHANGE),bp->memory); EnableWindow(GetDlgItem(hwnd,IDC_BREAKPOINT_SIZE),bp->memory); EnableWindow(GetDlgItem(hwnd,IDC_BREAKPOINT_CONDITION),!bp->memory); - EnableWindow(GetDlgItem(hwnd,IDC_BREAKPOINT_LOG),bp->memory); break; } break; @@ -69,7 +69,14 @@ INT_PTR CALLBACK BreakpointWindow::dlgFunc(HWND hwnd, UINT iMsg, WPARAM wParam, EnableWindow(GetDlgItem(hwnd,IDC_BREAKPOINT_ONCHANGE),bp->memory); EnableWindow(GetDlgItem(hwnd,IDC_BREAKPOINT_SIZE),bp->memory); EnableWindow(GetDlgItem(hwnd,IDC_BREAKPOINT_CONDITION),!bp->memory); - EnableWindow(GetDlgItem(hwnd,IDC_BREAKPOINT_LOG),bp->memory); + break; + } + break; + case IDC_BREAKPOINT_LOG: + switch (HIWORD(wParam)) + { + case BN_CLICKED: + EnableWindow(GetDlgItem(hwnd, IDC_BREAKPOINT_LOG_FORMAT), bp->GetCheckState(hwnd, IDC_BREAKPOINT_LOG)); break; } break; @@ -116,12 +123,12 @@ bool BreakpointWindow::fetchDialogData(HWND hwnd) char str[256],errorMessage[512]; PostfixExpression exp; - memory = SendMessage(GetDlgItem(hwnd,IDC_BREAKPOINT_MEMORY),BM_GETCHECK,0,0) != 0; - read = SendMessage(GetDlgItem(hwnd,IDC_BREAKPOINT_READ),BM_GETCHECK,0,0) != 0; - write = SendMessage(GetDlgItem(hwnd,IDC_BREAKPOINT_WRITE),BM_GETCHECK,0,0) != 0; - enabled = SendMessage(GetDlgItem(hwnd,IDC_BREAKPOINT_ENABLED),BM_GETCHECK,0,0) != 0; - log = SendMessage(GetDlgItem(hwnd,IDC_BREAKPOINT_LOG),BM_GETCHECK,0,0) != 0; - onChange = SendMessage(GetDlgItem(hwnd,IDC_BREAKPOINT_ONCHANGE),BM_GETCHECK,0,0) != 0; + memory = GetCheckState(hwnd, IDC_BREAKPOINT_MEMORY); + read = GetCheckState(hwnd, IDC_BREAKPOINT_READ); + write = GetCheckState(hwnd, IDC_BREAKPOINT_WRITE); + enabled = GetCheckState(hwnd, IDC_BREAKPOINT_ENABLED); + log = GetCheckState(hwnd, IDC_BREAKPOINT_LOG); + onChange = GetCheckState(hwnd, IDC_BREAKPOINT_ONCHANGE); // parse address GetWindowTextA(GetDlgItem(hwnd,IDC_BREAKPOINT_ADDRESS),str,256); @@ -159,11 +166,13 @@ bool BreakpointWindow::fetchDialogData(HWND hwnd) } // condition - GetWindowTextA(GetDlgItem(hwnd,IDC_BREAKPOINT_CONDITION),condition,128); + wchar_t tempCond[512]; + GetWindowTextW(GetDlgItem(hwnd, IDC_BREAKPOINT_CONDITION), tempCond, 512); + condition = ConvertWStringToUTF8(tempCond); compiledCondition.clear(); - if (condition[0] != 0) + if (!condition.empty()) { - if (cpu->initExpression(condition,compiledCondition) == false) + if (cpu->initExpression(condition.c_str(), compiledCondition) == false) { snprintf(errorMessage, sizeof(errorMessage), "Invalid expression \"%s\".",str); MessageBoxA(hwnd,errorMessage,"Error",MB_OK); @@ -171,9 +180,22 @@ bool BreakpointWindow::fetchDialogData(HWND hwnd) } } + wchar_t tempLogFormat[512]; + GetWindowTextW(GetDlgItem(hwnd, IDC_BREAKPOINT_LOG_FORMAT), tempLogFormat, 512); + logFormat = ConvertWStringToUTF8(tempLogFormat); + if (!CBreakPoints::ValidateLogFormat(cpu, logFormat)) { + snprintf(errorMessage, sizeof(errorMessage), "Invalid log format (example: \"{a1}\")."); + MessageBoxA(hwnd, errorMessage, "Error", MB_OK); + return false; + } + return true; } +bool BreakpointWindow::GetCheckState(HWND hwnd, int dlgItem) { + return SendMessage(GetDlgItem(hwnd, dlgItem), BM_GETCHECK, 0, 0) != 0; +} + bool BreakpointWindow::exec() { bp = this; @@ -183,6 +205,12 @@ bool BreakpointWindow::exec() void BreakpointWindow::addBreakpoint() { + BreakAction result = BREAK_ACTION_IGNORE; + if (log) + result |= BREAK_ACTION_LOG; + if (enabled) + result |= BREAK_ACTION_PAUSE; + if (memory) { // add memcheck @@ -194,30 +222,23 @@ void BreakpointWindow::addBreakpoint() if (onChange) cond |= MEMCHECK_WRITE_ONCHANGE; - MemCheckResult result; - if (log && enabled) result = MEMCHECK_BOTH; - else if (log) result = MEMCHECK_LOG; - else if (enabled) result = MEMCHECK_BREAK; - else result = MEMCHECK_IGNORE; - CBreakPoints::AddMemCheck(address, address + size, (MemCheckCondition)cond, result); + CBreakPoints::ChangeMemCheckLogFormat(address, address + size, logFormat); } else { // add breakpoint CBreakPoints::AddBreakPoint(address,false); - if (condition[0] != 0) + if (!condition.empty()) { BreakPointCond cond; cond.debug = cpu; - strcpy(cond.expressionString,condition); + cond.expressionString = condition; cond.expression = compiledCondition; CBreakPoints::ChangeBreakPointAddCond(address,cond); } - if (enabled == false) - { - CBreakPoints::ChangeBreakPoint(address,false); - } + CBreakPoints::ChangeBreakPoint(address, result); + CBreakPoints::ChangeBreakPointLogFormat(address, logFormat); } } @@ -229,42 +250,31 @@ void BreakpointWindow::loadFromMemcheck(MemCheck& memcheck) write = (memcheck.cond & MEMCHECK_WRITE) != 0; onChange = (memcheck.cond & MEMCHECK_WRITE_ONCHANGE) != 0; - switch (memcheck.result) - { - case MEMCHECK_BOTH: - log = enabled = true; - break; - case MEMCHECK_LOG: - log = true; - enabled = false; - break; - case MEMCHECK_BREAK: - log = false; - enabled = true; - break; - case MEMCHECK_IGNORE: - log = enabled = false; - break; - } + log = (memcheck.result & BREAK_ACTION_LOG) != 0; + enabled = (memcheck.result & BREAK_ACTION_PAUSE) != 0; address = memcheck.start; size = memcheck.end-address; + + logFormat = memcheck.logFormat; } void BreakpointWindow::loadFromBreakpoint(BreakPoint& breakpoint) { memory = false; - enabled = breakpoint.enabled; + log = (breakpoint.result & BREAK_ACTION_LOG) != 0; + enabled = (breakpoint.result & BREAK_ACTION_PAUSE) != 0; address = breakpoint.addr; size = 1; - if (breakpoint.hasCond) - { - strcpy(condition,breakpoint.cond.expressionString); + if (breakpoint.hasCond) { + condition = breakpoint.cond.expressionString; } else { - condition[0] = 0; + condition.clear(); } + + logFormat = breakpoint.logFormat; } void BreakpointWindow::initBreakpoint(u32 _address) @@ -273,5 +283,5 @@ void BreakpointWindow::initBreakpoint(u32 _address) enabled = true; address = _address; size = 1; - condition[0] = 0; + condition.clear(); } diff --git a/Windows/Debugger/BreakpointWindow.h b/Windows/Debugger/BreakpointWindow.h index 31a80470b579..0a79c79d6fef 100644 --- a/Windows/Debugger/BreakpointWindow.h +++ b/Windows/Debugger/BreakpointWindow.h @@ -1,4 +1,5 @@ #pragma once +#include #include "Common/CommonWindows.h" #include "Common/CommonTypes.h" #include "Core/Debugger/DebugInterface.h" @@ -17,11 +18,14 @@ class BreakpointWindow bool onChange; u32 address; u32 size; - char condition[128]; + std::string condition; + std::string logFormat; PostfixExpression compiledCondition; static BreakpointWindow* bp; bool fetchDialogData(HWND hwnd); + bool GetCheckState(HWND hwnd, int dlgItem); + public: BreakpointWindow(HWND parent, DebugInterface* cpu): cpu(cpu) { @@ -32,7 +36,6 @@ class BreakpointWindow enabled = log = true; address = -1; size = 1; - condition[0] = 0; }; @@ -44,4 +47,4 @@ class BreakpointWindow void loadFromMemcheck(MemCheck& memcheck); void loadFromBreakpoint(BreakPoint& memcheck); void initBreakpoint(u32 address); -}; \ No newline at end of file +}; diff --git a/Windows/Debugger/CtrlDisAsmView.cpp b/Windows/Debugger/CtrlDisAsmView.cpp index 7da836ab7e12..b0afc5f9a5f1 100644 --- a/Windows/Debugger/CtrlDisAsmView.cpp +++ b/Windows/Debugger/CtrlDisAsmView.cpp @@ -1,4 +1,4 @@ -// NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003. +// NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003. #include "Windows/resource.h" #include "Core/MemMap.h" @@ -550,7 +550,7 @@ void CtrlDisAsmView::onPaint(WPARAM wParam, LPARAM lParam) if (isInInterval(address,line.totalSize,debugger->getPC())) { - TextOut(hdc,pixelPositions.opcodeStart-8,rowY1,L"■",1); + TextOut(hdc,pixelPositions.opcodeStart-8,rowY1,L"\x25A0",1); } // display whether the condition of a branch is met @@ -834,22 +834,18 @@ void CtrlDisAsmView::redraw() void CtrlDisAsmView::toggleBreakpoint(bool toggleEnabled) { bool enabled; - if (CBreakPoints::IsAddressBreakPoint(curAddress,&enabled)) - { - if (!enabled) - { + if (CBreakPoints::IsAddressBreakPoint(curAddress, &enabled)) { + if (!enabled) { // enable disabled breakpoints - CBreakPoints::ChangeBreakPoint(curAddress,true); - } else if (!toggleEnabled && CBreakPoints::GetBreakPointCondition(curAddress) != NULL) - { + CBreakPoints::ChangeBreakPoint(curAddress, true); + } else if (!toggleEnabled && CBreakPoints::GetBreakPointCondition(curAddress) != nullptr) { // don't just delete a breakpoint with a custom condition int ret = MessageBox(wnd,L"This breakpoint has a custom condition.\nDo you want to remove it?",L"Confirmation",MB_YESNO); if (ret == IDYES) CBreakPoints::RemoveBreakPoint(curAddress); - } else if (toggleEnabled) - { + } else if (toggleEnabled) { // disable breakpoint - CBreakPoints::ChangeBreakPoint(curAddress,false); + CBreakPoints::ChangeBreakPoint(curAddress, false); } else { // otherwise just remove breakpoint CBreakPoints::RemoveBreakPoint(curAddress); diff --git a/Windows/Debugger/Debugger_Lists.cpp b/Windows/Debugger/Debugger_Lists.cpp index 04f71ad6da3e..7d08b09ee604 100644 --- a/Windows/Debugger/Debugger_Lists.cpp +++ b/Windows/Debugger/Debugger_Lists.cpp @@ -324,9 +324,9 @@ void CtrlBreakpointList::reloadBreakpoints() continue; if (isMemory) - SetCheckState(i,(displayedMemChecks_[index].result & MEMCHECK_BREAK) != 0); + SetCheckState(i, displayedMemChecks_[index].IsEnabled()); else - SetCheckState(i,displayedBreakPoints_[index].enabled); + SetCheckState(i, displayedBreakPoints_[index].IsEnabled()); } } @@ -365,10 +365,10 @@ void CtrlBreakpointList::toggleEnabled(int itemIndex) if (isMemory) { MemCheck mcPrev = displayedMemChecks_[index]; - CBreakPoints::ChangeMemCheck(mcPrev.start, mcPrev.end, mcPrev.cond, MemCheckResult(mcPrev.result ^ MEMCHECK_BREAK)); + CBreakPoints::ChangeMemCheck(mcPrev.start, mcPrev.end, mcPrev.cond, BreakAction(mcPrev.result ^ BREAK_ACTION_PAUSE)); } else { BreakPoint bpPrev = displayedBreakPoints_[index]; - CBreakPoints::ChangeBreakPoint(bpPrev.addr, !bpPrev.enabled); + CBreakPoints::ChangeBreakPoint(bpPrev.addr, BreakAction(bpPrev.result ^ BREAK_ACTION_PAUSE)); } } @@ -605,18 +605,18 @@ void CtrlBreakpointList::showBreakpointMenu(int itemIndex, const POINT &pt) HMENU subMenu = GetSubMenu(g_hPopupMenus, POPUP_SUBMENU_ID_BREAKPOINTLIST); if (isMemory) { - CheckMenuItem(subMenu, ID_DISASM_DISABLEBREAKPOINT, MF_BYCOMMAND | (mcPrev.result & MEMCHECK_BREAK ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(subMenu, ID_DISASM_DISABLEBREAKPOINT, MF_BYCOMMAND | (mcPrev.IsEnabled() ? MF_CHECKED : MF_UNCHECKED)); } else { - CheckMenuItem(subMenu, ID_DISASM_DISABLEBREAKPOINT, MF_BYCOMMAND | (bpPrev.enabled ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(subMenu, ID_DISASM_DISABLEBREAKPOINT, MF_BYCOMMAND | (bpPrev.IsEnabled() ? MF_CHECKED : MF_UNCHECKED)); } switch (TrackPopupMenuEx(subMenu, TPM_RIGHTBUTTON | TPM_RETURNCMD, screenPt.x, screenPt.y, GetHandle(), 0)) { case ID_DISASM_DISABLEBREAKPOINT: if (isMemory) { - CBreakPoints::ChangeMemCheck(mcPrev.start, mcPrev.end, mcPrev.cond, MemCheckResult(mcPrev.result ^ MEMCHECK_BREAK)); + CBreakPoints::ChangeMemCheck(mcPrev.start, mcPrev.end, mcPrev.cond, BreakAction(mcPrev.result ^ BREAK_ACTION_PAUSE)); } else { - CBreakPoints::ChangeBreakPoint(bpPrev.addr, !bpPrev.enabled); + CBreakPoints::ChangeBreakPoint(bpPrev.addr, BreakAction(bpPrev.result ^ BREAK_ACTION_PAUSE)); } break; case ID_DISASM_EDITBREAKPOINT: diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 766f9dff641e..5135556f6fd1 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -266,7 +266,7 @@ BEGIN CONTROL "",IDC_TABDATATYPE,"SysTabControl32",TCS_BUTTONS,0,1,205,15 END -IDD_BREAKPOINT DIALOGEX 0, 0, 236, 89 +IDD_BREAKPOINT DIALOGEX 0, 0, 236, 109 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Breakpoint" FONT 8, "MS Shell Dlg", 400, 0, 0x1 @@ -282,10 +282,12 @@ BEGIN CONTROL "On change",IDC_BREAKPOINT_ONCHANGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,170,34,50,10 LTEXT "Condition",IDC_STATIC,7,51,31,8 EDITTEXT IDC_BREAKPOINT_CONDITION,41,49,187,14,ES_AUTOHSCROLL - CONTROL "Enabled",IDC_BREAKPOINT_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,41,71,41,10 - CONTROL "Log",IDC_BREAKPOINT_LOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,96,71,27,10 - DEFPUSHBUTTON "OK",IDC_BREAKPOINT_OK,144,68,41,14 - PUSHBUTTON "Cancel",IDC_BREAKPOINT_CANCEL,186,68,42,14 + LTEXT "Log fmt",IDC_STATIC,7,71,31,8 + EDITTEXT IDC_BREAKPOINT_LOG_FORMAT,41,69,187,14,ES_AUTOHSCROLL + CONTROL "Break",IDC_BREAKPOINT_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,41,91,41,10 + CONTROL "Log",IDC_BREAKPOINT_LOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,96,91,27,10 + DEFPUSHBUTTON "OK",IDC_BREAKPOINT_OK,144,88,41,14 + PUSHBUTTON "Cancel",IDC_BREAKPOINT_CANCEL,186,88,42,14 END IDD_DUMPMEMORY DIALOGEX 0, 0, 230, 85 diff --git a/Windows/resource.h b/Windows/resource.h index 5c8af70437fd..66e88a362068 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -163,6 +163,7 @@ #define IDC_GEDBG_MATRICES 1196 #define IDC_GEDBG_FORCEOPAQUE 1197 #define IDC_GEDBG_SHOWCLUT 1198 +#define IDC_BREAKPOINT_LOG_FORMAT 1199 #define ID_SHADERS_BASE 5000 @@ -340,7 +341,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 256 #define _APS_NEXT_COMMAND_VALUE 40165 -#define _APS_NEXT_CONTROL_VALUE 1199 +#define _APS_NEXT_CONTROL_VALUE 1200 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif