diff --git a/Source/Core/Core/PowerPC/BreakPoints.cpp b/Source/Core/Core/PowerPC/BreakPoints.cpp index fbaeff777e..00227a434b 100644 --- a/Source/Core/Core/PowerPC/BreakPoints.cpp +++ b/Source/Core/Core/PowerPC/BreakPoints.cpp @@ -30,6 +30,19 @@ bool BreakPoints::IsTempBreakPoint(u32 address) const }); } +bool BreakPoints::IsBreakPointBreakOnHit(u32 address) const +{ + return std::any_of(m_breakpoints.begin(), m_breakpoints.end(), [address](const auto& bp) { + return bp.address == address && bp.break_on_hit; + }); +} + +bool BreakPoints::IsBreakPointLogOnHit(u32 address) const +{ + return std::any_of(m_breakpoints.begin(), m_breakpoints.end(), + [address](const auto& bp) { return bp.address == address && bp.log_on_hit; }); +} + BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const { TBreakPointsStr bp_strings; @@ -38,7 +51,8 @@ BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const if (!bp.is_temporary) { std::ostringstream ss; - ss << std::hex << bp.address << " " << (bp.is_enabled ? "n" : ""); + ss << std::hex << bp.address << " " << (bp.is_enabled ? "n" : "") + << (bp.log_on_hit ? "l" : "") << (bp.break_on_hit ? "b" : ""); bp_strings.push_back(ss.str()); } } @@ -55,6 +69,8 @@ void BreakPoints::AddFromStrings(const TBreakPointsStr& bp_strings) ss << std::hex << bp_string; ss >> bp.address; bp.is_enabled = bp_string.find('n') != bp_string.npos; + bp.log_on_hit = bp_string.find('l') != bp_string.npos; + bp.break_on_hit = bp_string.find('b') != bp_string.npos; bp.is_temporary = false; Add(bp); } @@ -71,6 +87,11 @@ void BreakPoints::Add(const TBreakPoint& bp) } void BreakPoints::Add(u32 address, bool temp) +{ + BreakPoints::Add(address, temp, true, false); +} + +void BreakPoints::Add(u32 address, bool temp, bool break_on_hit, bool log_on_hit) { // Only add new addresses if (IsAddressBreakPoint(address)) @@ -79,6 +100,8 @@ void BreakPoints::Add(u32 address, bool temp) TBreakPoint bp; // breakpoint settings bp.is_enabled = true; bp.is_temporary = temp; + bp.break_on_hit = break_on_hit; + bp.log_on_hit = log_on_hit; bp.address = address; m_breakpoints.push_back(bp); @@ -154,7 +177,7 @@ void MemChecks::AddFromStrings(const TMemChecksStr& mc_strings) mc.is_break_on_read = mc_string.find('r') != mc_string.npos; mc.is_break_on_write = mc_string.find('w') != mc_string.npos; mc.log_on_hit = mc_string.find('l') != mc_string.npos; - mc.break_on_hit = mc_string.find('p') != mc_string.npos; + mc.break_on_hit = mc_string.find('b') != mc_string.npos; if (mc.is_ranged) ss >> mc.end_address; else diff --git a/Source/Core/Core/PowerPC/BreakPoints.h b/Source/Core/Core/PowerPC/BreakPoints.h index c00caeef98..571427f47d 100644 --- a/Source/Core/Core/PowerPC/BreakPoints.h +++ b/Source/Core/Core/PowerPC/BreakPoints.h @@ -20,6 +20,8 @@ struct TBreakPoint u32 address = 0; bool is_enabled = false; bool is_temporary = false; + bool log_on_hit = false; + bool break_on_hit = false; }; struct TMemCheck @@ -56,8 +58,11 @@ public: // is address breakpoint bool IsAddressBreakPoint(u32 address) const; bool IsTempBreakPoint(u32 address) const; + bool IsBreakPointBreakOnHit(u32 address) const; + bool IsBreakPointLogOnHit(u32 address) const; // Add BreakPoint + void Add(u32 address, bool temp, bool break_on_hit, bool log_on_hit); void Add(u32 address, bool temp = false); void Add(const TBreakPoint& bp); diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index ebac1a07d9..3833774c85 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -28,6 +28,7 @@ #include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/MMU.h" +#include "Core/PowerPC/PPCSymbolDB.h" namespace PowerPC { @@ -603,7 +604,14 @@ void CheckBreakPoints() { if (PowerPC::breakpoints.IsAddressBreakPoint(PC)) { - CPU::Break(); + if (PowerPC::breakpoints.IsBreakPointBreakOnHit(PC)) + CPU::Break(); + if (PowerPC::breakpoints.IsBreakPointLogOnHit(PC)) + { + NOTICE_LOG(MEMMAP, "BP %08x %s(%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x) LR=%08x", + PC, g_symbolDB.GetDescription(PC).c_str(), GPR(3), GPR(4), GPR(5), GPR(6), GPR(7), + GPR(8), GPR(9), GPR(10), GPR(11), GPR(12), LR); + } if (PowerPC::breakpoints.IsTempBreakPoint(PC)) PowerPC::breakpoints.Remove(PC); } diff --git a/Source/Core/DolphinQt/Debugger/BreakpointWidget.cpp b/Source/Core/DolphinQt/Debugger/BreakpointWidget.cpp index 2f12877f15..ea686a2dcf 100644 --- a/Source/Core/DolphinQt/Debugger/BreakpointWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/BreakpointWidget.cpp @@ -188,7 +188,15 @@ void BreakpointWidget::Update() m_table->setItem(i, 3, create_item(QStringLiteral("%1").arg(bp.address, 8, 16, QLatin1Char('0')))); - m_table->setItem(i, 4, create_item()); + QString flags; + + if (bp.break_on_hit) + flags.append(QLatin1Char{'b'}); + + if (bp.log_on_hit) + flags.append(QLatin1Char{'l'}); + + m_table->setItem(i, 4, create_item(flags)); i++; } @@ -308,7 +316,12 @@ void BreakpointWidget::OnSave() void BreakpointWidget::AddBP(u32 addr) { - PowerPC::breakpoints.Add(addr); + AddBP(addr, false, true, true); +} + +void BreakpointWidget::AddBP(u32 addr, bool temp, bool break_on_hit, bool log_on_hit) +{ + PowerPC::breakpoints.Add(addr, temp, break_on_hit, log_on_hit); Update(); } diff --git a/Source/Core/DolphinQt/Debugger/BreakpointWidget.h b/Source/Core/DolphinQt/Debugger/BreakpointWidget.h index 87ca60679e..570bb02b51 100644 --- a/Source/Core/DolphinQt/Debugger/BreakpointWidget.h +++ b/Source/Core/DolphinQt/Debugger/BreakpointWidget.h @@ -22,6 +22,7 @@ public: ~BreakpointWidget(); void AddBP(u32 addr); + void AddBP(u32 addr, bool temp, bool break_on_hit, bool log_on_hit); void AddAddressMBP(u32 addr, bool on_read = true, bool on_write = true, bool do_log = true, bool do_break = true); void AddRangedMBP(u32 from, u32 to, bool do_read = true, bool do_write = true, bool do_log = true, diff --git a/Source/Core/DolphinQt/Debugger/NewBreakpointDialog.cpp b/Source/Core/DolphinQt/Debugger/NewBreakpointDialog.cpp index 6271be807a..4ad30016cd 100644 --- a/Source/Core/DolphinQt/Debugger/NewBreakpointDialog.cpp +++ b/Source/Core/DolphinQt/Debugger/NewBreakpointDialog.cpp @@ -62,12 +62,12 @@ void NewBreakpointDialog::CreateWidgets() m_memory_on_read_and_write = new QRadioButton(tr("Read or Write")); m_memory_on_write->setChecked(true); // i18n: This is a selectable action when adding a breakpoint - m_memory_do_log = new QRadioButton(tr("Write to Log")); + m_do_log = new QRadioButton(tr("Write to Log")); // i18n: This is a selectable action when adding a breakpoint - m_memory_do_break = new QRadioButton(tr("Break")); + m_do_break = new QRadioButton(tr("Break")); // i18n: This is a selectable action when adding a breakpoint - m_memory_do_log_and_break = new QRadioButton(tr("Write to Log and Break")); - m_memory_do_log_and_break->setChecked(true); + m_do_log_and_break = new QRadioButton(tr("Write to Log and Break")); + m_do_log_and_break->setChecked(true); auto* memory_layout = new QGridLayout; m_memory_box->setLayout(memory_layout); @@ -89,10 +89,9 @@ void NewBreakpointDialog::CreateWidgets() QGroupBox* action_box = new QGroupBox(tr("Action")); auto* action_layout = new QHBoxLayout; action_box->setLayout(action_layout); - memory_layout->addWidget(action_box, 3, 0, 1, -1); - action_layout->addWidget(m_memory_do_log); - action_layout->addWidget(m_memory_do_break); - action_layout->addWidget(m_memory_do_log_and_break); + action_layout->addWidget(m_do_log); + action_layout->addWidget(m_do_break); + action_layout->addWidget(m_do_log_and_break); auto* layout = new QVBoxLayout; @@ -100,6 +99,7 @@ void NewBreakpointDialog::CreateWidgets() layout->addWidget(m_instruction_box); layout->addWidget(m_memory_bp); layout->addWidget(m_memory_box); + layout->addWidget(action_box); layout->addWidget(m_buttons); setLayout(layout); @@ -150,8 +150,8 @@ void NewBreakpointDialog::accept() bool on_write = m_memory_on_write->isChecked() || m_memory_on_read_and_write->isChecked(); // Actions - bool do_log = m_memory_do_log->isChecked() || m_memory_do_log_and_break->isChecked(); - bool do_break = m_memory_do_break->isChecked() || m_memory_do_log_and_break->isChecked(); + bool do_log = m_do_log->isChecked() || m_do_log_and_break->isChecked(); + bool do_break = m_do_break->isChecked() || m_do_log_and_break->isChecked(); bool good; @@ -165,7 +165,7 @@ void NewBreakpointDialog::accept() return; } - m_parent->AddBP(address); + m_parent->AddBP(address, false, do_break, do_log); } else { diff --git a/Source/Core/DolphinQt/Debugger/NewBreakpointDialog.h b/Source/Core/DolphinQt/Debugger/NewBreakpointDialog.h index 681dfa9656..d9d2958c2b 100644 --- a/Source/Core/DolphinQt/Debugger/NewBreakpointDialog.h +++ b/Source/Core/DolphinQt/Debugger/NewBreakpointDialog.h @@ -48,9 +48,11 @@ private: QRadioButton* m_memory_on_read; QRadioButton* m_memory_on_read_and_write; QRadioButton* m_memory_on_write; - QRadioButton* m_memory_do_log; - QRadioButton* m_memory_do_break; - QRadioButton* m_memory_do_log_and_break; + + // Action + QRadioButton* m_do_log; + QRadioButton* m_do_break; + QRadioButton* m_do_log_and_break; QDialogButtonBox* m_buttons; BreakpointWidget* m_parent;