Debugger: Fixed issues with using labels in breakpoint conditions
This commit is contained in:
parent
3c8c046e67
commit
1a7f07cff5
13 changed files with 234 additions and 188 deletions
|
@ -52,6 +52,9 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
|
|||
_profiler.reset(new Profiler(this));
|
||||
_traceLogger.reset(new TraceLogger(this, memoryManager, _labelManager));
|
||||
|
||||
_bpExpEval.reset(new ExpressionEvaluator(this));
|
||||
_watchExpEval.reset(new ExpressionEvaluator(this));
|
||||
|
||||
_stepOut = false;
|
||||
_stepCount = -1;
|
||||
_stepOverAddr = -1;
|
||||
|
@ -246,15 +249,20 @@ void Debugger::SetBreakpoints(Breakpoint breakpoints[], uint32_t length)
|
|||
_hasBreakpoint[i] = false;
|
||||
}
|
||||
|
||||
ExpressionEvaluator expEval(this);
|
||||
_bpExpEval.reset(new ExpressionEvaluator(this));
|
||||
for(uint32_t j = 0; j < length; j++) {
|
||||
Breakpoint &bp = breakpoints[j];
|
||||
for(int i = 0; i < Debugger::BreakpointTypeCount; i++) {
|
||||
bool isEnabled = bp.IsEnabled() && _console->GetSettings()->CheckFlag(EmulationFlags::DebuggerWindowEnabled);
|
||||
if((bp.IsMarked() || isEnabled) && bp.HasBreakpointType((BreakpointType)i)) {
|
||||
_breakpoints[i].push_back(bp);
|
||||
vector<int> *rpnList = expEval.GetRpnList(bp.GetCondition());
|
||||
_breakpointRpnList[i].push_back(rpnList ? *rpnList : vector<int>());
|
||||
|
||||
bool success = true;
|
||||
if(bp.HasCondition()) {
|
||||
ExpressionData data = _bpExpEval->GetRpnList(bp.GetCondition(), success);
|
||||
_breakpointRpnList[i].push_back(success ? data : ExpressionData());
|
||||
}
|
||||
|
||||
_hasBreakpoint[i] = true;
|
||||
}
|
||||
}
|
||||
|
@ -318,7 +326,7 @@ void Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationI
|
|||
GetState(&_debugState, false);
|
||||
needState = false;
|
||||
}
|
||||
if(_bpExpEval.Evaluate(_breakpointRpnList[(int)type][i], _debugState, resultType, operationInfo) != 0) {
|
||||
if(_bpExpEval->Evaluate(_breakpointRpnList[(int)type][i], _debugState, resultType, operationInfo) != 0) {
|
||||
processBreakpoint(breakpoint);
|
||||
}
|
||||
}
|
||||
|
@ -341,12 +349,17 @@ void Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationI
|
|||
}
|
||||
}
|
||||
|
||||
int32_t Debugger::EvaluateExpression(string expression, EvalResultType &resultType)
|
||||
int32_t Debugger::EvaluateExpression(string expression, EvalResultType &resultType, bool useCache)
|
||||
{
|
||||
DebugState state;
|
||||
OperationInfo operationInfo { 0, 0, MemoryOperationType::DummyRead };
|
||||
GetState(&state);
|
||||
return _watchExpEval.Evaluate(expression, state, resultType, operationInfo);
|
||||
if(useCache) {
|
||||
return _watchExpEval->Evaluate(expression, state, resultType, operationInfo);
|
||||
} else {
|
||||
ExpressionEvaluator expEval(this);
|
||||
return expEval.Evaluate(expression, state, resultType, operationInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::UpdateCallstack(uint8_t instruction, uint32_t addr)
|
||||
|
|
|
@ -10,7 +10,6 @@ using std::unordered_set;
|
|||
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
#include "DebuggerTypes.h"
|
||||
#include "ExpressionEvaluator.h"
|
||||
|
||||
class CPU;
|
||||
class APU;
|
||||
|
@ -29,7 +28,10 @@ class ScriptHost;
|
|||
class TraceLogger;
|
||||
class Breakpoint;
|
||||
class CodeDataLogger;
|
||||
class ExpressionEvaluator;
|
||||
struct ExpressionData;
|
||||
|
||||
enum EvalResultType : int32_t;
|
||||
enum class CdlStripFlag;
|
||||
|
||||
class Debugger
|
||||
|
@ -67,7 +69,7 @@ private:
|
|||
atomic<bool> _executionStopped;
|
||||
atomic<int32_t> _suspendCount;
|
||||
vector<Breakpoint> _breakpoints[BreakpointTypeCount];
|
||||
vector<vector<int>> _breakpointRpnList[BreakpointTypeCount];
|
||||
vector<ExpressionData> _breakpointRpnList[BreakpointTypeCount];
|
||||
bool _hasBreakpoint[BreakpointTypeCount] = {};
|
||||
|
||||
vector<uint8_t> _frozenAddresses;
|
||||
|
@ -79,8 +81,8 @@ private:
|
|||
|
||||
unordered_set<uint32_t> _functionEntryPoints;
|
||||
|
||||
ExpressionEvaluator _watchExpEval = ExpressionEvaluator(this);
|
||||
ExpressionEvaluator _bpExpEval = ExpressionEvaluator(this);
|
||||
unique_ptr<ExpressionEvaluator> _watchExpEval;
|
||||
unique_ptr<ExpressionEvaluator> _bpExpEval;
|
||||
DebugState _debugState;
|
||||
|
||||
SimpleLock _breakLock;
|
||||
|
@ -215,7 +217,7 @@ public:
|
|||
shared_ptr<MemoryDumper> GetMemoryDumper();
|
||||
shared_ptr<MemoryAccessCounter> GetMemoryAccessCounter();
|
||||
|
||||
int32_t EvaluateExpression(string expression, EvalResultType &resultType);
|
||||
int32_t EvaluateExpression(string expression, EvalResultType &resultType, bool useCache);
|
||||
|
||||
void ProcessPpuCycle();
|
||||
bool ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value);
|
||||
|
|
|
@ -8,12 +8,9 @@
|
|||
#include "LabelManager.h"
|
||||
#include "../Utilities/HexUtilities.h"
|
||||
|
||||
std::unordered_map<string, std::vector<int>, StringHasher> ExpressionEvaluator::_outputCache;
|
||||
SimpleLock ExpressionEvaluator::_cacheLock;
|
||||
|
||||
const vector<string> ExpressionEvaluator::_binaryOperators = { { "*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||" } };
|
||||
const vector<int> ExpressionEvaluator::_binaryPrecedence = { { 10, 10, 10, 9, 9, 8, 8, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1 } };
|
||||
const vector<string> ExpressionEvaluator::_unaryOperators = { { "+", "-", "!", "~" } };
|
||||
const vector<string> ExpressionEvaluator::_unaryOperators = { { "+", "-", "~", "!" } };
|
||||
const vector<int> ExpressionEvaluator::_unaryPrecedence = { { 11, 11, 11, 11 } };
|
||||
|
||||
bool ExpressionEvaluator::IsOperator(string token, int &precedence, bool unaryOperator)
|
||||
|
@ -41,20 +38,20 @@ EvalOperators ExpressionEvaluator::GetOperator(string token, bool unaryOperator)
|
|||
if(unaryOperator) {
|
||||
for(size_t i = 0, len = _unaryOperators.size(); i < len; i++) {
|
||||
if(token.compare(_unaryOperators[i]) == 0) {
|
||||
return (EvalOperators)(2000000050 + i);
|
||||
return (EvalOperators)(EvalOperators::Plus + i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(size_t i = 0, len = _binaryOperators.size(); i < len; i++) {
|
||||
if(token.compare(_binaryOperators[i]) == 0) {
|
||||
return (EvalOperators)(2000000000 + i);
|
||||
return (EvalOperators)(EvalOperators::Multiplication + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return EvalOperators::Addition;
|
||||
}
|
||||
|
||||
bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t &pos, string &output)
|
||||
bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t &pos, string &output, ExpressionData &data)
|
||||
{
|
||||
string token;
|
||||
size_t initialPos = pos;
|
||||
|
@ -70,46 +67,46 @@ bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t &pos, str
|
|||
}
|
||||
} while(pos < len);
|
||||
|
||||
if(!token.compare("a")) {
|
||||
output += std::to_string(EvalValues::RegA);
|
||||
} else if(!token.compare("x")) {
|
||||
output += std::to_string(EvalValues::RegX);
|
||||
} else if(!token.compare("y")) {
|
||||
output += std::to_string(EvalValues::RegY);
|
||||
} else if(!token.compare("ps")) {
|
||||
output += std::to_string(EvalValues::RegPS);
|
||||
} else if(!token.compare("sp")) {
|
||||
output += std::to_string(EvalValues::RegSP);
|
||||
} else if(!token.compare("pc")) {
|
||||
output += std::to_string(EvalValues::RegPC);
|
||||
} else if(!token.compare("oppc")) {
|
||||
output += std::to_string(EvalValues::RegOpPC);
|
||||
} else if(!token.compare("frame")) {
|
||||
output += std::to_string(EvalValues::PpuFrameCount);
|
||||
} else if(!token.compare("cycle")) {
|
||||
output += std::to_string(EvalValues::PpuCycle);
|
||||
} else if(!token.compare("scanline")) {
|
||||
output += std::to_string(EvalValues::PpuScanline);
|
||||
} else if(!token.compare("irq")) {
|
||||
output += std::to_string(EvalValues::Irq);
|
||||
} else if(!token.compare("nmi")) {
|
||||
output += std::to_string(EvalValues::Nmi);
|
||||
} else if(!token.compare("value")) {
|
||||
output += std::to_string(EvalValues::Value);
|
||||
} else if(!token.compare("address")) {
|
||||
output += std::to_string(EvalValues::Address);
|
||||
} else if(!token.compare("romaddress")) {
|
||||
output += std::to_string(EvalValues::AbsoluteAddress);
|
||||
} else if(!token.compare("iswrite")) {
|
||||
output += std::to_string(EvalValues::IsWrite);
|
||||
} else if(!token.compare("isread")) {
|
||||
output += std::to_string(EvalValues::IsRead);
|
||||
if(token == "a") {
|
||||
output += std::to_string((int64_t)EvalValues::RegA);
|
||||
} else if(token == "x") {
|
||||
output += std::to_string((int64_t)EvalValues::RegX);
|
||||
} else if(token == "y") {
|
||||
output += std::to_string((int64_t)EvalValues::RegY);
|
||||
} else if(token == "ps") {
|
||||
output += std::to_string((int64_t)EvalValues::RegPS);
|
||||
} else if(token == "sp") {
|
||||
output += std::to_string((int64_t)EvalValues::RegSP);
|
||||
} else if(token == "pc") {
|
||||
output += std::to_string((int64_t)EvalValues::RegPC);
|
||||
} else if(token == "oppc") {
|
||||
output += std::to_string((int64_t)EvalValues::RegOpPC);
|
||||
} else if(token == "frame") {
|
||||
output += std::to_string((int64_t)EvalValues::PpuFrameCount);
|
||||
} else if(token == "cycle") {
|
||||
output += std::to_string((int64_t)EvalValues::PpuCycle);
|
||||
} else if(token == "scanline") {
|
||||
output += std::to_string((int64_t)EvalValues::PpuScanline);
|
||||
} else if(token == "irq") {
|
||||
output += std::to_string((int64_t)EvalValues::Irq);
|
||||
} else if(token == "nmi") {
|
||||
output += std::to_string((int64_t)EvalValues::Nmi);
|
||||
} else if(token == "value") {
|
||||
output += std::to_string((int64_t)EvalValues::Value);
|
||||
} else if(token == "address") {
|
||||
output += std::to_string((int64_t)EvalValues::Address);
|
||||
} else if(token == "romaddress") {
|
||||
output += std::to_string((int64_t)EvalValues::AbsoluteAddress);
|
||||
} else if(token == "iswrite") {
|
||||
output += std::to_string((int64_t)EvalValues::IsWrite);
|
||||
} else if(token == "isread") {
|
||||
output += std::to_string((int64_t)EvalValues::IsRead);
|
||||
} else {
|
||||
string originalExpression = expression.substr(initialPos, pos - initialPos);
|
||||
int32_t address = _debugger->GetLabelManager()->GetLabelRelativeAddress(originalExpression);
|
||||
if(address >= 0) {
|
||||
_containsCustomLabels = true;
|
||||
output += std::to_string(address);
|
||||
bool validLabel = _debugger->GetLabelManager()->ContainsLabel(originalExpression);
|
||||
if(validLabel) {
|
||||
data.Labels.push_back(originalExpression);
|
||||
output += std::to_string(EvalValues::FirstLabelIndex + data.Labels.size() - 1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -118,7 +115,7 @@ bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t &pos, str
|
|||
return true;
|
||||
}
|
||||
|
||||
string ExpressionEvaluator::GetNextToken(string expression, size_t &pos)
|
||||
string ExpressionEvaluator::GetNextToken(string expression, size_t &pos, ExpressionData &data)
|
||||
{
|
||||
string output;
|
||||
bool isOperator = false;
|
||||
|
@ -171,7 +168,7 @@ string ExpressionEvaluator::GetNextToken(string expression, size_t &pos)
|
|||
break;
|
||||
} else {
|
||||
if(output.empty()) {
|
||||
if(CheckSpecialTokens(expression, pos, output)) {
|
||||
if(CheckSpecialTokens(expression, pos, output, data)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -188,7 +185,7 @@ string ExpressionEvaluator::GetNextToken(string expression, size_t &pos)
|
|||
return output;
|
||||
}
|
||||
|
||||
bool ExpressionEvaluator::ProcessSpecialOperator(EvalOperators evalOp, std::stack<EvalOperators> &opStack, std::stack<int> &precedenceStack, vector<int> &outputQueue)
|
||||
bool ExpressionEvaluator::ProcessSpecialOperator(EvalOperators evalOp, std::stack<EvalOperators> &opStack, std::stack<int> &precedenceStack, vector<int64_t> &outputQueue)
|
||||
{
|
||||
if(opStack.empty()) {
|
||||
return false;
|
||||
|
@ -211,7 +208,7 @@ bool ExpressionEvaluator::ProcessSpecialOperator(EvalOperators evalOp, std::stac
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
|
||||
bool ExpressionEvaluator::ToRpn(string expression, ExpressionData &data)
|
||||
{
|
||||
std::stack<EvalOperators> opStack = std::stack<EvalOperators>();
|
||||
std::stack<int> precedenceStack;
|
||||
|
@ -223,7 +220,7 @@ bool ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
|
|||
|
||||
bool previousTokenIsOp = true;
|
||||
while(true) {
|
||||
string token = GetNextToken(expression, position);
|
||||
string token = GetNextToken(expression, position, data);
|
||||
if(token.empty()) {
|
||||
break;
|
||||
}
|
||||
|
@ -239,7 +236,7 @@ bool ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
|
|||
if((unaryOperator && precedence < precedenceStack.top()) || (!unaryOperator && precedence <= precedenceStack.top())) {
|
||||
opStack.pop();
|
||||
precedenceStack.pop();
|
||||
outputQueue.push_back(topOp);
|
||||
data.RpnQueue.push_back(topOp);
|
||||
}
|
||||
}
|
||||
opStack.push(op);
|
||||
|
@ -253,7 +250,7 @@ bool ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
|
|||
previousTokenIsOp = true;
|
||||
} else if(token[0] == ')') {
|
||||
parenthesisCount--;
|
||||
if(!ProcessSpecialOperator(EvalOperators::Parenthesis, opStack, precedenceStack, outputQueue)) {
|
||||
if(!ProcessSpecialOperator(EvalOperators::Parenthesis, opStack, precedenceStack, data.RpnQueue)) {
|
||||
return false;
|
||||
}
|
||||
} else if(token[0] == '[') {
|
||||
|
@ -262,7 +259,7 @@ bool ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
|
|||
precedenceStack.push(0);
|
||||
} else if(token[0] == ']') {
|
||||
bracketCount--;
|
||||
if(!ProcessSpecialOperator(EvalOperators::Bracket, opStack, precedenceStack, outputQueue)) {
|
||||
if(!ProcessSpecialOperator(EvalOperators::Bracket, opStack, precedenceStack, data.RpnQueue)) {
|
||||
return false;
|
||||
}
|
||||
} else if(token[0] == '{') {
|
||||
|
@ -271,14 +268,14 @@ bool ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
|
|||
precedenceStack.push(0);
|
||||
} else if(token[0] == '}') {
|
||||
braceCount--;
|
||||
if(!ProcessSpecialOperator(EvalOperators::Braces, opStack, precedenceStack, outputQueue)){
|
||||
if(!ProcessSpecialOperator(EvalOperators::Braces, opStack, precedenceStack, data.RpnQueue)){
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(token[0] < '0' || token[0] > '9') {
|
||||
return false;
|
||||
} else {
|
||||
outputQueue.push_back(std::stoi(token));
|
||||
data.RpnQueue.push_back(std::stoll(token));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -289,43 +286,62 @@ bool ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
|
|||
}
|
||||
|
||||
while(!opStack.empty()) {
|
||||
outputQueue.push_back(opStack.top());
|
||||
data.RpnQueue.push_back(opStack.top());
|
||||
opStack.pop();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t ExpressionEvaluator::Evaluate(vector<int> &rpnList, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo)
|
||||
int32_t ExpressionEvaluator::Evaluate(ExpressionData &data, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo)
|
||||
{
|
||||
if(data.RpnQueue.empty()) {
|
||||
resultType = EvalResultType::Invalid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
int right = 0;
|
||||
int left = 0;
|
||||
int64_t right = 0;
|
||||
int64_t left = 0;
|
||||
resultType = EvalResultType::Numeric;
|
||||
|
||||
for(size_t i = 0, len = rpnList.size(); i < len; i++) {
|
||||
int token = rpnList[i];
|
||||
for(size_t i = 0, len = data.RpnQueue.size(); i < len; i++) {
|
||||
int64_t token = data.RpnQueue[i];
|
||||
|
||||
if(token >= EvalValues::RegA) {
|
||||
//Replace value with a special value
|
||||
switch(token) {
|
||||
case EvalValues::RegA: token = state.CPU.A; break;
|
||||
case EvalValues::RegX: token = state.CPU.X; break;
|
||||
case EvalValues::RegY: token = state.CPU.Y; break;
|
||||
case EvalValues::RegSP: token = state.CPU.SP; break;
|
||||
case EvalValues::RegPS: token = state.CPU.PS; break;
|
||||
case EvalValues::RegPC: token = state.CPU.PC; break;
|
||||
case EvalValues::RegOpPC: token = state.CPU.DebugPC; break;
|
||||
case EvalValues::PpuFrameCount: token = state.PPU.FrameCount; break;
|
||||
case EvalValues::PpuCycle: token = state.PPU.Cycle; break;
|
||||
case EvalValues::PpuScanline: token = state.PPU.Scanline; break;
|
||||
case EvalValues::Nmi: token = state.CPU.NMIFlag; break;
|
||||
case EvalValues::Irq: token = state.CPU.IRQFlag; break;
|
||||
case EvalValues::Value: token = operationInfo.Value; break;
|
||||
case EvalValues::Address: token = operationInfo.Address; break;
|
||||
case EvalValues::AbsoluteAddress: token = _debugger->GetAbsoluteAddress(operationInfo.Address); break;
|
||||
case EvalValues::IsWrite: token = operationInfo.OperationType == MemoryOperationType::Write; break;
|
||||
case EvalValues::IsRead: token = operationInfo.OperationType == MemoryOperationType::Read; break;
|
||||
if(token >= EvalValues::FirstLabelIndex) {
|
||||
int64_t labelIndex = token - EvalValues::FirstLabelIndex;
|
||||
if((size_t)labelIndex < data.Labels.size()) {
|
||||
token = _debugger->GetLabelManager()->GetLabelRelativeAddress(data.Labels[labelIndex]);
|
||||
} else {
|
||||
token = -1;
|
||||
}
|
||||
if(token < 0) {
|
||||
//Label is no longer valid
|
||||
resultType = EvalResultType::Invalid;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
switch(token) {
|
||||
case EvalValues::RegA: token = state.CPU.A; break;
|
||||
case EvalValues::RegX: token = state.CPU.X; break;
|
||||
case EvalValues::RegY: token = state.CPU.Y; break;
|
||||
case EvalValues::RegSP: token = state.CPU.SP; break;
|
||||
case EvalValues::RegPS: token = state.CPU.PS; break;
|
||||
case EvalValues::RegPC: token = state.CPU.PC; break;
|
||||
case EvalValues::RegOpPC: token = state.CPU.DebugPC; break;
|
||||
case EvalValues::PpuFrameCount: token = state.PPU.FrameCount; break;
|
||||
case EvalValues::PpuCycle: token = state.PPU.Cycle; break;
|
||||
case EvalValues::PpuScanline: token = state.PPU.Scanline; break;
|
||||
case EvalValues::Nmi: token = state.CPU.NMIFlag; break;
|
||||
case EvalValues::Irq: token = state.CPU.IRQFlag; break;
|
||||
case EvalValues::Value: token = operationInfo.Value; break;
|
||||
case EvalValues::Address: token = operationInfo.Address; break;
|
||||
case EvalValues::AbsoluteAddress: token = _debugger->GetAbsoluteAddress(operationInfo.Address); break;
|
||||
case EvalValues::IsWrite: token = operationInfo.OperationType == MemoryOperationType::Write; break;
|
||||
case EvalValues::IsRead: token = operationInfo.OperationType == MemoryOperationType::Read; break;
|
||||
}
|
||||
}
|
||||
} else if(token >= EvalOperators::Multiplication) {
|
||||
right = operandStack[--pos];
|
||||
|
@ -371,14 +387,14 @@ int32_t ExpressionEvaluator::Evaluate(vector<int> &rpnList, DebugState &state, E
|
|||
case EvalOperators::Minus: token = -right; break;
|
||||
case EvalOperators::BinaryNot: token = ~right; break;
|
||||
case EvalOperators::LogicalNot: token = !right; break;
|
||||
case EvalOperators::Bracket: token = _debugger->GetMemoryDumper()->GetMemoryValue(DebugMemoryType::CpuMemory, right); break;
|
||||
case EvalOperators::Braces: token = _debugger->GetMemoryDumper()->GetMemoryValueWord(DebugMemoryType::CpuMemory, right); break;
|
||||
case EvalOperators::Bracket: token = _debugger->GetMemoryDumper()->GetMemoryValue(DebugMemoryType::CpuMemory, (uint32_t)right); break;
|
||||
case EvalOperators::Braces: token = _debugger->GetMemoryDumper()->GetMemoryValueWord(DebugMemoryType::CpuMemory, (uint32_t)right); break;
|
||||
default: throw std::runtime_error("Invalid operator");
|
||||
}
|
||||
}
|
||||
operandStack[pos++] = token;
|
||||
}
|
||||
return operandStack[0];
|
||||
return (int32_t)operandStack[0];
|
||||
}
|
||||
|
||||
ExpressionEvaluator::ExpressionEvaluator(Debugger* debugger)
|
||||
|
@ -386,55 +402,55 @@ ExpressionEvaluator::ExpressionEvaluator(Debugger* debugger)
|
|||
_debugger = debugger;
|
||||
}
|
||||
|
||||
vector<int>* ExpressionEvaluator::GetRpnList(string expression)
|
||||
ExpressionData ExpressionEvaluator::GetRpnList(string expression, bool &success)
|
||||
{
|
||||
vector<int> output;
|
||||
bool success;
|
||||
return GetRpnList(expression, output, success);
|
||||
ExpressionData* cachedData = PrivateGetRpnList(expression, success);
|
||||
if(cachedData) {
|
||||
return *cachedData;
|
||||
} else {
|
||||
return ExpressionData();
|
||||
}
|
||||
}
|
||||
|
||||
vector<int>* ExpressionEvaluator::GetRpnList(string expression, vector<int> &output, bool& success)
|
||||
ExpressionData* ExpressionEvaluator::PrivateGetRpnList(string expression, bool& success)
|
||||
{
|
||||
vector<int> *outputQueue = nullptr;
|
||||
ExpressionData *cachedData = nullptr;
|
||||
{
|
||||
LockHandler lock = _cacheLock.AcquireSafe();
|
||||
|
||||
auto cacheOutputQueue = _outputCache.find(expression);
|
||||
if(cacheOutputQueue != _outputCache.end()) {
|
||||
outputQueue = &(cacheOutputQueue->second);
|
||||
auto result = _cache.find(expression);
|
||||
if(result != _cache.end()) {
|
||||
cachedData = &(result->second);
|
||||
}
|
||||
}
|
||||
|
||||
if(outputQueue == nullptr) {
|
||||
if(cachedData == nullptr) {
|
||||
string fixedExp = expression;
|
||||
fixedExp.erase(std::remove(fixedExp.begin(), fixedExp.end(), ' '), fixedExp.end());
|
||||
success = ToRpn(fixedExp, output);
|
||||
|
||||
if(success && !_containsCustomLabels) {
|
||||
ExpressionData data;
|
||||
success = ToRpn(fixedExp, data);
|
||||
if(success) {
|
||||
LockHandler lock = _cacheLock.AcquireSafe();
|
||||
_outputCache[expression] = output;
|
||||
outputQueue = &_outputCache[expression];
|
||||
_cache[expression] = data;
|
||||
cachedData = &_cache[expression];
|
||||
}
|
||||
} else {
|
||||
success = true;
|
||||
}
|
||||
|
||||
return outputQueue;
|
||||
return cachedData;
|
||||
}
|
||||
|
||||
int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo, bool& success)
|
||||
{
|
||||
success = true;
|
||||
vector<int> output;
|
||||
vector<int> *rpnList = GetRpnList(expression, output, success);
|
||||
ExpressionData *cachedData = PrivateGetRpnList(expression, success);
|
||||
|
||||
if(!success) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!rpnList) {
|
||||
rpnList = &output;
|
||||
}
|
||||
|
||||
return Evaluate(*rpnList, state, resultType, operationInfo);
|
||||
return Evaluate(*cachedData, state, resultType, operationInfo);
|
||||
}
|
||||
|
||||
int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo)
|
||||
|
|
|
@ -8,64 +8,66 @@
|
|||
|
||||
class Debugger;
|
||||
|
||||
enum EvalOperators
|
||||
enum EvalOperators : int64_t
|
||||
{
|
||||
//Binary operators
|
||||
Multiplication = 2000000000,
|
||||
Division = 2000000001,
|
||||
Modulo = 2000000002,
|
||||
Addition = 2000000003,
|
||||
Substration = 2000000004,
|
||||
ShiftLeft = 2000000005,
|
||||
ShiftRight = 2000000006,
|
||||
SmallerThan = 2000000007,
|
||||
SmallerOrEqual = 2000000008,
|
||||
GreaterThan = 2000000009,
|
||||
GreaterOrEqual = 2000000010,
|
||||
Equal = 2000000011,
|
||||
NotEqual = 2000000012,
|
||||
BinaryAnd = 2000000013,
|
||||
BinaryXor = 2000000014,
|
||||
BinaryOr = 2000000015,
|
||||
LogicalAnd = 2000000016,
|
||||
LogicalOr = 2000000017,
|
||||
Multiplication = 20000000000,
|
||||
Division = 20000000001,
|
||||
Modulo = 20000000002,
|
||||
Addition = 20000000003,
|
||||
Substration = 20000000004,
|
||||
ShiftLeft = 20000000005,
|
||||
ShiftRight = 20000000006,
|
||||
SmallerThan = 20000000007,
|
||||
SmallerOrEqual = 20000000008,
|
||||
GreaterThan = 20000000009,
|
||||
GreaterOrEqual = 20000000010,
|
||||
Equal = 20000000011,
|
||||
NotEqual = 20000000012,
|
||||
BinaryAnd = 20000000013,
|
||||
BinaryXor = 20000000014,
|
||||
BinaryOr = 20000000015,
|
||||
LogicalAnd = 20000000016,
|
||||
LogicalOr = 20000000017,
|
||||
|
||||
//Unary operators
|
||||
Plus = 2000000050,
|
||||
Minus = 2000000051,
|
||||
BinaryNot = 2000000052,
|
||||
LogicalNot = 2000000053,
|
||||
Plus = 20000000050,
|
||||
Minus = 20000000051,
|
||||
BinaryNot = 20000000052,
|
||||
LogicalNot = 20000000053,
|
||||
|
||||
//Used to read ram address
|
||||
Bracket = 2000000054, //Read byte
|
||||
Braces = 2000000055, //Read word
|
||||
Bracket = 20000000054, //Read byte
|
||||
Braces = 20000000055, //Read word
|
||||
|
||||
//Special value, not used as an operator
|
||||
Parenthesis = 2000000100,
|
||||
Parenthesis = 20000000100,
|
||||
};
|
||||
|
||||
enum EvalValues
|
||||
enum EvalValues : int64_t
|
||||
{
|
||||
RegA = 2000000100,
|
||||
RegX = 2000000101,
|
||||
RegY = 2000000102,
|
||||
RegSP = 2000000103,
|
||||
RegPS = 2000000104,
|
||||
RegPC = 2000000105,
|
||||
RegOpPC = 2000000106,
|
||||
PpuFrameCount = 2000000107,
|
||||
PpuCycle = 2000000108,
|
||||
PpuScanline = 2000000109,
|
||||
Nmi = 2000000110,
|
||||
Irq = 2000000111,
|
||||
Value = 2000000112,
|
||||
Address = 2000000113,
|
||||
AbsoluteAddress = 2000000114,
|
||||
IsWrite = 2000000115,
|
||||
IsRead = 2000000116,
|
||||
RegA = 20000000100,
|
||||
RegX = 20000000101,
|
||||
RegY = 20000000102,
|
||||
RegSP = 20000000103,
|
||||
RegPS = 20000000104,
|
||||
RegPC = 20000000105,
|
||||
RegOpPC = 20000000106,
|
||||
PpuFrameCount = 20000000107,
|
||||
PpuCycle = 20000000108,
|
||||
PpuScanline = 20000000109,
|
||||
Nmi = 20000000110,
|
||||
Irq = 20000000111,
|
||||
Value = 20000000112,
|
||||
Address = 20000000113,
|
||||
AbsoluteAddress = 20000000114,
|
||||
IsWrite = 20000000115,
|
||||
IsRead = 20000000116,
|
||||
|
||||
FirstLabelIndex = 20000002000,
|
||||
};
|
||||
|
||||
enum EvalResultType
|
||||
enum EvalResultType : int32_t
|
||||
{
|
||||
Numeric = 0,
|
||||
Boolean = 1,
|
||||
|
@ -83,6 +85,12 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
struct ExpressionData
|
||||
{
|
||||
std::vector<int64_t> RpnQueue;
|
||||
std::vector<string> Labels;
|
||||
};
|
||||
|
||||
class ExpressionEvaluator
|
||||
{
|
||||
private:
|
||||
|
@ -91,28 +99,27 @@ private:
|
|||
static const vector<string> _unaryOperators;
|
||||
static const vector<int> _unaryPrecedence;
|
||||
|
||||
static std::unordered_map<string, std::vector<int>, StringHasher> _outputCache;
|
||||
static SimpleLock _cacheLock;
|
||||
std::unordered_map<string, ExpressionData, StringHasher> _cache;
|
||||
SimpleLock _cacheLock;
|
||||
|
||||
int operandStack[1000];
|
||||
int64_t operandStack[1000];
|
||||
Debugger* _debugger;
|
||||
bool _containsCustomLabels = false;
|
||||
|
||||
bool IsOperator(string token, int &precedence, bool unaryOperator);
|
||||
EvalOperators GetOperator(string token, bool unaryOperator);
|
||||
bool CheckSpecialTokens(string expression, size_t &pos, string &output);
|
||||
string GetNextToken(string expression, size_t &pos);
|
||||
bool ProcessSpecialOperator(EvalOperators evalOp, std::stack<EvalOperators> &opStack, std::stack<int> &precedenceStack, vector<int> &outputQueue);
|
||||
bool ToRpn(string expression, vector<int> &outputQueue);
|
||||
bool CheckSpecialTokens(string expression, size_t &pos, string &output, ExpressionData &data);
|
||||
string GetNextToken(string expression, size_t &pos, ExpressionData &data);
|
||||
bool ProcessSpecialOperator(EvalOperators evalOp, std::stack<EvalOperators> &opStack, std::stack<int> &precedenceStack, vector<int64_t> &outputQueue);
|
||||
bool ToRpn(string expression, ExpressionData &data);
|
||||
int32_t PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo, bool &success);
|
||||
vector<int>* GetRpnList(string expression, vector<int> &output, bool& success);
|
||||
ExpressionData* PrivateGetRpnList(string expression, bool& success);
|
||||
|
||||
public:
|
||||
ExpressionEvaluator(Debugger* debugger);
|
||||
|
||||
int32_t Evaluate(vector<int> &outputQueue, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo);
|
||||
int32_t Evaluate(ExpressionData &data, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo);
|
||||
int32_t Evaluate(string expression, DebugState &state, EvalResultType &resultType, OperationInfo &operationInfo);
|
||||
vector<int>* GetRpnList(string expression);
|
||||
ExpressionData GetRpnList(string expression, bool &success);
|
||||
|
||||
bool Validate(string expression);
|
||||
};
|
|
@ -133,7 +133,12 @@ void LabelManager::GetLabelAndComment(uint16_t relativeAddr, string &label, stri
|
|||
}
|
||||
}
|
||||
|
||||
int32_t LabelManager::GetLabelRelativeAddress(string label)
|
||||
bool LabelManager::ContainsLabel(string &label)
|
||||
{
|
||||
return _codeLabelReverseLookup.find(label) != _codeLabelReverseLookup.end();
|
||||
}
|
||||
|
||||
int32_t LabelManager::GetLabelRelativeAddress(string &label)
|
||||
{
|
||||
auto result = _codeLabelReverseLookup.find(label);
|
||||
if(result != _codeLabelReverseLookup.end()) {
|
||||
|
|
|
@ -35,12 +35,14 @@ public:
|
|||
void SetLabel(uint32_t address, AddressType addressType, string label, string comment);
|
||||
void DeleteLabels();
|
||||
|
||||
int32_t GetLabelRelativeAddress(string label);
|
||||
int32_t GetLabelRelativeAddress(string &label);
|
||||
|
||||
string GetLabel(uint16_t relativeAddr, bool checkRegisters);
|
||||
string GetComment(uint16_t relativeAddr);
|
||||
void GetLabelAndComment(uint16_t relativeAddr, string &label, string &comment);
|
||||
|
||||
bool ContainsLabel(string &label);
|
||||
|
||||
bool HasLabelOrComment(uint16_t relativeAddr);
|
||||
bool HasLabelOrComment(uint32_t absoluteAddr, AddressType addressType);
|
||||
};
|
||||
|
|
|
@ -56,11 +56,12 @@ void TraceLogger::SetOptions(TraceLoggerOptions options)
|
|||
string format = _options.Format;
|
||||
|
||||
auto lock = _lock.AcquireSafe();
|
||||
_conditionRpnList.clear();
|
||||
_conditionData = ExpressionData();
|
||||
if(!condition.empty()) {
|
||||
vector<int> *rpnList = _expEvaluator->GetRpnList(condition);
|
||||
if(rpnList) {
|
||||
_conditionRpnList = *rpnList;
|
||||
bool success = false;
|
||||
ExpressionData rpnList = _expEvaluator->GetRpnList(condition, success);
|
||||
if(success) {
|
||||
_conditionData = rpnList;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,9 +253,9 @@ void TraceLogger::GetTraceRow(string &output, State &cpuState, PPUDebugState &pp
|
|||
|
||||
bool TraceLogger::ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo)
|
||||
{
|
||||
if(!_conditionRpnList.empty()) {
|
||||
if(!_conditionData.RpnQueue.empty()) {
|
||||
EvalResultType type;
|
||||
if(!_expEvaluator->Evaluate(_conditionRpnList, state, type, operationInfo)) {
|
||||
if(!_expEvaluator->Evaluate(_conditionData, state, type, operationInfo)) {
|
||||
if(operationInfo.OperationType == MemoryOperationType::ExecOpCode) {
|
||||
//Condition did not match, keep state/disassembly info for instruction's subsequent cycles
|
||||
_lastState = state;
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
#include "DebuggerTypes.h"
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
#include "DisassemblyInfo.h"
|
||||
#include "ExpressionEvaluator.h"
|
||||
|
||||
class MemoryManager;
|
||||
class LabelManager;
|
||||
class ExpressionEvaluator;
|
||||
class Debugger;
|
||||
|
||||
enum class RowDataType
|
||||
|
@ -65,7 +65,7 @@ private:
|
|||
shared_ptr<LabelManager> _labelManager;
|
||||
|
||||
shared_ptr<ExpressionEvaluator> _expEvaluator;
|
||||
vector<int> _conditionRpnList;
|
||||
ExpressionData _conditionData;
|
||||
|
||||
vector<RowPart> _rowParts;
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace Mesen.GUI.Debugger
|
|||
//Watch expression matches the array display syntax (e.g: [$300,10] = display 10 bytes starting from $300)
|
||||
newValue = ProcessArrayDisplaySyntax(useHex, ref forceHasChanged, match);
|
||||
} else {
|
||||
Int32 result = InteropEmu.DebugEvaluateExpression(expression, out resultType);
|
||||
Int32 result = InteropEmu.DebugEvaluateExpression(expression, out resultType, true);
|
||||
switch(resultType) {
|
||||
case EvalResultType.Numeric: newValue = useHex ? ("$" + result.ToString("X2")) : result.ToString(); break;
|
||||
case EvalResultType.Boolean: newValue = result == 0 ? "false" : "true"; break;
|
||||
|
|
|
@ -99,7 +99,7 @@ namespace Mesen.GUI.Debugger
|
|||
txtFrom.Focus();
|
||||
txtFrom.SelectionStart = 0;
|
||||
txtFrom.SelectionLength = 0;
|
||||
} else {
|
||||
} else if(bp.AddressType == BreakpointAddressType.SingleAddress) {
|
||||
txtAddress.Focus();
|
||||
txtAddress.SelectionStart = 0;
|
||||
txtAddress.SelectionLength = 0;
|
||||
|
@ -159,7 +159,7 @@ namespace Mesen.GUI.Debugger
|
|||
{
|
||||
if(txtCondition.Text.Trim().Length > 0) {
|
||||
EvalResultType resultType;
|
||||
InteropEmu.DebugEvaluateExpression(txtCondition.Text.Replace(Environment.NewLine, " "), out resultType);
|
||||
InteropEmu.DebugEvaluateExpression(txtCondition.Text.Replace(Environment.NewLine, " "), out resultType, false);
|
||||
if(resultType == EvalResultType.Invalid) {
|
||||
picExpressionWarning.Visible = true;
|
||||
return false;
|
||||
|
|
|
@ -367,7 +367,7 @@ namespace Mesen.GUI.Debugger
|
|||
{
|
||||
if(txtCondition.Text.Length > 0) {
|
||||
EvalResultType resultType;
|
||||
InteropEmu.DebugEvaluateExpression(txtCondition.Text, out resultType);
|
||||
InteropEmu.DebugEvaluateExpression(txtCondition.Text, out resultType, false);
|
||||
picExpressionWarning.Visible = (resultType == EvalResultType.Invalid);
|
||||
} else {
|
||||
picExpressionWarning.Visible = false;
|
||||
|
|
|
@ -285,7 +285,7 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] public static extern void DebugSetFreezeState(UInt16 address, [MarshalAs(UnmanagedType.I1)]bool frozen);
|
||||
|
||||
[DllImport(DLLPath)] public static extern void DebugSetNextStatement(UInt16 addr);
|
||||
[DllImport(DLLPath)] public static extern Int32 DebugEvaluateExpression([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string expression, out EvalResultType resultType);
|
||||
[DllImport(DLLPath)] public static extern Int32 DebugEvaluateExpression([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string expression, out EvalResultType resultType, [MarshalAs(UnmanagedType.I1)]bool useCache);
|
||||
|
||||
[DllImport(DLLPath)] public static extern void DebugStartTraceLogger([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filename);
|
||||
[DllImport(DLLPath)] public static extern void DebugStopTraceLogger();
|
||||
|
|
|
@ -96,7 +96,7 @@ extern "C"
|
|||
DllExport void __stdcall DebugGetCdlData(uint32_t offset, uint32_t length, DebugMemoryType memoryType, uint8_t* cdlData) { GetDebugger()->GetCodeDataLogger()->GetCdlData(offset, length, memoryType, cdlData); }
|
||||
DllExport void __stdcall DebugMarkPrgBytesAs(uint32_t start, uint32_t end, CdlPrgFlags type) { GetDebugger()->GetCodeDataLogger()->MarkPrgBytesAs(start, end, type); }
|
||||
|
||||
DllExport int32_t __stdcall DebugEvaluateExpression(char* expression, EvalResultType *resultType) { return GetDebugger()->EvaluateExpression(expression, *resultType); }
|
||||
DllExport int32_t __stdcall DebugEvaluateExpression(char* expression, EvalResultType *resultType, bool useCache) { return GetDebugger()->EvaluateExpression(expression, *resultType, useCache); }
|
||||
|
||||
DllExport void __stdcall DebugSetTraceOptions(TraceLoggerOptions options) { GetDebugger()->GetTraceLogger()->SetOptions(options); }
|
||||
DllExport void __stdcall DebugStartTraceLogger(char* filename) { GetDebugger()->GetTraceLogger()->StartLogging(filename); }
|
||||
|
|
Loading…
Add table
Reference in a new issue