From 747a6ec524838a0dc6430ac75b6793457addffd9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 4 Aug 2016 13:29:22 -0700 Subject: [PATCH] Debugger: Add custom log expressions. Similar to Visual Studio, just use {a1} to log the value of register a1. Supports anything the expression parser supports. --- Core/Debugger/Breakpoints.cpp | 62 ++++++++++++++++++++++++++- Core/Debugger/Breakpoints.h | 3 ++ Windows/Debugger/BreakpointWindow.cpp | 6 ++- 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/Core/Debugger/Breakpoints.cpp b/Core/Debugger/Breakpoints.cpp index 053068c5f6c6..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" @@ -42,7 +43,9 @@ void MemCheck::Log(u32 addr, bool write, int size, u32 pc) { 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 { - NOTICE_LOG(MEMMAP, "%s", logFormat.c_str()); + 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()); } } } @@ -312,7 +315,9 @@ BreakAction CBreakPoints::ExecBreakPoint(u32 addr) { if (breakPoints_[bp].logFormat.empty()) { NOTICE_LOG(JIT, "BKP PC=%08x (%s)", addr, g_symbolMap->GetDescription(addr).c_str()); } else { - NOTICE_LOG(JIT, "%s", breakPoints_[bp].logFormat.c_str()); + 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) { @@ -544,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 279ab787e06d..934667914aff 100644 --- a/Core/Debugger/Breakpoints.h +++ b/Core/Debugger/Breakpoints.h @@ -177,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/Windows/Debugger/BreakpointWindow.cpp b/Windows/Debugger/BreakpointWindow.cpp index 0adf84f89180..7c17fb64d515 100644 --- a/Windows/Debugger/BreakpointWindow.cpp +++ b/Windows/Debugger/BreakpointWindow.cpp @@ -183,7 +183,11 @@ bool BreakpointWindow::fetchDialogData(HWND hwnd) wchar_t tempLogFormat[512]; GetWindowTextW(GetDlgItem(hwnd, IDC_BREAKPOINT_LOG_FORMAT), tempLogFormat, 512); logFormat = ConvertWStringToUTF8(tempLogFormat); - // TODO: Verify format. + if (!CBreakPoints::ValidateLogFormat(cpu, logFormat)) { + snprintf(errorMessage, sizeof(errorMessage), "Invalid log format (example: \"{a1}\")."); + MessageBoxA(hwnd, errorMessage, "Error", MB_OK); + return false; + } return true; }