Compare commits

...

2 Commits

Author SHA1 Message Date
Jas Laferriere
52a7b51b3b
Merge 476234f001 into 04f71e5e6d 2025-12-12 18:03:12 -06:00
Jas Laferriere
476234f001 MI: add option to log call stack on bp hit 2025-09-30 13:27:38 -04:00
8 changed files with 66 additions and 15 deletions

View File

@ -10,11 +10,13 @@
#include <string>
#include <vector>
#include "Common/Assert.h"
#include "Common/BitSet.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Core/Core.h"
#include "Core/Debugger/DebugInterface.h"
#include "Core/Debugger/Debugger_SymbolMap.h"
#include "Core/PowerPC/Expression.h"
#include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/MMU.h"
@ -72,6 +74,8 @@ BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const
ss << "l";
if (bp.break_on_hit)
ss << "b";
if (bp.log_call_stack)
ss << "s";
if (bp.condition)
ss << "c " << bp.condition->GetText();
bp_strings.emplace_back(ss.str());
@ -96,6 +100,7 @@ void BreakPoints::AddFromStrings(const TBreakPointsStr& bp_strings)
bp.is_enabled = flags.find('n') != flags.npos;
bp.log_on_hit = flags.find('l') != flags.npos;
bp.break_on_hit = flags.find('b') != flags.npos;
bp.log_call_stack = flags.find('s') != flags.npos;
if (flags.find('c') != std::string::npos)
{
iss >> std::ws;
@ -119,10 +124,10 @@ void BreakPoints::Add(TBreakPoint bp)
void BreakPoints::Add(u32 address)
{
BreakPoints::Add(address, true, false, std::nullopt);
BreakPoints::Add(address, true, false, false, std::nullopt);
}
void BreakPoints::Add(u32 address, bool break_on_hit, bool log_on_hit,
void BreakPoints::Add(u32 address, bool break_on_hit, bool log_on_hit, bool log_call_stack,
std::optional<Expression> condition)
{
// Check for existing breakpoint, and overwrite with new info.
@ -133,6 +138,7 @@ void BreakPoints::Add(u32 address, bool break_on_hit, bool log_on_hit,
bp.is_enabled = true;
bp.break_on_hit = break_on_hit;
bp.log_on_hit = log_on_hit;
bp.log_call_stack = log_call_stack;
bp.address = address;
bp.condition = std::move(condition);
@ -241,6 +247,8 @@ MemChecks::TMemChecksStr MemChecks::GetStrings() const
ss << 'l';
if (mc.break_on_hit)
ss << 'b';
if (mc.log_call_stack)
ss << 's';
if (mc.condition)
ss << "c " << mc.condition->GetText();
@ -271,6 +279,7 @@ void MemChecks::AddFromStrings(const TMemChecksStr& mc_strings)
mc.is_enabled = flags.find('n') != flags.npos;
mc.is_break_on_read = flags.find('r') != flags.npos;
mc.is_break_on_write = flags.find('w') != flags.npos;
mc.log_call_stack = flags.find('s') != flags.npos;
mc.log_on_hit = flags.find('l') != flags.npos;
mc.break_on_hit = flags.find('b') != flags.npos;
if (flags.find('c') != std::string::npos)
@ -421,6 +430,14 @@ bool TMemCheck::Action(Core::System& system, u64 value, u32 addr, bool write, si
NOTICE_LOG_FMT(MEMMAP, "MBP {:08x} ({}) {}{} {:x} at {:08x} ({})", pc,
ppc_symbol_db.GetDescription(pc), write ? "Write" : "Read", size * 8, value,
addr, ppc_symbol_db.GetDescription(addr));
if (log_call_stack)
{
ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard(system);
Dolphin_Debugger::PrintCallstack(guard, Common::Log::LogType::MEMMAP,
Common::Log::LogLevel::LNOTICE);
}
}
if (break_on_hit)
return true;

View File

@ -23,6 +23,7 @@ struct TBreakPoint
bool is_enabled = false;
bool log_on_hit = false;
bool break_on_hit = false;
bool log_call_stack = false;
std::optional<Expression> condition;
};
@ -40,6 +41,8 @@ struct TMemCheck
bool log_on_hit = false;
bool break_on_hit = false;
bool log_call_stack = false;
u32 num_hits = 0;
std::optional<Expression> condition;
@ -74,7 +77,8 @@ public:
const TBreakPoint* GetRegularBreakpoint(u32 address) const;
// Add BreakPoint. If one already exists on the same address, replace it.
void Add(u32 address, bool break_on_hit, bool log_on_hit, std::optional<Expression> condition);
void Add(u32 address, bool break_on_hit, bool log_on_hit, bool log_call_stack,
std::optional<Expression> condition);
void Add(u32 address);
void Add(TBreakPoint bp);
// Add temporary breakpoint (e.g., Step Over, Run to Here)

View File

@ -20,6 +20,7 @@
#include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/Debugger/Debugger_SymbolMap.h"
#include "Core/HW/CPU.h"
#include "Core/HW/SystemTimers.h"
#include "Core/Host.h"
@ -641,6 +642,15 @@ bool PowerPCManager::CheckBreakPoints()
m_ppc_state.gpr[4], m_ppc_state.gpr[5], m_ppc_state.gpr[6], m_ppc_state.gpr[7],
m_ppc_state.gpr[8], m_ppc_state.gpr[9], m_ppc_state.gpr[10], m_ppc_state.gpr[11],
m_ppc_state.gpr[12], LR(m_ppc_state));
if (bp->log_call_stack)
{
auto& system = Core::System::GetInstance();
ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard(system);
Dolphin_Debugger::PrintCallstack(guard, Common::Log::LogType::MEMMAP,
Common::Log::LogLevel::LNOTICE);
}
}
if (bp->break_on_hit)
return true;

View File

@ -1159,7 +1159,7 @@ void BranchWatchDialog::SetBreakpoints(bool break_on_hit, bool log_on_hit) const
for (const QModelIndex& index : m_index_list_temp)
{
const u32 address = m_table_proxy->data(index, UserRole::ClickRole).value<u32>();
breakpoints.Add(address, break_on_hit, log_on_hit, {});
breakpoints.Add(address, break_on_hit, log_on_hit, false, {});
}
emit Host::GetInstance()->PPCBreakpointsChanged();
}

View File

@ -47,6 +47,8 @@ BreakpointDialog::BreakpointDialog(BreakpointWidget* parent, const TBreakPoint*
m_do_log->setChecked(!breakpoint->break_on_hit && breakpoint->log_on_hit);
m_do_log_and_break->setChecked(breakpoint->break_on_hit && breakpoint->log_on_hit);
m_call_stack_checkbox->setChecked(breakpoint->log_call_stack);
OnBPTypeChanged();
OnAddressTypeChanged();
}
@ -81,6 +83,8 @@ BreakpointDialog::BreakpointDialog(BreakpointWidget* parent, const TMemCheck* me
m_do_log->setChecked(!memcheck->break_on_hit && memcheck->log_on_hit);
m_do_log_and_break->setChecked(memcheck->break_on_hit && memcheck->log_on_hit);
m_call_stack_checkbox->setChecked(memcheck->log_call_stack);
OnBPTypeChanged();
OnAddressTypeChanged();
}
@ -175,6 +179,11 @@ void BreakpointDialog::CreateWidgets()
conditional_layout->addWidget(new QLabel(tr("Condition:")));
conditional_layout->addWidget(m_conditional);
// add a checkbox to support printing call stacks on membps
QHBoxLayout* call_stack_layout = new QHBoxLayout;
m_call_stack_checkbox = new QCheckBox(tr("Log Call Stack"));
call_stack_layout->addWidget(m_call_stack_checkbox);
auto* action_layout = new QHBoxLayout;
action_layout->addWidget(m_do_log);
action_layout->addWidget(m_do_break);
@ -183,6 +192,7 @@ void BreakpointDialog::CreateWidgets()
auto* action_vlayout = new QVBoxLayout;
action_vlayout->addLayout(conditional_layout);
action_vlayout->addLayout(action_layout);
action_vlayout->addLayout(call_stack_layout);
action_box->setLayout(action_vlayout);
@ -263,6 +273,7 @@ void BreakpointDialog::accept()
// Actions
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 log_call_stack = m_call_stack_checkbox->isChecked();
bool good;
@ -286,7 +297,7 @@ void BreakpointDialog::accept()
return;
}
m_parent->AddBP(address, do_break, do_log, condition);
m_parent->AddBP(address, do_break, do_log, log_call_stack, condition);
}
else
{
@ -307,11 +318,12 @@ void BreakpointDialog::accept()
return;
}
m_parent->AddRangedMBP(from, to, on_read, on_write, do_log, do_break, condition);
m_parent->AddRangedMBP(from, to, on_read, on_write, do_log, do_break, log_call_stack,
condition);
}
else
{
m_parent->AddAddressMBP(from, on_read, on_write, do_log, do_break, condition);
m_parent->AddAddressMBP(from, on_read, on_write, do_log, do_break, log_call_stack, condition);
}
}

View File

@ -66,6 +66,8 @@ private:
QRadioButton* m_do_break;
QRadioButton* m_do_log_and_break;
QCheckBox* m_call_stack_checkbox;
QLineEdit* m_conditional;
QPushButton* m_cond_help_btn;

View File

@ -597,13 +597,14 @@ void BreakpointWidget::OnItemChanged(QTableWidgetItem* item)
void BreakpointWidget::AddBP(u32 addr)
{
AddBP(addr, true, true, {});
AddBP(addr, true, true, false, {});
}
void BreakpointWidget::AddBP(u32 addr, bool break_on_hit, bool log_on_hit, const QString& condition)
void BreakpointWidget::AddBP(u32 addr, bool break_on_hit, bool log_on_hit, bool log_call_stack,
const QString& condition)
{
m_system.GetPowerPC().GetBreakPoints().Add(
addr, break_on_hit, log_on_hit,
addr, break_on_hit, log_on_hit, log_call_stack,
!condition.isEmpty() ? Expression::TryParse(condition.toUtf8().constData()) : std::nullopt);
emit Host::GetInstance()->PPCBreakpointsChanged();
@ -644,7 +645,7 @@ void BreakpointWidget::EditBreakpoint(u32 address, int edit, std::optional<QStri
}
void BreakpointWidget::AddAddressMBP(u32 addr, bool on_read, bool on_write, bool do_log,
bool do_break, const QString& condition)
bool do_break, bool log_call_stack, const QString& condition)
{
TMemCheck check;
@ -655,6 +656,7 @@ void BreakpointWidget::AddAddressMBP(u32 addr, bool on_read, bool on_write, bool
check.is_break_on_write = on_write;
check.log_on_hit = do_log;
check.break_on_hit = do_break;
check.log_call_stack = log_call_stack;
check.condition =
!condition.isEmpty() ? Expression::TryParse(condition.toUtf8().constData()) : std::nullopt;
{
@ -666,7 +668,7 @@ void BreakpointWidget::AddAddressMBP(u32 addr, bool on_read, bool on_write, bool
}
void BreakpointWidget::AddRangedMBP(u32 from, u32 to, bool on_read, bool on_write, bool do_log,
bool do_break, const QString& condition)
bool do_break, bool log_call_stack, const QString& condition)
{
TMemCheck check;
@ -677,6 +679,7 @@ void BreakpointWidget::AddRangedMBP(u32 from, u32 to, bool on_read, bool on_writ
check.is_break_on_write = on_write;
check.log_on_hit = do_log;
check.break_on_hit = do_break;
check.log_call_stack = log_call_stack;
check.condition =
!condition.isEmpty() ? Expression::TryParse(condition.toUtf8().constData()) : std::nullopt;
{

View File

@ -34,11 +34,14 @@ public:
~BreakpointWidget() override;
void AddBP(u32 addr);
void AddBP(u32 addr, bool break_on_hit, bool log_on_hit, const QString& condition);
void AddBP(u32 addr, bool break_on_hit, bool log_on_hit, bool log_call_stack,
const QString& condition);
void AddAddressMBP(u32 addr, bool on_read = true, bool on_write = true, bool do_log = true,
bool do_break = true, const QString& condition = {});
bool do_break = true, bool log_call_stack = false,
const QString& condition = {});
void AddRangedMBP(u32 from, u32 to, bool do_read = true, bool do_write = true, bool do_log = true,
bool do_break = true, const QString& condition = {});
bool do_break = true, bool log_call_stack = false,
const QString& condition = {});
void UpdateButtonsEnabled();
void Update();