mirror of https://github.com/PCSX2/pcsx2.git
Debugger: Bring back the expression parser
This commit is contained in:
parent
f340b5ebd0
commit
90463a4a6c
|
@ -93,10 +93,9 @@ void BreakpointDialog::accept()
|
||||||
PostfixExpression expr;
|
PostfixExpression expr;
|
||||||
|
|
||||||
u64 address;
|
u64 address;
|
||||||
if (!m_cpu->initExpression(m_ui.txtAddress->text().toLocal8Bit().constData(), expr) ||
|
if (!m_cpu->evaluateExpression(m_ui.txtAddress->text().toStdString().c_str(), address))
|
||||||
!m_cpu->parseExpression(expr, address))
|
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Error"), tr("Invalid address \"%1\"").arg(m_ui.txtAddress->text()));
|
QMessageBox::warning(this, tr("Invalid Address"), getExpressionError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,9 +108,9 @@ void BreakpointDialog::accept()
|
||||||
bp->hasCond = true;
|
bp->hasCond = true;
|
||||||
bp->cond.debug = m_cpu;
|
bp->cond.debug = m_cpu;
|
||||||
|
|
||||||
if (!m_cpu->initExpression(m_ui.txtCondition->text().toLocal8Bit().constData(), expr))
|
if (!m_cpu->initExpression(m_ui.txtCondition->text().toStdString().c_str(), expr))
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Error"), tr("Invalid condition \"%1\"").arg(getExpressionError()));
|
QMessageBox::warning(this, tr("Invalid Condition"), getExpressionError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,21 +120,17 @@ void BreakpointDialog::accept()
|
||||||
}
|
}
|
||||||
if (auto* mc = std::get_if<MemCheck>(&m_bp_mc))
|
if (auto* mc = std::get_if<MemCheck>(&m_bp_mc))
|
||||||
{
|
{
|
||||||
PostfixExpression expr;
|
|
||||||
|
|
||||||
u64 startAddress;
|
u64 startAddress;
|
||||||
if (!m_cpu->initExpression(m_ui.txtAddress->text().toLocal8Bit().constData(), expr) ||
|
if (!m_cpu->evaluateExpression(m_ui.txtAddress->text().toStdString().c_str(), startAddress))
|
||||||
!m_cpu->parseExpression(expr, startAddress))
|
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Error"), tr("Invalid address \"%1\"").arg(m_ui.txtAddress->text()));
|
QMessageBox::warning(this, tr("Invalid Address"), getExpressionError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 size;
|
u64 size;
|
||||||
if (!m_cpu->initExpression(m_ui.txtSize->text().toLocal8Bit(), expr) ||
|
if (!m_cpu->evaluateExpression(m_ui.txtSize->text().toStdString().c_str(), size) || !size)
|
||||||
!m_cpu->parseExpression(expr, size) || !size)
|
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Error"), tr("Invalid size \"%1\"").arg(m_ui.txtSize->text()));
|
QMessageBox::warning(this, tr("Invalid Size"), getExpressionError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,9 +142,10 @@ void BreakpointDialog::accept()
|
||||||
mc->hasCond = true;
|
mc->hasCond = true;
|
||||||
mc->cond.debug = m_cpu;
|
mc->cond.debug = m_cpu;
|
||||||
|
|
||||||
if (!m_cpu->initExpression(m_ui.txtCondition->text().toLocal8Bit().constData(), expr))
|
PostfixExpression expr;
|
||||||
|
if (!m_cpu->initExpression(m_ui.txtCondition->text().toStdString().c_str(), expr))
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Error"), tr("Invalid condition \"%1\"").arg(getExpressionError()));
|
QMessageBox::warning(this, tr("Invalid Condition"), getExpressionError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,21 +163,20 @@ void DisassemblyWidget::contextFollowBranch()
|
||||||
void DisassemblyWidget::contextGoToAddress()
|
void DisassemblyWidget::contextGoToAddress()
|
||||||
{
|
{
|
||||||
bool ok;
|
bool ok;
|
||||||
const QString targetString = QInputDialog::getText(this, tr("Go to address"), "",
|
const QString targetString = QInputDialog::getText(this, tr("Go To In Disassembly"), "",
|
||||||
QLineEdit::Normal, "", &ok);
|
QLineEdit::Normal, "", &ok);
|
||||||
|
|
||||||
if (!ok)
|
if (!ok)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const u32 targetAddress = targetString.toUInt(&ok, 16) & ~3;
|
u64 address = 0;
|
||||||
|
if (!m_cpu->evaluateExpression(targetString.toStdString().c_str(), address))
|
||||||
if (!ok)
|
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Go to address error"), tr("Invalid address"));
|
QMessageBox::warning(this, tr("Cannot Go To"), getExpressionError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gotoAddressAndSetFocus(targetAddress);
|
gotoAddressAndSetFocus(static_cast<u32>(address) & ~3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassemblyWidget::contextAddFunction()
|
void DisassemblyWidget::contextAddFunction()
|
||||||
|
|
|
@ -592,21 +592,20 @@ void MemoryViewWidget::contextPaste()
|
||||||
void MemoryViewWidget::contextGoToAddress()
|
void MemoryViewWidget::contextGoToAddress()
|
||||||
{
|
{
|
||||||
bool ok;
|
bool ok;
|
||||||
QString targetString = QInputDialog::getText(this, tr("Go to address"), "",
|
QString targetString = QInputDialog::getText(this, tr("Go To In Memory View"), "",
|
||||||
QLineEdit::Normal, "", &ok);
|
QLineEdit::Normal, "", &ok);
|
||||||
|
|
||||||
if (!ok)
|
if (!ok)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const u32 targetAddress = targetString.toUInt(&ok, 16);
|
u64 address = 0;
|
||||||
|
if (!m_cpu->evaluateExpression(targetString.toStdString().c_str(), address))
|
||||||
if (!ok)
|
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, "Go to address error", "Invalid address");
|
QMessageBox::warning(this, tr("Cannot Go To"), getExpressionError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gotoAddress(targetAddress);
|
gotoAddress(static_cast<u32>(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryViewWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
void MemoryViewWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
||||||
|
|
|
@ -25,6 +25,7 @@ public:
|
||||||
Tag tag = OBJECT;
|
Tag tag = OBJECT;
|
||||||
ccc::MultiSymbolHandle symbol;
|
ccc::MultiSymbolHandle symbol;
|
||||||
QString name;
|
QString name;
|
||||||
|
QString mangled_name;
|
||||||
SymbolTreeLocation location;
|
SymbolTreeLocation location;
|
||||||
bool is_location_editable = false;
|
bool is_location_editable = false;
|
||||||
std::optional<u32> size;
|
std::optional<u32> size;
|
||||||
|
|
|
@ -362,6 +362,13 @@ void SymbolTreeWidget::setupMenu()
|
||||||
connect(copy_name, &QAction::triggered, this, &SymbolTreeWidget::onCopyName);
|
connect(copy_name, &QAction::triggered, this, &SymbolTreeWidget::onCopyName);
|
||||||
m_context_menu->addAction(copy_name);
|
m_context_menu->addAction(copy_name);
|
||||||
|
|
||||||
|
if (m_flags & ALLOW_MANGLED_NAME_ACTIONS)
|
||||||
|
{
|
||||||
|
QAction* copy_mangled_name = new QAction(tr("Copy Mangled Name"), this);
|
||||||
|
connect(copy_mangled_name, &QAction::triggered, this, &SymbolTreeWidget::onCopyMangledName);
|
||||||
|
m_context_menu->addAction(copy_mangled_name);
|
||||||
|
}
|
||||||
|
|
||||||
QAction* copy_location = new QAction(tr("Copy Location"), this);
|
QAction* copy_location = new QAction(tr("Copy Location"), this);
|
||||||
connect(copy_location, &QAction::triggered, this, &SymbolTreeWidget::onCopyLocation);
|
connect(copy_location, &QAction::triggered, this, &SymbolTreeWidget::onCopyLocation);
|
||||||
m_context_menu->addAction(copy_location);
|
m_context_menu->addAction(copy_location);
|
||||||
|
@ -484,6 +491,18 @@ void SymbolTreeWidget::onCopyName()
|
||||||
QApplication::clipboard()->setText(node->name);
|
QApplication::clipboard()->setText(node->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SymbolTreeWidget::onCopyMangledName()
|
||||||
|
{
|
||||||
|
SymbolTreeNode* node = currentNode();
|
||||||
|
if (!node)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!node->mangled_name.isEmpty())
|
||||||
|
QApplication::clipboard()->setText(node->mangled_name);
|
||||||
|
else
|
||||||
|
QApplication::clipboard()->setText(node->name);
|
||||||
|
}
|
||||||
|
|
||||||
void SymbolTreeWidget::onCopyLocation()
|
void SymbolTreeWidget::onCopyLocation()
|
||||||
{
|
{
|
||||||
SymbolTreeNode* node = currentNode();
|
SymbolTreeNode* node = currentNode();
|
||||||
|
@ -611,7 +630,7 @@ SymbolTreeNode* SymbolTreeWidget::currentNode()
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
|
|
||||||
FunctionTreeWidget::FunctionTreeWidget(DebugInterface& cpu, QWidget* parent)
|
FunctionTreeWidget::FunctionTreeWidget(DebugInterface& cpu, QWidget* parent)
|
||||||
: SymbolTreeWidget(ALLOW_GROUPING, 4, cpu, parent)
|
: SymbolTreeWidget(ALLOW_GROUPING | ALLOW_MANGLED_NAME_ACTIONS, 4, cpu, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,6 +671,7 @@ std::unique_ptr<SymbolTreeNode> FunctionTreeWidget::buildNode(
|
||||||
|
|
||||||
std::unique_ptr<SymbolTreeNode> node = std::make_unique<SymbolTreeNode>();
|
std::unique_ptr<SymbolTreeNode> node = std::make_unique<SymbolTreeNode>();
|
||||||
node->name = std::move(work.name);
|
node->name = std::move(work.name);
|
||||||
|
node->mangled_name = QString::fromStdString(function.mangled_name());
|
||||||
node->location = SymbolTreeLocation(SymbolTreeLocation::MEMORY, function.address().value);
|
node->location = SymbolTreeLocation(SymbolTreeLocation::MEMORY, function.address().value);
|
||||||
node->size = function.size();
|
node->size = function.size();
|
||||||
node->symbol = ccc::MultiSymbolHandle(function);
|
node->symbol = ccc::MultiSymbolHandle(function);
|
||||||
|
@ -694,7 +714,7 @@ void FunctionTreeWidget::onNewButtonPressed()
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
|
|
||||||
GlobalVariableTreeWidget::GlobalVariableTreeWidget(DebugInterface& cpu, QWidget* parent)
|
GlobalVariableTreeWidget::GlobalVariableTreeWidget(DebugInterface& cpu, QWidget* parent)
|
||||||
: SymbolTreeWidget(ALLOW_GROUPING | ALLOW_SORTING_BY_IF_TYPE_IS_KNOWN | ALLOW_TYPE_ACTIONS, 1, cpu, parent)
|
: SymbolTreeWidget(ALLOW_GROUPING | ALLOW_SORTING_BY_IF_TYPE_IS_KNOWN | ALLOW_TYPE_ACTIONS | ALLOW_MANGLED_NAME_ACTIONS, 1, cpu, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -777,6 +797,7 @@ std::unique_ptr<SymbolTreeNode> GlobalVariableTreeWidget::buildNode(
|
||||||
{
|
{
|
||||||
const ccc::GlobalVariable& global_variable = static_cast<const ccc::GlobalVariable&>(*work.symbol);
|
const ccc::GlobalVariable& global_variable = static_cast<const ccc::GlobalVariable&>(*work.symbol);
|
||||||
|
|
||||||
|
node->mangled_name = QString::fromStdString(global_variable.mangled_name());
|
||||||
if (global_variable.type())
|
if (global_variable.type())
|
||||||
node->type = ccc::NodeHandle(global_variable, global_variable.type());
|
node->type = ccc::NodeHandle(global_variable, global_variable.type());
|
||||||
node->location = SymbolTreeLocation(SymbolTreeLocation::MEMORY, global_variable.address().value);
|
node->location = SymbolTreeLocation(SymbolTreeLocation::MEMORY, global_variable.address().value);
|
||||||
|
|
|
@ -84,6 +84,7 @@ protected:
|
||||||
void onDeleteButtonPressed();
|
void onDeleteButtonPressed();
|
||||||
|
|
||||||
void onCopyName();
|
void onCopyName();
|
||||||
|
void onCopyMangledName();
|
||||||
void onCopyLocation();
|
void onCopyLocation();
|
||||||
void onRenameSymbol();
|
void onRenameSymbol();
|
||||||
void onGoToInDisassembly();
|
void onGoToInDisassembly();
|
||||||
|
@ -117,7 +118,8 @@ protected:
|
||||||
NO_SYMBOL_TREE_FLAGS = 0,
|
NO_SYMBOL_TREE_FLAGS = 0,
|
||||||
ALLOW_GROUPING = 1 << 0,
|
ALLOW_GROUPING = 1 << 0,
|
||||||
ALLOW_SORTING_BY_IF_TYPE_IS_KNOWN = 1 << 1,
|
ALLOW_SORTING_BY_IF_TYPE_IS_KNOWN = 1 << 1,
|
||||||
ALLOW_TYPE_ACTIONS = 1 << 2
|
ALLOW_TYPE_ACTIONS = 1 << 2,
|
||||||
|
ALLOW_MANGLED_NAME_ACTIONS = 1 << 3
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 m_flags;
|
u32 m_flags;
|
||||||
|
|
|
@ -10,17 +10,13 @@
|
||||||
#include "GS.h" // Required for gsNonMirroredRead()
|
#include "GS.h" // Required for gsNonMirroredRead()
|
||||||
#include "Counters.h"
|
#include "Counters.h"
|
||||||
|
|
||||||
|
#include "Host.h"
|
||||||
#include "R3000A.h"
|
#include "R3000A.h"
|
||||||
#include "IopMem.h"
|
#include "IopMem.h"
|
||||||
#include "VMManager.h"
|
#include "VMManager.h"
|
||||||
|
|
||||||
#include "common/StringUtil.h"
|
#include "common/StringUtil.h"
|
||||||
|
|
||||||
#ifdef __clang__
|
|
||||||
// TODO: The sprintf() usage here needs to be rewritten...
|
|
||||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
R5900DebugInterface r5900Debug;
|
R5900DebugInterface r5900Debug;
|
||||||
R3000DebugInterface r3000Debug;
|
R3000DebugInterface r3000Debug;
|
||||||
|
|
||||||
|
@ -45,8 +41,20 @@ enum ReferenceIndexType
|
||||||
class MipsExpressionFunctions : public IExpressionFunctions
|
class MipsExpressionFunctions : public IExpressionFunctions
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit MipsExpressionFunctions(DebugInterface* cpu)
|
explicit MipsExpressionFunctions(DebugInterface* cpu, bool enumerateSymbols)
|
||||||
: cpu(cpu){};
|
: m_cpu(cpu)
|
||||||
|
{
|
||||||
|
if (!enumerateSymbols)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_cpu->GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
||||||
|
for (const ccc::Function& function : database.functions)
|
||||||
|
m_mangled_function_names_to_handles.emplace(function.mangled_name(), function.handle());
|
||||||
|
|
||||||
|
for (const ccc::GlobalVariable& global : database.global_variables)
|
||||||
|
m_mangled_global_names_to_handles.emplace(global.mangled_name(), global.handle());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool parseReference(char* str, u64& referenceIndex)
|
virtual bool parseReference(char* str, u64& referenceIndex)
|
||||||
{
|
{
|
||||||
|
@ -54,7 +62,7 @@ public:
|
||||||
{
|
{
|
||||||
char reg[8];
|
char reg[8];
|
||||||
std::snprintf(reg, std::size(reg), "r%d", i);
|
std::snprintf(reg, std::size(reg), "r%d", i);
|
||||||
if (StringUtil::Strcasecmp(str, reg) == 0 || StringUtil::Strcasecmp(str, cpu->getRegisterName(0, i)) == 0)
|
if (StringUtil::Strcasecmp(str, reg) == 0 || StringUtil::Strcasecmp(str, m_cpu->getRegisterName(0, i)) == 0)
|
||||||
{
|
{
|
||||||
referenceIndex = i;
|
referenceIndex = i;
|
||||||
return true;
|
return true;
|
||||||
|
@ -108,27 +116,62 @@ public:
|
||||||
|
|
||||||
virtual bool parseSymbol(char* str, u64& symbolValue)
|
virtual bool parseSymbol(char* str, u64& symbolValue)
|
||||||
{
|
{
|
||||||
SymbolInfo symbol = cpu->GetSymbolGuardian().SymbolWithName(std::string(str));
|
bool success = false;
|
||||||
if (!symbol.address.valid())
|
m_cpu->GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
||||||
return false;
|
std::string name = str;
|
||||||
|
|
||||||
symbolValue = symbol.address.value;
|
// Check for mangled function names.
|
||||||
return true;
|
auto function_iterator = m_mangled_function_names_to_handles.find(name);
|
||||||
|
if (function_iterator != m_mangled_function_names_to_handles.end())
|
||||||
|
{
|
||||||
|
const ccc::Function* function = database.functions.symbol_from_handle(function_iterator->second);
|
||||||
|
if (function && function->address().valid())
|
||||||
|
{
|
||||||
|
symbolValue = function->address().value;
|
||||||
|
success = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for mangled global variable names.
|
||||||
|
auto global_iterator = m_mangled_global_names_to_handles.find(name);
|
||||||
|
if (global_iterator != m_mangled_global_names_to_handles.end())
|
||||||
|
{
|
||||||
|
const ccc::GlobalVariable* global = database.global_variables.symbol_from_handle(global_iterator->second);
|
||||||
|
if (global && global->address().valid())
|
||||||
|
{
|
||||||
|
symbolValue = global->address().value;
|
||||||
|
success = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for regular unmangled names.
|
||||||
|
const ccc::Symbol* symbol = database.symbol_with_name(name);
|
||||||
|
if (symbol && symbol->address().valid())
|
||||||
|
{
|
||||||
|
symbolValue = symbol->address().value;
|
||||||
|
success = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual u64 getReferenceValue(u64 referenceIndex)
|
virtual u64 getReferenceValue(u64 referenceIndex)
|
||||||
{
|
{
|
||||||
if (referenceIndex < 32)
|
if (referenceIndex < 32)
|
||||||
return cpu->getRegister(0, referenceIndex)._u64[0];
|
return m_cpu->getRegister(0, referenceIndex)._u64[0];
|
||||||
if (referenceIndex == REF_INDEX_PC)
|
if (referenceIndex == REF_INDEX_PC)
|
||||||
return cpu->getPC();
|
return m_cpu->getPC();
|
||||||
if (referenceIndex == REF_INDEX_HI)
|
if (referenceIndex == REF_INDEX_HI)
|
||||||
return cpu->getHI()._u64[0];
|
return m_cpu->getHI()._u64[0];
|
||||||
if (referenceIndex == REF_INDEX_LO)
|
if (referenceIndex == REF_INDEX_LO)
|
||||||
return cpu->getLO()._u64[0];
|
return m_cpu->getLO()._u64[0];
|
||||||
if (referenceIndex & REF_INDEX_IS_OPSL)
|
if (referenceIndex & REF_INDEX_IS_OPSL)
|
||||||
{
|
{
|
||||||
const u32 OP = memRead32(cpu->getPC());
|
const u32 OP = memRead32(m_cpu->getPC());
|
||||||
const R5900::OPCODE& opcode = R5900::GetInstruction(OP);
|
const R5900::OPCODE& opcode = R5900::GetInstruction(OP);
|
||||||
if (opcode.flags & IS_MEMORY)
|
if (opcode.flags & IS_MEMORY)
|
||||||
{
|
{
|
||||||
|
@ -154,7 +197,7 @@ public:
|
||||||
}
|
}
|
||||||
if (referenceIndex & REF_INDEX_FPU)
|
if (referenceIndex & REF_INDEX_FPU)
|
||||||
{
|
{
|
||||||
return cpu->getRegister(EECAT_FPR, referenceIndex & 0x1F)._u64[0];
|
return m_cpu->getRegister(EECAT_FPR, referenceIndex & 0x1F)._u64[0];
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -168,7 +211,7 @@ public:
|
||||||
return EXPR_TYPE_UINT;
|
return EXPR_TYPE_UINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool getMemoryValue(u32 address, int size, u64& dest, char* error)
|
virtual bool getMemoryValue(u32 address, int size, u64& dest, std::string& error)
|
||||||
{
|
{
|
||||||
switch (size)
|
switch (size)
|
||||||
{
|
{
|
||||||
|
@ -178,37 +221,40 @@ public:
|
||||||
case 8:
|
case 8:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sprintf(error, "Invalid memory access size %d", size);
|
error = StringUtil::StdStringFromFormat(
|
||||||
|
TRANSLATE("ExpressionParser", "Invalid memory access size %d."), size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (address % size)
|
if (address % size)
|
||||||
{
|
{
|
||||||
sprintf(error, "Invalid memory access (unaligned)");
|
error = TRANSLATE("ExpressionParser", "Invalid memory access (unaligned).");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (size)
|
switch (size)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
dest = cpu->read8(address);
|
dest = m_cpu->read8(address);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
dest = cpu->read16(address);
|
dest = m_cpu->read16(address);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
dest = cpu->read32(address);
|
dest = m_cpu->read32(address);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
dest = cpu->read64(address);
|
dest = m_cpu->read64(address);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
DebugInterface* cpu;
|
DebugInterface* m_cpu;
|
||||||
|
std::map<std::string, ccc::FunctionHandle> m_mangled_function_names_to_handles;
|
||||||
|
std::map<std::string, ccc::GlobalVariableHandle> m_mangled_global_names_to_handles;
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -308,19 +354,31 @@ std::optional<u32> DebugInterface::getStackFrameSize(const ccc::Function& functi
|
||||||
return static_cast<u32>(stack_frame_size);
|
return static_cast<u32>(stack_frame_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DebugInterface::evaluateExpression(const char* expression, u64& dest)
|
||||||
|
{
|
||||||
|
PostfixExpression postfix;
|
||||||
|
|
||||||
|
if (!initExpression(expression, postfix))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!parseExpression(postfix, dest))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool DebugInterface::initExpression(const char* exp, PostfixExpression& dest)
|
bool DebugInterface::initExpression(const char* exp, PostfixExpression& dest)
|
||||||
{
|
{
|
||||||
MipsExpressionFunctions funcs(this);
|
MipsExpressionFunctions funcs(this, true);
|
||||||
return initPostfixExpression(exp, &funcs, dest);
|
return initPostfixExpression(exp, &funcs, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DebugInterface::parseExpression(PostfixExpression& exp, u64& dest)
|
bool DebugInterface::parseExpression(PostfixExpression& exp, u64& dest)
|
||||||
{
|
{
|
||||||
MipsExpressionFunctions funcs(this);
|
MipsExpressionFunctions funcs(this, false);
|
||||||
return parsePostfixExpression(exp, &funcs, dest);
|
return parsePostfixExpression(exp, &funcs, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// R5900DebugInterface
|
// R5900DebugInterface
|
||||||
//
|
//
|
||||||
|
|
|
@ -79,6 +79,7 @@ public:
|
||||||
[[nodiscard]] virtual SymbolGuardian& GetSymbolGuardian() const = 0;
|
[[nodiscard]] virtual SymbolGuardian& GetSymbolGuardian() const = 0;
|
||||||
[[nodiscard]] virtual std::vector<std::unique_ptr<BiosThread>> GetThreadList() const = 0;
|
[[nodiscard]] virtual std::vector<std::unique_ptr<BiosThread>> GetThreadList() const = 0;
|
||||||
|
|
||||||
|
bool evaluateExpression(const char* expression, u64& dest);
|
||||||
bool initExpression(const char* exp, PostfixExpression& dest);
|
bool initExpression(const char* exp, PostfixExpression& dest);
|
||||||
bool parseExpression(PostfixExpression& exp, u64& dest);
|
bool parseExpression(PostfixExpression& exp, u64& dest);
|
||||||
bool isAlive();
|
bool isAlive();
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
#include "ExpressionParser.h"
|
#include "ExpressionParser.h"
|
||||||
|
|
||||||
|
#include "Host.h"
|
||||||
|
#include "common/StringUtil.h"
|
||||||
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -18,7 +21,7 @@ typedef enum {
|
||||||
|
|
||||||
typedef enum { EXCOMM_CONST, EXCOMM_CONST_FLOAT, EXCOMM_REF, EXCOMM_OP } ExpressionCommand;
|
typedef enum { EXCOMM_CONST, EXCOMM_CONST_FLOAT, EXCOMM_REF, EXCOMM_OP } ExpressionCommand;
|
||||||
|
|
||||||
static char expressionError[256];
|
static std::string expressionError;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char Name[4];
|
char Name[4];
|
||||||
|
@ -85,8 +88,6 @@ bool parseNumber(char* str, int defaultrad, int len, u64& result)
|
||||||
str+=2;
|
str+=2;
|
||||||
len-=2;
|
len-=2;
|
||||||
} else {
|
} else {
|
||||||
if (!(str[0] >= '0' && str[0] <= '9')) return false;
|
|
||||||
|
|
||||||
if (tolower(str[len-1]) == 'b' && defaultrad != 16)
|
if (tolower(str[len-1]) == 'b' && defaultrad != 16)
|
||||||
{
|
{
|
||||||
r = 2;
|
r = 2;
|
||||||
|
@ -210,7 +211,7 @@ bool isAlphaNum(char c)
|
||||||
|
|
||||||
bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest)
|
bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest)
|
||||||
{
|
{
|
||||||
expressionError[0] = 0;
|
expressionError.clear();
|
||||||
|
|
||||||
int infixPos = 0;
|
int infixPos = 0;
|
||||||
int infixLen = (int)strlen(infix);
|
int infixLen = (int)strlen(infix);
|
||||||
|
@ -232,19 +233,26 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
|
||||||
|
|
||||||
if (first >= '0' && first <= '9')
|
if (first >= '0' && first <= '9')
|
||||||
{
|
{
|
||||||
while (isAlphaNum(infix[infixPos]))
|
while (isAlphaNum(infix[infixPos]) && subPos < static_cast<int>(sizeof(subStr)) - 1)
|
||||||
{
|
{
|
||||||
subStr[subPos++] = infix[infixPos++];
|
subStr[subPos++] = infix[infixPos++];
|
||||||
}
|
}
|
||||||
subStr[subPos] = 0;
|
subStr[subPos] = 0;
|
||||||
|
|
||||||
|
if(subPos == sizeof(subStr) - 1)
|
||||||
|
{
|
||||||
|
expressionError = TRANSLATE("ExpressionParser", "Token too long.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
u64 value;
|
u64 value;
|
||||||
bool isFloat = false;
|
bool isFloat = false;
|
||||||
if (parseFloat(subStr,subPos,value))
|
if (parseFloat(subStr,subPos,value))
|
||||||
isFloat = true;
|
isFloat = true;
|
||||||
else if (!parseNumber(subStr,16,subPos,value))
|
else if (!parseNumber(subStr,16,subPos,value))
|
||||||
{
|
{
|
||||||
std::snprintf(expressionError, std::size(expressionError),"Invalid number \"%s\"",subStr);
|
expressionError = StringUtil::StdStringFromFormat(
|
||||||
|
TRANSLATE("ExpressionParser", "Invalid number \"%s\"."), subStr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,12 +260,18 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
|
||||||
lastOpcode = EXOP_NUMBER;
|
lastOpcode = EXOP_NUMBER;
|
||||||
} else if ((first >= 'a' && first <= 'z') || first == '@')
|
} else if ((first >= 'a' && first <= 'z') || first == '@')
|
||||||
{
|
{
|
||||||
while (isAlphaNum(infix[infixPos]))
|
while (isAlphaNum(infix[infixPos]) && subPos < static_cast<int>(sizeof(subStr)) - 1)
|
||||||
{
|
{
|
||||||
subStr[subPos++] = infix[infixPos++];
|
subStr[subPos++] = infix[infixPos++];
|
||||||
}
|
}
|
||||||
subStr[subPos] = 0;
|
subStr[subPos] = 0;
|
||||||
|
|
||||||
|
if(subPos == sizeof(subStr) - 1)
|
||||||
|
{
|
||||||
|
expressionError = TRANSLATE("ExpressionParser", "Token too long.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
u64 value;
|
u64 value;
|
||||||
if (funcs->parseReference(subStr,value))
|
if (funcs->parseReference(subStr,value))
|
||||||
{
|
{
|
||||||
|
@ -273,14 +287,23 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::snprintf(expressionError, std::size(expressionError),"Invalid symbol \"%s\"",subStr);
|
if(parseNumber(subStr,16,subPos,value))
|
||||||
|
{
|
||||||
|
dest.push_back(ExpressionPair(EXCOMM_CONST,value));
|
||||||
|
lastOpcode = EXOP_NUMBER;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
expressionError = StringUtil::StdStringFromFormat(
|
||||||
|
TRANSLATE("ExpressionParser", "Invalid symbol \"%s\"."), subStr);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
int len;
|
int len;
|
||||||
ExpressionOpcodeType type = getExpressionOpcode(&infix[infixPos],len,lastOpcode);
|
ExpressionOpcodeType type = getExpressionOpcode(&infix[infixPos],len,lastOpcode);
|
||||||
if (type == EXOP_NONE)
|
if (type == EXOP_NONE)
|
||||||
{
|
{
|
||||||
std::snprintf(expressionError, std::size(expressionError),"Invalid operator at \"%s\"",&infix[infixPos]);
|
expressionError = StringUtil::StdStringFromFormat(
|
||||||
|
TRANSLATE("ExpressionParser", "Invalid operator at \"%s\"."), &infix[infixPos]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +318,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
|
||||||
{
|
{
|
||||||
if (opcodeStack.empty())
|
if (opcodeStack.empty())
|
||||||
{
|
{
|
||||||
std::snprintf(expressionError, std::size(expressionError),"Closing parenthesis without opening one");
|
expressionError = TRANSLATE("ExpressionParser", "Closing parenthesis without opening one.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
|
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
|
||||||
|
@ -309,7 +332,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
|
||||||
{
|
{
|
||||||
if (opcodeStack.empty())
|
if (opcodeStack.empty())
|
||||||
{
|
{
|
||||||
std::snprintf(expressionError, std::size(expressionError),"Closing bracket without opening one");
|
expressionError = TRANSLATE("ExpressionParser", "Closing bracket without opening one.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
|
ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];
|
||||||
|
@ -362,7 +385,7 @@ bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, Postf
|
||||||
|
|
||||||
if (t == EXOP_BRACKETL) // opening bracket without closing one
|
if (t == EXOP_BRACKETL) // opening bracket without closing one
|
||||||
{
|
{
|
||||||
std::snprintf(expressionError, std::size(expressionError),"Parenthesis not closed");
|
expressionError = TRANSLATE("ExpressionParser", "Parenthesis not closed.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
dest.push_back(ExpressionPair(EXCOMM_OP,t));
|
dest.push_back(ExpressionPair(EXCOMM_OP,t));
|
||||||
|
@ -421,7 +444,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
|
||||||
opcode = exp[num++].second;
|
opcode = exp[num++].second;
|
||||||
if (valueStack.size() < ExpressionOpcodes[opcode].args)
|
if (valueStack.size() < ExpressionOpcodes[opcode].args)
|
||||||
{
|
{
|
||||||
std::snprintf(expressionError, std::size(expressionError),"Not enough arguments");
|
expressionError = TRANSLATE("ExpressionParser", "Not enough arguments.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int l = 0; l < ExpressionOpcodes[opcode].args; l++)
|
for (int l = 0; l < ExpressionOpcodes[opcode].args; l++)
|
||||||
|
@ -436,7 +459,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
|
||||||
case EXOP_MEMSIZE: // must be followed by EXOP_MEM
|
case EXOP_MEMSIZE: // must be followed by EXOP_MEM
|
||||||
if (exp[num++].second != EXOP_MEM)
|
if (exp[num++].second != EXOP_MEM)
|
||||||
{
|
{
|
||||||
std::snprintf(expressionError, std::size(expressionError),"Invalid memsize operator");
|
expressionError = TRANSLATE("ExpressionParser", "Invalid memsize operator.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,7 +503,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
|
||||||
case EXOP_DIV: // a/b
|
case EXOP_DIV: // a/b
|
||||||
if (arg[0] == 0)
|
if (arg[0] == 0)
|
||||||
{
|
{
|
||||||
std::snprintf(expressionError, std::size(expressionError),"Division by zero");
|
expressionError = TRANSLATE("ExpressionParser", "Division by zero.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (useFloat)
|
if (useFloat)
|
||||||
|
@ -491,7 +514,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
|
||||||
case EXOP_MOD: // a%b
|
case EXOP_MOD: // a%b
|
||||||
if (arg[0] == 0)
|
if (arg[0] == 0)
|
||||||
{
|
{
|
||||||
std::snprintf(expressionError, std::size(expressionError),"Modulo by zero");
|
expressionError = TRANSLATE("ExpressionParser", "Modulo by zero.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
valueStack.push_back(arg[1]%arg[0]);
|
valueStack.push_back(arg[1]%arg[0]);
|
||||||
|
@ -570,7 +593,7 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
|
||||||
case EXOP_TERTELSE: // exp ? exp : exp, else muss zuerst kommen!
|
case EXOP_TERTELSE: // exp ? exp : exp, else muss zuerst kommen!
|
||||||
if (exp[num++].second != EXOP_TERTIF)
|
if (exp[num++].second != EXOP_TERTIF)
|
||||||
{
|
{
|
||||||
std::snprintf(expressionError, std::size(expressionError),"Invalid tertiary operator");
|
expressionError = TRANSLATE("ExpressionParser", "Invalid tertiary operator.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
valueStack.push_back(arg[2]?arg[1]:arg[0]);
|
valueStack.push_back(arg[2]?arg[1]:arg[0]);
|
||||||
|
@ -594,6 +617,8 @@ bool parseExpression(char* exp, IExpressionFunctions* funcs, u64& dest)
|
||||||
|
|
||||||
const char* getExpressionError()
|
const char* getExpressionError()
|
||||||
{
|
{
|
||||||
if (expressionError[0] == 0) strcpy(expressionError,"Invalid expression");
|
if (expressionError.empty())
|
||||||
return expressionError;
|
return TRANSLATE("ExpressionParser", "Invalid expression.");
|
||||||
|
|
||||||
|
return expressionError.c_str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ public:
|
||||||
virtual bool parseSymbol(char* str, u64& symbolValue) = 0;
|
virtual bool parseSymbol(char* str, u64& symbolValue) = 0;
|
||||||
virtual u64 getReferenceValue(u64 referenceIndex) = 0;
|
virtual u64 getReferenceValue(u64 referenceIndex) = 0;
|
||||||
virtual ExpressionType getReferenceType(u64 referenceIndex) = 0;
|
virtual ExpressionType getReferenceType(u64 referenceIndex) = 0;
|
||||||
virtual bool getMemoryValue(u32 address, int size, u64& dest, char* error) = 0;
|
virtual bool getMemoryValue(u32 address, int size, u64& dest, std::string& error) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest);
|
bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest);
|
||||||
|
|
Loading…
Reference in New Issue