Merge pull request #8882 from unknownbrackets/debugger

Add custom log expressions to the debugger
This commit is contained in:
Henrik Rydgård 2016-08-06 10:54:57 +02:00 committed by GitHub
commit cbf0a479fa
10 changed files with 291 additions and 135 deletions

View File

@ -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;
}

View File

@ -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 @@ public:
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 @@ public:
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 @@ public:
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.

View File

@ -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) {

View File

@ -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<u32, std::string> notJitSorted;

View File

@ -1,6 +1,7 @@
#include <stdio.h>
#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();
}

View File

@ -1,4 +1,5 @@
#pragma once
#include <string>
#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 @@ public:
enabled = log = true;
address = -1;
size = 1;
condition[0] = 0;
};
@ -44,4 +47,4 @@ public:
void loadFromMemcheck(MemCheck& memcheck);
void loadFromBreakpoint(BreakPoint& memcheck);
void initBreakpoint(u32 address);
};
};

View File

@ -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);

View File

@ -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:

View File

@ -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

View File

@ -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