mirror of https://github.com/PCSX2/pcsx2.git
Debugger: Use std::string for bp conditions. Implement memory bp conditions
This commit is contained in:
parent
75defbeded
commit
de020978e4
|
@ -44,7 +44,7 @@ BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu, Breakpo
|
||||||
m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(bp->addr, 16));
|
m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(bp->addr, 16));
|
||||||
|
|
||||||
if (bp->hasCond)
|
if (bp->hasCond)
|
||||||
m_ui.txtCondition->setText(QString::fromLocal8Bit(bp->cond.expressionString));
|
m_ui.txtCondition->setText(QString::fromStdString(bp->cond.expressionString));
|
||||||
}
|
}
|
||||||
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
|
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
|
||||||
{
|
{
|
||||||
|
@ -53,12 +53,15 @@ BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu, Breakpo
|
||||||
m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(mc->start, 16));
|
m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(mc->start, 16));
|
||||||
m_ui.txtSize->setText(QtUtils::FilledQStringFromValue(mc->end - mc->start, 16));
|
m_ui.txtSize->setText(QtUtils::FilledQStringFromValue(mc->end - mc->start, 16));
|
||||||
|
|
||||||
m_ui.chkRead->setChecked(mc->cond & MEMCHECK_READ);
|
m_ui.chkRead->setChecked(mc->memCond & MEMCHECK_READ);
|
||||||
m_ui.chkWrite->setChecked(mc->cond & MEMCHECK_WRITE);
|
m_ui.chkWrite->setChecked(mc->memCond & MEMCHECK_WRITE);
|
||||||
m_ui.chkChange->setChecked(mc->cond & MEMCHECK_WRITE_ONCHANGE);
|
m_ui.chkChange->setChecked(mc->memCond & MEMCHECK_WRITE_ONCHANGE);
|
||||||
|
|
||||||
m_ui.chkEnable->setChecked(mc->result & MEMCHECK_BREAK);
|
m_ui.chkEnable->setChecked(mc->result & MEMCHECK_BREAK);
|
||||||
m_ui.chkLog->setChecked(mc->result & MEMCHECK_LOG);
|
m_ui.chkLog->setChecked(mc->result & MEMCHECK_LOG);
|
||||||
|
|
||||||
|
if (mc->hasCond)
|
||||||
|
m_ui.txtCondition->setText(QString::fromStdString(mc->cond.expressionString));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +73,6 @@ void BreakpointDialog::onRdoButtonToggled()
|
||||||
{
|
{
|
||||||
const bool isExecute = m_ui.rdoExecute->isChecked();
|
const bool isExecute = m_ui.rdoExecute->isChecked();
|
||||||
|
|
||||||
m_ui.grpExecute->setEnabled(isExecute);
|
|
||||||
m_ui.grpMemory->setEnabled(!isExecute);
|
m_ui.grpMemory->setEnabled(!isExecute);
|
||||||
|
|
||||||
m_ui.chkLog->setEnabled(!isExecute);
|
m_ui.chkLog->setEnabled(!isExecute);
|
||||||
|
@ -114,8 +116,7 @@ void BreakpointDialog::accept()
|
||||||
}
|
}
|
||||||
|
|
||||||
bp->cond.expression = expr;
|
bp->cond.expression = expr;
|
||||||
strncpy(&bp->cond.expressionString[0], m_ui.txtCondition->text().toLocal8Bit().constData(),
|
bp->cond.expressionString = m_ui.txtCondition->text().toStdString();
|
||||||
sizeof(bp->cond.expressionString));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (auto* mc = std::get_if<MemCheck>(&m_bp_mc))
|
if (auto* mc = std::get_if<MemCheck>(&m_bp_mc))
|
||||||
|
@ -141,6 +142,21 @@ void BreakpointDialog::accept()
|
||||||
mc->start = startAddress;
|
mc->start = startAddress;
|
||||||
mc->end = startAddress + size;
|
mc->end = startAddress + size;
|
||||||
|
|
||||||
|
if (!m_ui.txtCondition->text().isEmpty())
|
||||||
|
{
|
||||||
|
mc->hasCond = true;
|
||||||
|
mc->cond.debug = m_cpu;
|
||||||
|
|
||||||
|
if (!m_cpu->initExpression(m_ui.txtCondition->text().toLocal8Bit().constData(), expr))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Error"), tr("Invalid condition \"%1\"").arg(getExpressionError()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mc->cond.expression = expr;
|
||||||
|
mc->cond.expressionString = m_ui.txtCondition->text().toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
int condition = 0;
|
int condition = 0;
|
||||||
if (m_ui.chkRead->isChecked())
|
if (m_ui.chkRead->isChecked())
|
||||||
condition |= MEMCHECK_READ;
|
condition |= MEMCHECK_READ;
|
||||||
|
@ -149,7 +165,7 @@ void BreakpointDialog::accept()
|
||||||
if (m_ui.chkChange->isChecked())
|
if (m_ui.chkChange->isChecked())
|
||||||
condition |= MEMCHECK_WRITE_ONCHANGE;
|
condition |= MEMCHECK_WRITE_ONCHANGE;
|
||||||
|
|
||||||
mc->cond = static_cast<MemCheckCondition>(condition);
|
mc->memCond = static_cast<MemCheckCondition>(condition);
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (m_ui.chkEnable->isChecked())
|
if (m_ui.chkEnable->isChecked())
|
||||||
|
|
|
@ -221,9 +221,6 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QGroupBox" name="grpExecute">
|
<widget class="QGroupBox" name="grpExecute">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>110</x>
|
<x>110</x>
|
||||||
|
@ -233,7 +230,7 @@
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Execute</string>
|
<string></string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QFormLayout" name="formLayout_3">
|
<layout class="QFormLayout" name="formLayout_3">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
|
|
|
@ -52,7 +52,7 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||||
// Note: Fix up the disassemblymanager so we can use it here, instead of calling a function through the disassemblyview (yuck)
|
// Note: Fix up the disassemblymanager so we can use it here, instead of calling a function through the disassemblyview (yuck)
|
||||||
return m_cpu.disasm(bp->addr, true).c_str();
|
return m_cpu.disasm(bp->addr, true).c_str();
|
||||||
case BreakpointColumns::CONDITION:
|
case BreakpointColumns::CONDITION:
|
||||||
return bp->hasCond ? QString::fromLocal8Bit(bp->cond.expressionString) : "";
|
return bp->hasCond ? QString::fromStdString(bp->cond.expressionString) : "";
|
||||||
case BreakpointColumns::HITS:
|
case BreakpointColumns::HITS:
|
||||||
return tr("--");
|
return tr("--");
|
||||||
}
|
}
|
||||||
|
@ -66,10 +66,10 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||||
case BreakpointColumns::TYPE:
|
case BreakpointColumns::TYPE:
|
||||||
{
|
{
|
||||||
QString type("");
|
QString type("");
|
||||||
type += (mc->cond & MEMCHECK_READ) ? tr("Read") : "";
|
type += (mc->memCond & MEMCHECK_READ) ? tr("Read") : "";
|
||||||
type += ((mc->cond & MEMCHECK_READWRITE) == MEMCHECK_READWRITE) ? ", " : " ";
|
type += ((mc->memCond & MEMCHECK_READWRITE) == MEMCHECK_READWRITE) ? ", " : " ";
|
||||||
//: (C) = changes, as in "look for changes".
|
//: (C) = changes, as in "look for changes".
|
||||||
type += (mc->cond & MEMCHECK_WRITE) ? (mc->cond & MEMCHECK_WRITE_ONCHANGE) ? tr("Write(C)") : tr("Write") : "";
|
type += (mc->memCond & MEMCHECK_WRITE) ? (mc->memCond & MEMCHECK_WRITE_ONCHANGE) ? tr("Write(C)") : tr("Write") : "";
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
case BreakpointColumns::OFFSET:
|
case BreakpointColumns::OFFSET:
|
||||||
|
@ -79,7 +79,7 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||||
case BreakpointColumns::OPCODE:
|
case BreakpointColumns::OPCODE:
|
||||||
return tr("--"); // Our address is going to point to memory, no purpose in printing the op
|
return tr("--"); // Our address is going to point to memory, no purpose in printing the op
|
||||||
case BreakpointColumns::CONDITION:
|
case BreakpointColumns::CONDITION:
|
||||||
return tr("--"); // No condition on memchecks
|
return mc->hasCond ? QString::fromStdString(mc->cond.expressionString) : "";
|
||||||
case BreakpointColumns::HITS:
|
case BreakpointColumns::HITS:
|
||||||
return QString::number(mc->numHits);
|
return QString::number(mc->numHits);
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||||
// Note: Fix up the disassemblymanager so we can use it here, instead of calling a function through the disassemblyview (yuck)
|
// Note: Fix up the disassemblymanager so we can use it here, instead of calling a function through the disassemblyview (yuck)
|
||||||
return m_cpu.disasm(bp->addr, false).c_str();
|
return m_cpu.disasm(bp->addr, false).c_str();
|
||||||
case BreakpointColumns::CONDITION:
|
case BreakpointColumns::CONDITION:
|
||||||
return bp->hasCond ? QString::fromLocal8Bit(bp->cond.expressionString) : "";
|
return bp->hasCond ? QString::fromStdString(bp->cond.expressionString) : "";
|
||||||
case BreakpointColumns::HITS:
|
case BreakpointColumns::HITS:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||||
case BreakpointColumns::ENABLED:
|
case BreakpointColumns::ENABLED:
|
||||||
return (mc->result & MEMCHECK_BREAK);
|
return (mc->result & MEMCHECK_BREAK);
|
||||||
case BreakpointColumns::TYPE:
|
case BreakpointColumns::TYPE:
|
||||||
return mc->cond;
|
return mc->memCond;
|
||||||
case BreakpointColumns::OFFSET:
|
case BreakpointColumns::OFFSET:
|
||||||
return mc->start;
|
return mc->start;
|
||||||
case BreakpointColumns::SIZE_LABEL:
|
case BreakpointColumns::SIZE_LABEL:
|
||||||
|
@ -125,7 +125,7 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||||
case BreakpointColumns::OPCODE:
|
case BreakpointColumns::OPCODE:
|
||||||
return "";
|
return "";
|
||||||
case BreakpointColumns::CONDITION:
|
case BreakpointColumns::CONDITION:
|
||||||
return "";
|
return mc->hasCond ? QString::fromStdString(mc->cond.expressionString) : "";
|
||||||
case BreakpointColumns::HITS:
|
case BreakpointColumns::HITS:
|
||||||
return mc->numHits;
|
return mc->numHits;
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||||
// Note: Fix up the disassemblymanager so we can use it here, instead of calling a function through the disassemblyview (yuck)
|
// Note: Fix up the disassemblymanager so we can use it here, instead of calling a function through the disassemblyview (yuck)
|
||||||
return m_cpu.disasm(bp->addr, false).c_str();
|
return m_cpu.disasm(bp->addr, false).c_str();
|
||||||
case BreakpointColumns::CONDITION:
|
case BreakpointColumns::CONDITION:
|
||||||
return bp->hasCond ? QString::fromLocal8Bit(bp->cond.expressionString) : "";
|
return bp->hasCond ? QString::fromStdString(bp->cond.expressionString) : "";
|
||||||
case BreakpointColumns::HITS:
|
case BreakpointColumns::HITS:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||||
switch (index.column())
|
switch (index.column())
|
||||||
{
|
{
|
||||||
case BreakpointColumns::TYPE:
|
case BreakpointColumns::TYPE:
|
||||||
return mc->cond;
|
return mc->memCond;
|
||||||
case BreakpointColumns::OFFSET:
|
case BreakpointColumns::OFFSET:
|
||||||
return QtUtils::FilledQStringFromValue(mc->start, 16);
|
return QtUtils::FilledQStringFromValue(mc->start, 16);
|
||||||
case BreakpointColumns::SIZE_LABEL:
|
case BreakpointColumns::SIZE_LABEL:
|
||||||
|
@ -169,7 +169,7 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||||
case BreakpointColumns::OPCODE:
|
case BreakpointColumns::OPCODE:
|
||||||
return "";
|
return "";
|
||||||
case BreakpointColumns::CONDITION:
|
case BreakpointColumns::CONDITION:
|
||||||
return "";
|
return mc->hasCond ? QString::fromStdString(mc->cond.expressionString) : "";
|
||||||
case BreakpointColumns::HITS:
|
case BreakpointColumns::HITS:
|
||||||
return mc->numHits;
|
return mc->numHits;
|
||||||
case BreakpointColumns::ENABLED:
|
case BreakpointColumns::ENABLED:
|
||||||
|
@ -256,14 +256,12 @@ Qt::ItemFlags BreakpointModel::flags(const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
volatile const int row = index.row();
|
volatile const int row = index.row();
|
||||||
|
|
||||||
bool is_breakpoint = std::holds_alternative<BreakPoint>(m_breakpoints.at(row));
|
const bool is_breakpoint = std::holds_alternative<BreakPoint>(m_breakpoints.at(row));
|
||||||
|
|
||||||
switch (index.column())
|
switch (index.column())
|
||||||
{
|
{
|
||||||
case BreakpointColumns::CONDITION:
|
case BreakpointColumns::CONDITION:
|
||||||
if (is_breakpoint)
|
return Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEditable;
|
||||||
return Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEditable;
|
|
||||||
[[fallthrough]];
|
|
||||||
case BreakpointColumns::TYPE:
|
case BreakpointColumns::TYPE:
|
||||||
case BreakpointColumns::OPCODE:
|
case BreakpointColumns::OPCODE:
|
||||||
case BreakpointColumns::HITS:
|
case BreakpointColumns::HITS:
|
||||||
|
@ -292,7 +290,7 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||||
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
|
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
|
||||||
{
|
{
|
||||||
Host::RunOnCPUThread([cpu = this->m_cpu.getCpuType(), mc = *mc] {
|
Host::RunOnCPUThread([cpu = this->m_cpu.getCpuType(), mc = *mc] {
|
||||||
CBreakPoints::ChangeMemCheck(cpu, mc.start, mc.end, mc.cond,
|
CBreakPoints::ChangeMemCheck(cpu, mc.start, mc.end, mc.memCond,
|
||||||
MemCheckResult(mc.result ^ MEMCHECK_BREAK));
|
MemCheckResult(mc.result ^ MEMCHECK_BREAK));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -303,40 +301,71 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||||
{
|
{
|
||||||
auto bp_mc = m_breakpoints.at(index.row());
|
auto bp_mc = m_breakpoints.at(index.row());
|
||||||
|
|
||||||
if (std::holds_alternative<MemCheck>(bp_mc))
|
if (auto* bp = std::get_if<BreakPoint>(&bp_mc))
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto bp = std::get<BreakPoint>(bp_mc);
|
|
||||||
|
|
||||||
const QString condValue = value.toString();
|
|
||||||
|
|
||||||
if (condValue.isEmpty())
|
|
||||||
{
|
{
|
||||||
if (bp.hasCond)
|
const QString condValue = value.toString();
|
||||||
|
|
||||||
|
if (condValue.isEmpty())
|
||||||
{
|
{
|
||||||
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), bp] {
|
if (bp->hasCond)
|
||||||
CBreakPoints::ChangeBreakPointRemoveCond(cpu, bp.addr);
|
{
|
||||||
|
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), bp] {
|
||||||
|
CBreakPoints::ChangeBreakPointRemoveCond(cpu, bp->addr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PostfixExpression expr;
|
||||||
|
|
||||||
|
if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(nullptr, "Condition Error", QString(getExpressionError()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BreakPointCond cond;
|
||||||
|
cond.debug = &m_cpu;
|
||||||
|
cond.expression = expr;
|
||||||
|
cond.expressionString = condValue.toStdString();
|
||||||
|
|
||||||
|
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), bp, cond] {
|
||||||
|
CBreakPoints::ChangeBreakPointAddCond(cpu, bp->addr, cond);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (auto* mc = std::get_if<MemCheck>(&bp_mc))
|
||||||
{
|
{
|
||||||
PostfixExpression expr;
|
const QString condValue = value.toString();
|
||||||
|
|
||||||
if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr))
|
if (condValue.isEmpty())
|
||||||
{
|
{
|
||||||
QMessageBox::warning(nullptr, "Condition Error", QString(getExpressionError()));
|
if (mc->hasCond)
|
||||||
return false;
|
{
|
||||||
|
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), mc] {
|
||||||
|
CBreakPoints::ChangeMemCheckRemoveCond(cpu, mc->start, mc->end);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PostfixExpression expr;
|
||||||
|
|
||||||
BreakPointCond cond;
|
if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr))
|
||||||
cond.debug = &m_cpu;
|
{
|
||||||
cond.expression = expr;
|
QMessageBox::warning(nullptr, "Condition Error", QString(getExpressionError()));
|
||||||
strcpy(&cond.expressionString[0], condValue.toLocal8Bit().constData());
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), bp, cond] {
|
BreakPointCond cond;
|
||||||
CBreakPoints::ChangeBreakPointAddCond(cpu, bp.addr, cond);
|
cond.debug = &m_cpu;
|
||||||
});
|
cond.expression = expr;
|
||||||
|
cond.expressionString = condValue.toStdString();
|
||||||
|
|
||||||
|
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), mc, cond] {
|
||||||
|
CBreakPoints::ChangeMemCheckAddCond(cpu, mc->start, mc->end, cond);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
emit dataChanged(index, index);
|
emit dataChanged(index, index);
|
||||||
return true;
|
return true;
|
||||||
|
@ -401,7 +430,11 @@ bool BreakpointModel::insertBreakpointRows(int row, int count, std::vector<Break
|
||||||
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
|
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
|
||||||
{
|
{
|
||||||
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), mc = *mc] {
|
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), mc = *mc] {
|
||||||
CBreakPoints::AddMemCheck(cpu, mc.start, mc.end, mc.cond, mc.result);
|
CBreakPoints::AddMemCheck(cpu, mc.start, mc.end, mc.memCond, mc.result);
|
||||||
|
if (mc.hasCond)
|
||||||
|
{
|
||||||
|
CBreakPoints::ChangeMemCheckAddCond(cpu, mc.start, mc.end, mc.cond);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -413,18 +446,15 @@ bool BreakpointModel::insertBreakpointRows(int row, int count, std::vector<Break
|
||||||
void BreakpointModel::refreshData()
|
void BreakpointModel::refreshData()
|
||||||
{
|
{
|
||||||
Host::RunOnCPUThread([this]() mutable {
|
Host::RunOnCPUThread([this]() mutable {
|
||||||
|
|
||||||
std::vector<BreakpointMemcheck> all_breakpoints;
|
std::vector<BreakpointMemcheck> all_breakpoints;
|
||||||
std::ranges::move(CBreakPoints::GetBreakpoints(m_cpu.getCpuType(), false), std::back_inserter(all_breakpoints));
|
std::ranges::move(CBreakPoints::GetBreakpoints(m_cpu.getCpuType(), false), std::back_inserter(all_breakpoints));
|
||||||
std::ranges::move(CBreakPoints::GetMemChecks(m_cpu.getCpuType()), std::back_inserter(all_breakpoints));
|
std::ranges::move(CBreakPoints::GetMemChecks(m_cpu.getCpuType()), std::back_inserter(all_breakpoints));
|
||||||
|
|
||||||
QtHost::RunOnUIThread([this, breakpoints = std::move(all_breakpoints)]() mutable {
|
QtHost::RunOnUIThread([this, breakpoints = std::move(all_breakpoints)]() mutable {
|
||||||
|
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_breakpoints = std::move(breakpoints);
|
m_breakpoints = std::move(breakpoints);
|
||||||
endResetModel();
|
endResetModel();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,7 +500,7 @@ void BreakpointModel::loadBreakpointFromFieldList(QStringList fields)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bp.cond.expression = expr;
|
bp.cond.expression = expr;
|
||||||
strncpy(&bp.cond.expressionString[0], fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), sizeof(bp.cond.expressionString));
|
bp.cond.expressionString = fields[BreakpointModel::BreakpointColumns::CONDITION].toStdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enabled
|
// Enabled
|
||||||
|
@ -492,7 +522,7 @@ void BreakpointModel::loadBreakpointFromFieldList(QStringList fields)
|
||||||
Console.WriteLn("Debugger Breakpoint Model: Failed to parse cond type '%s', skipping", fields[BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData());
|
Console.WriteLn("Debugger Breakpoint Model: Failed to parse cond type '%s', skipping", fields[BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mc.cond = static_cast<MemCheckCondition>(type);
|
mc.memCond = static_cast<MemCheckCondition>(type);
|
||||||
|
|
||||||
// Address
|
// Address
|
||||||
QString test = fields[BreakpointModel::BreakpointColumns::OFFSET];
|
QString test = fields[BreakpointModel::BreakpointColumns::OFFSET];
|
||||||
|
@ -511,6 +541,22 @@ void BreakpointModel::loadBreakpointFromFieldList(QStringList fields)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Condition
|
||||||
|
if (!fields[BreakpointModel::BreakpointColumns::CONDITION].isEmpty())
|
||||||
|
{
|
||||||
|
PostfixExpression expr;
|
||||||
|
mc.hasCond = true;
|
||||||
|
mc.cond.debug = &m_cpu;
|
||||||
|
|
||||||
|
if (!m_cpu.initExpression(fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), expr))
|
||||||
|
{
|
||||||
|
Console.WriteLn("Debugger Breakpoint Model: Failed to parse cond '%s', skipping", fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mc.cond.expression = expr;
|
||||||
|
mc.cond.expressionString = fields[BreakpointModel::BreakpointColumns::CONDITION].toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
// Result
|
// Result
|
||||||
const int result = fields[BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok);
|
const int result = fields[BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
|
|
|
@ -38,7 +38,8 @@ u32 standardizeBreakpointAddress(u32 addr)
|
||||||
MemCheck::MemCheck()
|
MemCheck::MemCheck()
|
||||||
: start(0)
|
: start(0)
|
||||||
, end(0)
|
, end(0)
|
||||||
, cond(MEMCHECK_READWRITE)
|
, hasCond(false)
|
||||||
|
, memCond(MEMCHECK_READWRITE)
|
||||||
, result(MEMCHECK_BOTH)
|
, result(MEMCHECK_BOTH)
|
||||||
, cpu(BREAKPOINT_EE)
|
, cpu(BREAKPOINT_EE)
|
||||||
, numHits(0)
|
, numHits(0)
|
||||||
|
@ -55,15 +56,15 @@ void MemCheck::Log(u32 addr, bool write, int size, u32 pc)
|
||||||
void MemCheck::Action(u32 addr, bool write, int size, u32 pc)
|
void MemCheck::Action(u32 addr, bool write, int size, u32 pc)
|
||||||
{
|
{
|
||||||
int mask = write ? MEMCHECK_WRITE : MEMCHECK_READ;
|
int mask = write ? MEMCHECK_WRITE : MEMCHECK_READ;
|
||||||
if (cond & mask)
|
if (memCond & mask)
|
||||||
{
|
{
|
||||||
++numHits;
|
++numHits;
|
||||||
|
|
||||||
Log(addr, write, size, pc);
|
Log(addr, write, size, pc);
|
||||||
if (result & MEMCHECK_BREAK)
|
if (result & MEMCHECK_BREAK)
|
||||||
{
|
{
|
||||||
// Core_EnableStepping(true);
|
// Core_EnableStepping(true);
|
||||||
// host->SetDebugMode(true);
|
// host->SetDebugMode(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +72,7 @@ void MemCheck::Action(u32 addr, bool write, int size, u32 pc)
|
||||||
void MemCheck::JitBefore(u32 addr, bool write, int size, u32 pc)
|
void MemCheck::JitBefore(u32 addr, bool write, int size, u32 pc)
|
||||||
{
|
{
|
||||||
int mask = MEMCHECK_WRITE | MEMCHECK_WRITE_ONCHANGE;
|
int mask = MEMCHECK_WRITE | MEMCHECK_WRITE_ONCHANGE;
|
||||||
if (write && (cond & mask) == mask)
|
if (write && (memCond & mask) == mask)
|
||||||
{
|
{
|
||||||
lastAddr = addr;
|
lastAddr = addr;
|
||||||
lastPC = pc;
|
lastPC = pc;
|
||||||
|
@ -157,7 +158,7 @@ bool CBreakPoints::IsAddressBreakPoint(BreakPointCpu cpu, u32 addr)
|
||||||
|
|
||||||
bool CBreakPoints::IsAddressBreakPoint(BreakPointCpu cpu, u32 addr, bool* enabled)
|
bool CBreakPoints::IsAddressBreakPoint(BreakPointCpu cpu, u32 addr, bool* enabled)
|
||||||
{
|
{
|
||||||
size_t bp = FindBreakpoint(cpu, addr);
|
const size_t bp = FindBreakpoint(cpu, addr);
|
||||||
if (bp == INVALID_BREAKPOINT)
|
if (bp == INVALID_BREAKPOINT)
|
||||||
return false;
|
return false;
|
||||||
if (enabled != NULL)
|
if (enabled != NULL)
|
||||||
|
@ -167,13 +168,13 @@ bool CBreakPoints::IsAddressBreakPoint(BreakPointCpu cpu, u32 addr, bool* enable
|
||||||
|
|
||||||
bool CBreakPoints::IsTempBreakPoint(BreakPointCpu cpu, u32 addr)
|
bool CBreakPoints::IsTempBreakPoint(BreakPointCpu cpu, u32 addr)
|
||||||
{
|
{
|
||||||
size_t bp = FindBreakpoint(cpu, addr, true, true);
|
const size_t bp = FindBreakpoint(cpu, addr, true, true);
|
||||||
return bp != INVALID_BREAKPOINT;
|
return bp != INVALID_BREAKPOINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBreakPoints::AddBreakPoint(BreakPointCpu cpu, u32 addr, bool temp, bool enabled)
|
void CBreakPoints::AddBreakPoint(BreakPointCpu cpu, u32 addr, bool temp, bool enabled)
|
||||||
{
|
{
|
||||||
size_t bp = FindBreakpoint(cpu, addr, true, temp);
|
const size_t bp = FindBreakpoint(cpu, addr, true, temp);
|
||||||
if (bp == INVALID_BREAKPOINT)
|
if (bp == INVALID_BREAKPOINT)
|
||||||
{
|
{
|
||||||
BreakPoint pt;
|
BreakPoint pt;
|
||||||
|
@ -211,7 +212,7 @@ void CBreakPoints::RemoveBreakPoint(BreakPointCpu cpu, u32 addr)
|
||||||
|
|
||||||
void CBreakPoints::ChangeBreakPoint(BreakPointCpu cpu, u32 addr, bool status)
|
void CBreakPoints::ChangeBreakPoint(BreakPointCpu cpu, u32 addr, bool status)
|
||||||
{
|
{
|
||||||
size_t bp = FindBreakpoint(cpu, addr);
|
const size_t bp = FindBreakpoint(cpu, addr);
|
||||||
if (bp != INVALID_BREAKPOINT)
|
if (bp != INVALID_BREAKPOINT)
|
||||||
{
|
{
|
||||||
breakPoints_[bp].enabled = status;
|
breakPoints_[bp].enabled = status;
|
||||||
|
@ -245,7 +246,7 @@ void CBreakPoints::ClearTemporaryBreakPoints()
|
||||||
|
|
||||||
void CBreakPoints::ChangeBreakPointAddCond(BreakPointCpu cpu, u32 addr, const BreakPointCond& cond)
|
void CBreakPoints::ChangeBreakPointAddCond(BreakPointCpu cpu, u32 addr, const BreakPointCond& cond)
|
||||||
{
|
{
|
||||||
size_t bp = FindBreakpoint(cpu, addr, true, false);
|
const size_t bp = FindBreakpoint(cpu, addr, true, false);
|
||||||
if (bp != INVALID_BREAKPOINT)
|
if (bp != INVALID_BREAKPOINT)
|
||||||
{
|
{
|
||||||
breakPoints_[bp].hasCond = true;
|
breakPoints_[bp].hasCond = true;
|
||||||
|
@ -256,7 +257,7 @@ void CBreakPoints::ChangeBreakPointAddCond(BreakPointCpu cpu, u32 addr, const Br
|
||||||
|
|
||||||
void CBreakPoints::ChangeBreakPointRemoveCond(BreakPointCpu cpu, u32 addr)
|
void CBreakPoints::ChangeBreakPointRemoveCond(BreakPointCpu cpu, u32 addr)
|
||||||
{
|
{
|
||||||
size_t bp = FindBreakpoint(cpu, addr, true, false);
|
const size_t bp = FindBreakpoint(cpu, addr, true, false);
|
||||||
if (bp != INVALID_BREAKPOINT)
|
if (bp != INVALID_BREAKPOINT)
|
||||||
{
|
{
|
||||||
breakPoints_[bp].hasCond = false;
|
breakPoints_[bp].hasCond = false;
|
||||||
|
@ -282,13 +283,13 @@ void CBreakPoints::AddMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCo
|
||||||
// This will ruin any pending memchecks.
|
// This will ruin any pending memchecks.
|
||||||
cleanupMemChecks_.clear();
|
cleanupMemChecks_.clear();
|
||||||
|
|
||||||
size_t mc = FindMemCheck(cpu, start, end);
|
const size_t mc = FindMemCheck(cpu, start, end);
|
||||||
if (mc == INVALID_MEMCHECK)
|
if (mc == INVALID_MEMCHECK)
|
||||||
{
|
{
|
||||||
MemCheck check;
|
MemCheck check;
|
||||||
check.start = start;
|
check.start = start;
|
||||||
check.end = end;
|
check.end = end;
|
||||||
check.cond = cond;
|
check.memCond = cond;
|
||||||
check.result = result;
|
check.result = result;
|
||||||
check.cpu = cpu;
|
check.cpu = cpu;
|
||||||
|
|
||||||
|
@ -297,7 +298,7 @@ void CBreakPoints::AddMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCo
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memChecks_[mc].cond = (MemCheckCondition)(memChecks_[mc].cond | cond);
|
memChecks_[mc].memCond = (MemCheckCondition)(memChecks_[mc].memCond | cond);
|
||||||
memChecks_[mc].result = (MemCheckResult)(memChecks_[mc].result | result);
|
memChecks_[mc].result = (MemCheckResult)(memChecks_[mc].result | result);
|
||||||
Update(cpu);
|
Update(cpu);
|
||||||
}
|
}
|
||||||
|
@ -308,7 +309,7 @@ void CBreakPoints::RemoveMemCheck(BreakPointCpu cpu, u32 start, u32 end)
|
||||||
// This will ruin any pending memchecks.
|
// This will ruin any pending memchecks.
|
||||||
cleanupMemChecks_.clear();
|
cleanupMemChecks_.clear();
|
||||||
|
|
||||||
size_t mc = FindMemCheck(cpu, start, end);
|
const size_t mc = FindMemCheck(cpu, start, end);
|
||||||
if (mc != INVALID_MEMCHECK)
|
if (mc != INVALID_MEMCHECK)
|
||||||
{
|
{
|
||||||
memChecks_.erase(memChecks_.begin() + mc);
|
memChecks_.erase(memChecks_.begin() + mc);
|
||||||
|
@ -318,15 +319,36 @@ void CBreakPoints::RemoveMemCheck(BreakPointCpu cpu, u32 start, u32 end)
|
||||||
|
|
||||||
void CBreakPoints::ChangeMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result)
|
void CBreakPoints::ChangeMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result)
|
||||||
{
|
{
|
||||||
size_t mc = FindMemCheck(cpu, start, end);
|
const size_t mc = FindMemCheck(cpu, start, end);
|
||||||
if (mc != INVALID_MEMCHECK)
|
if (mc != INVALID_MEMCHECK)
|
||||||
{
|
{
|
||||||
memChecks_[mc].cond = cond;
|
memChecks_[mc].memCond = cond;
|
||||||
memChecks_[mc].result = result;
|
memChecks_[mc].result = result;
|
||||||
Update(cpu);
|
Update(cpu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CBreakPoints::ChangeMemCheckRemoveCond(BreakPointCpu cpu, u32 start, u32 end)
|
||||||
|
{
|
||||||
|
const size_t mc = FindMemCheck(cpu, start, end);
|
||||||
|
if (mc != INVALID_MEMCHECK)
|
||||||
|
{
|
||||||
|
memChecks_[mc].hasCond = false;
|
||||||
|
Update(cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBreakPoints::ChangeMemCheckAddCond(BreakPointCpu cpu, u32 start, u32 end, const BreakPointCond& cond)
|
||||||
|
{
|
||||||
|
const size_t mc = FindMemCheck(cpu, start, end);
|
||||||
|
if (mc != INVALID_MEMCHECK)
|
||||||
|
{
|
||||||
|
memChecks_[mc].hasCond = true;
|
||||||
|
memChecks_[mc].cond = cond;
|
||||||
|
Update(cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CBreakPoints::ClearAllMemChecks()
|
void CBreakPoints::ClearAllMemChecks()
|
||||||
{
|
{
|
||||||
// This will ruin any pending memchecks.
|
// This will ruin any pending memchecks.
|
||||||
|
|
|
@ -12,29 +12,35 @@
|
||||||
|
|
||||||
struct BreakPointCond
|
struct BreakPointCond
|
||||||
{
|
{
|
||||||
DebugInterface *debug;
|
DebugInterface* debug;
|
||||||
PostfixExpression expression;
|
PostfixExpression expression;
|
||||||
char expressionString[128];
|
std::string expressionString;
|
||||||
|
|
||||||
BreakPointCond() : debug(NULL)
|
BreakPointCond()
|
||||||
|
: debug(NULL)
|
||||||
{
|
{
|
||||||
expressionString[0] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Evaluate()
|
u32 Evaluate()
|
||||||
{
|
{
|
||||||
u64 result;
|
u64 result;
|
||||||
if (!debug->parseExpression(expression,result) || result == 0) return 0;
|
if (!debug->parseExpression(expression, result) || result == 0)
|
||||||
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BreakPoint
|
struct BreakPoint
|
||||||
{
|
{
|
||||||
BreakPoint() : addr(0), enabled(false), temporary(false), hasCond(false)
|
BreakPoint()
|
||||||
{}
|
: addr(0)
|
||||||
|
, enabled(false)
|
||||||
|
, temporary(false)
|
||||||
|
, hasCond(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
u32 addr;
|
u32 addr;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
bool temporary;
|
bool temporary;
|
||||||
|
|
||||||
|
@ -42,10 +48,12 @@ struct BreakPoint
|
||||||
BreakPointCond cond;
|
BreakPointCond cond;
|
||||||
BreakPointCpu cpu;
|
BreakPointCpu cpu;
|
||||||
|
|
||||||
bool operator == (const BreakPoint &other) const {
|
bool operator==(const BreakPoint& other) const
|
||||||
|
{
|
||||||
return addr == other.addr;
|
return addr == other.addr;
|
||||||
}
|
}
|
||||||
bool operator < (const BreakPoint &other) const {
|
bool operator<(const BreakPoint& other) const
|
||||||
|
{
|
||||||
return addr < other.addr;
|
return addr < other.addr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -75,7 +83,9 @@ struct MemCheck
|
||||||
u32 start;
|
u32 start;
|
||||||
u32 end;
|
u32 end;
|
||||||
|
|
||||||
MemCheckCondition cond;
|
bool hasCond;
|
||||||
|
BreakPointCond cond;
|
||||||
|
MemCheckCondition memCond;
|
||||||
MemCheckResult result;
|
MemCheckResult result;
|
||||||
BreakPointCpu cpu;
|
BreakPointCpu cpu;
|
||||||
|
|
||||||
|
@ -91,7 +101,8 @@ struct MemCheck
|
||||||
|
|
||||||
void Log(u32 addr, bool write, int size, u32 pc);
|
void Log(u32 addr, bool write, int size, u32 pc);
|
||||||
|
|
||||||
bool operator == (const MemCheck &other) const {
|
bool operator==(const MemCheck& other) const
|
||||||
|
{
|
||||||
return start == other.start && end == other.end;
|
return start == other.start && end == other.end;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -115,13 +126,15 @@ public:
|
||||||
static void ClearTemporaryBreakPoints();
|
static void ClearTemporaryBreakPoints();
|
||||||
|
|
||||||
// Makes a copy. Temporary breakpoints can't have conditions.
|
// Makes a copy. Temporary breakpoints can't have conditions.
|
||||||
static void ChangeBreakPointAddCond(BreakPointCpu cpu, u32 addr, const BreakPointCond &cond);
|
static void ChangeBreakPointAddCond(BreakPointCpu cpu, u32 addr, const BreakPointCond& cond);
|
||||||
static void ChangeBreakPointRemoveCond(BreakPointCpu cpu, u32 addr);
|
static void ChangeBreakPointRemoveCond(BreakPointCpu cpu, u32 addr);
|
||||||
static BreakPointCond *GetBreakPointCondition(BreakPointCpu cpu, u32 addr);
|
static BreakPointCond* GetBreakPointCondition(BreakPointCpu cpu, u32 addr);
|
||||||
|
|
||||||
static void AddMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
|
static void AddMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
|
||||||
static void RemoveMemCheck(BreakPointCpu cpu, u32 start, u32 end);
|
static void RemoveMemCheck(BreakPointCpu cpu, u32 start, u32 end);
|
||||||
static void ChangeMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
|
static void ChangeMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
|
||||||
|
static void ChangeMemCheckRemoveCond(BreakPointCpu cpu, u32 start, u32 end);
|
||||||
|
static void ChangeMemCheckAddCond(BreakPointCpu cpu, u32 start, u32 end, const BreakPointCond& cond);
|
||||||
static void ClearAllMemChecks();
|
static void ClearAllMemChecks();
|
||||||
|
|
||||||
static void SetSkipFirst(BreakPointCpu cpu, u32 pc);
|
static void SetSkipFirst(BreakPointCpu cpu, u32 pc);
|
||||||
|
@ -135,14 +148,18 @@ public:
|
||||||
static const std::vector<BreakPoint> GetBreakpoints(BreakPointCpu cpu, bool includeTemp);
|
static const std::vector<BreakPoint> GetBreakpoints(BreakPointCpu cpu, bool includeTemp);
|
||||||
// Returns count of all non-temporary breakpoints
|
// Returns count of all non-temporary breakpoints
|
||||||
static size_t GetNumBreakpoints()
|
static size_t GetNumBreakpoints()
|
||||||
{
|
{
|
||||||
return std::count_if(breakPoints_.begin(), breakPoints_.end(), [](BreakPoint& bp) { return !bp.temporary; });
|
return std::count_if(breakPoints_.begin(), breakPoints_.end(), [](BreakPoint& bp) { return !bp.temporary; });
|
||||||
}
|
}
|
||||||
static size_t GetNumMemchecks() { return memChecks_.size(); }
|
static size_t GetNumMemchecks() { return memChecks_.size(); }
|
||||||
|
|
||||||
static void Update(BreakPointCpu cpu = BREAKPOINT_IOP_AND_EE, u32 addr = 0);
|
static void Update(BreakPointCpu cpu = BREAKPOINT_IOP_AND_EE, u32 addr = 0);
|
||||||
|
|
||||||
static void SetBreakpointTriggered(bool triggered, BreakPointCpu cpu = BreakPointCpu::BREAKPOINT_IOP_AND_EE) { breakpointTriggered_ = triggered; breakpointTriggeredCpu_ = cpu; };
|
static void SetBreakpointTriggered(bool triggered, BreakPointCpu cpu = BreakPointCpu::BREAKPOINT_IOP_AND_EE)
|
||||||
|
{
|
||||||
|
breakpointTriggered_ = triggered;
|
||||||
|
breakpointTriggeredCpu_ = cpu;
|
||||||
|
};
|
||||||
static bool GetBreakpointTriggered() { return breakpointTriggered_; };
|
static bool GetBreakpointTriggered() { return breakpointTriggered_; };
|
||||||
static BreakPointCpu GetBreakpointTriggeredCpu() { return breakpointTriggeredCpu_; };
|
static BreakPointCpu GetBreakpointTriggeredCpu() { return breakpointTriggeredCpu_; };
|
||||||
|
|
||||||
|
@ -165,7 +182,7 @@ private:
|
||||||
static bool corePaused;
|
static bool corePaused;
|
||||||
|
|
||||||
static std::vector<MemCheck> memChecks_;
|
static std::vector<MemCheck> memChecks_;
|
||||||
static std::vector<MemCheck *> cleanupMemChecks_;
|
static std::vector<MemCheck*> cleanupMemChecks_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -99,11 +99,17 @@ void intMemcheck(u32 op, u32 bits, bool store)
|
||||||
|
|
||||||
if (check.result == 0)
|
if (check.result == 0)
|
||||||
continue;
|
continue;
|
||||||
if ((check.cond & MEMCHECK_WRITE) == 0 && store)
|
if ((check.memCond & MEMCHECK_WRITE) == 0 && store)
|
||||||
continue;
|
continue;
|
||||||
if ((check.cond & MEMCHECK_READ) == 0 && !store)
|
if ((check.memCond & MEMCHECK_READ) == 0 && !store)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (check.hasCond)
|
||||||
|
{
|
||||||
|
if (!check.cond.Evaluate())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (start < check.end && check.start < end)
|
if (start < check.end && check.start < end)
|
||||||
intBreakpoint(true);
|
intBreakpoint(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,11 +150,17 @@ void psxMemcheck(u32 op, u32 bits, bool store)
|
||||||
|
|
||||||
if (check.result == 0)
|
if (check.result == 0)
|
||||||
continue;
|
continue;
|
||||||
if ((check.cond & MEMCHECK_WRITE) == 0 && store)
|
if ((check.memCond & MEMCHECK_WRITE) == 0 && store)
|
||||||
continue;
|
continue;
|
||||||
if ((check.cond & MEMCHECK_READ) == 0 && !store)
|
if ((check.memCond & MEMCHECK_READ) == 0 && !store)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (check.hasCond)
|
||||||
|
{
|
||||||
|
if (!check.cond.Evaluate())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (start < check.end && check.start < end)
|
if (start < check.end && check.start < end)
|
||||||
psxBreakpoint(true);
|
psxBreakpoint(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1302,12 +1302,30 @@ static bool psxDynarecCheckBreakpoint()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool psxDynarecMemcheck()
|
static bool psxDynarecMemcheck(size_t i)
|
||||||
{
|
{
|
||||||
u32 pc = psxRegs.pc;
|
const u32 pc = psxRegs.pc;
|
||||||
|
const u32 op = iopMemRead32(pc);
|
||||||
|
const R5900::OPCODE& opcode = R5900::GetInstruction(op);
|
||||||
|
auto mc = CBreakPoints::GetMemChecks(BREAKPOINT_IOP)[i];
|
||||||
|
|
||||||
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_IOP, pc) == pc)
|
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_IOP, pc) == pc)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (mc.hasCond)
|
||||||
|
{
|
||||||
|
if (!mc.cond.Evaluate())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mc.result & MEMCHECK_LOG)
|
||||||
|
{
|
||||||
|
if (opcode.flags & IS_STORE)
|
||||||
|
DevCon.WriteLn("Hit R3000 store breakpoint @0x%x", pc);
|
||||||
|
else
|
||||||
|
DevCon.WriteLn("Hit R3000 load breakpoint @0x%x", pc);
|
||||||
|
}
|
||||||
|
|
||||||
CBreakPoints::SetBreakpointTriggered(true, BREAKPOINT_IOP);
|
CBreakPoints::SetBreakpointTriggered(true, BREAKPOINT_IOP);
|
||||||
VMManager::SetPaused(true);
|
VMManager::SetPaused(true);
|
||||||
|
|
||||||
|
@ -1316,14 +1334,6 @@ static bool psxDynarecMemcheck()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void psxDynarecMemLogcheck(u32 start, bool store)
|
|
||||||
{
|
|
||||||
if (store)
|
|
||||||
DevCon.WriteLn("Hit store breakpoint @0x%x", start);
|
|
||||||
else
|
|
||||||
DevCon.WriteLn("Hit load breakpoint @0x%x", start);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void psxRecMemcheck(u32 op, u32 bits, bool store)
|
static void psxRecMemcheck(u32 op, u32 bits, bool store)
|
||||||
{
|
{
|
||||||
_psxFlushCall(FLUSH_EVERYTHING | FLUSH_PC);
|
_psxFlushCall(FLUSH_EVERYTHING | FLUSH_PC);
|
||||||
|
@ -1344,9 +1354,9 @@ static void psxRecMemcheck(u32 op, u32 bits, bool store)
|
||||||
{
|
{
|
||||||
if (checks[i].result == 0)
|
if (checks[i].result == 0)
|
||||||
continue;
|
continue;
|
||||||
if ((checks[i].cond & MEMCHECK_WRITE) == 0 && store)
|
if ((checks[i].memCond & MEMCHECK_WRITE) == 0 && store)
|
||||||
continue;
|
continue;
|
||||||
if ((checks[i].cond & MEMCHECK_READ) == 0 && !store)
|
if ((checks[i].memCond & MEMCHECK_READ) == 0 && !store)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// logic: memAddress < bpEnd && bpStart < memAddress+memSize
|
// logic: memAddress < bpEnd && bpStart < memAddress+memSize
|
||||||
|
@ -1360,25 +1370,11 @@ static void psxRecMemcheck(u32 op, u32 bits, bool store)
|
||||||
xForwardJGE8 next2; // if start >= address+size then goto next2
|
xForwardJGE8 next2; // if start >= address+size then goto next2
|
||||||
|
|
||||||
// hit the breakpoint
|
// hit the breakpoint
|
||||||
if (checks[i].result & MEMCHECK_LOG)
|
|
||||||
{
|
|
||||||
xMOV(edx, store);
|
|
||||||
|
|
||||||
// Refer to the EE recompiler for an explaination
|
|
||||||
if(!(checks[i].result & MEMCHECK_BREAK))
|
|
||||||
{
|
|
||||||
xPUSH(eax); xPUSH(ebx); xPUSH(ecx); xPUSH(edx);
|
|
||||||
xFastCall((void*)psxDynarecMemLogcheck, ecx, edx);
|
|
||||||
xPOP(edx); xPOP(ecx); xPOP(ebx); xPOP(eax);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
xFastCall((void*)psxDynarecMemLogcheck, ecx, edx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (checks[i].result & MEMCHECK_BREAK)
|
if (checks[i].result & MEMCHECK_BREAK)
|
||||||
{
|
{
|
||||||
xFastCall((void*)psxDynarecMemcheck);
|
xMOV(eax, i);
|
||||||
|
xFastCall((void*)psxDynarecMemcheck, eax);
|
||||||
xTEST(al, al);
|
xTEST(al, al);
|
||||||
xJNZ(iopExitRecompiledCode);
|
xJNZ(iopExitRecompiledCode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1535,25 +1535,34 @@ void dynarecCheckBreakpoint()
|
||||||
recExitExecution();
|
recExitExecution();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dynarecMemcheck()
|
void dynarecMemcheck(size_t i)
|
||||||
{
|
{
|
||||||
const u32 pc = cpuRegs.pc;
|
const u32 op = memRead32(cpuRegs.pc);
|
||||||
|
const OPCODE& opcode = GetInstruction(op);
|
||||||
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_EE, pc) != 0)
|
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_EE, pc) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
auto mc = CBreakPoints::GetMemChecks(BREAKPOINT_EE)[i];
|
||||||
|
|
||||||
|
if(mc.hasCond)
|
||||||
|
{
|
||||||
|
if (!mc.cond.Evaluate())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mc.result & MEMCHECK_LOG)
|
||||||
|
{
|
||||||
|
if (opcode.flags & IS_STORE)
|
||||||
|
DevCon.WriteLn("Hit store breakpoint @0x%x", cpuRegs.pc);
|
||||||
|
else
|
||||||
|
DevCon.WriteLn("Hit load breakpoint @0x%x", cpuRegs.pc);
|
||||||
|
}
|
||||||
|
|
||||||
CBreakPoints::SetBreakpointTriggered(true, BREAKPOINT_EE);
|
CBreakPoints::SetBreakpointTriggered(true, BREAKPOINT_EE);
|
||||||
VMManager::SetPaused(true);
|
VMManager::SetPaused(true);
|
||||||
recExitExecution();
|
recExitExecution();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dynarecMemLogcheck(u32 start, bool store)
|
|
||||||
{
|
|
||||||
if (store)
|
|
||||||
DevCon.WriteLn("Hit store breakpoint @0x%x", start);
|
|
||||||
else
|
|
||||||
DevCon.WriteLn("Hit load breakpoint @0x%x", start);
|
|
||||||
}
|
|
||||||
|
|
||||||
void recMemcheck(u32 op, u32 bits, bool store)
|
void recMemcheck(u32 op, u32 bits, bool store)
|
||||||
{
|
{
|
||||||
iFlushCall(FLUSH_EVERYTHING | FLUSH_PC);
|
iFlushCall(FLUSH_EVERYTHING | FLUSH_PC);
|
||||||
|
@ -1578,9 +1587,9 @@ void recMemcheck(u32 op, u32 bits, bool store)
|
||||||
{
|
{
|
||||||
if (checks[i].result == 0)
|
if (checks[i].result == 0)
|
||||||
continue;
|
continue;
|
||||||
if ((checks[i].cond & MEMCHECK_WRITE) == 0 && store)
|
if ((checks[i].memCond & MEMCHECK_WRITE) == 0 && store)
|
||||||
continue;
|
continue;
|
||||||
if ((checks[i].cond & MEMCHECK_READ) == 0 && !store)
|
if ((checks[i].memCond & MEMCHECK_READ) == 0 && !store)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// logic: memAddress < bpEnd && bpStart < memAddress+memSize
|
// logic: memAddress < bpEnd && bpStart < memAddress+memSize
|
||||||
|
@ -1594,33 +1603,10 @@ void recMemcheck(u32 op, u32 bits, bool store)
|
||||||
xForwardJGE8 next2; // if start >= address+size then goto next2
|
xForwardJGE8 next2; // if start >= address+size then goto next2
|
||||||
|
|
||||||
// hit the breakpoint
|
// hit the breakpoint
|
||||||
if (checks[i].result & MEMCHECK_LOG)
|
|
||||||
{
|
|
||||||
xMOV(edx, store);
|
|
||||||
// Preserve ecx (address) and edx (address+size) because we aren't breaking
|
|
||||||
// out of this loops iteration and dynarecMemLogcheck will clobber them
|
|
||||||
// Also keep 16 byte stack alignment
|
|
||||||
if (!(checks[i].result & MEMCHECK_BREAK))
|
|
||||||
{
|
|
||||||
xPUSH(eax);
|
|
||||||
xPUSH(ebx);
|
|
||||||
xPUSH(ecx);
|
|
||||||
xPUSH(edx);
|
|
||||||
xFastCall((void*)dynarecMemLogcheck, ecx, edx);
|
|
||||||
xPOP(edx);
|
|
||||||
xPOP(ecx);
|
|
||||||
xPOP(ebx);
|
|
||||||
xPOP(eax);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
xFastCall((void*)dynarecMemLogcheck, ecx, edx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (checks[i].result & MEMCHECK_BREAK)
|
if (checks[i].result & MEMCHECK_BREAK)
|
||||||
{
|
{
|
||||||
// Don't need to preserve edx and ecx, we don't return
|
xMOV(eax, i);
|
||||||
xFastCall((void*)dynarecMemcheck);
|
xFastCall((void*)dynarecMemcheck, eax);
|
||||||
}
|
}
|
||||||
|
|
||||||
next1.SetTarget();
|
next1.SetTarget();
|
||||||
|
|
Loading…
Reference in New Issue