Debugger: Fixed issues with using labels in breakpoint conditions

This commit is contained in:
Sour 2018-08-02 20:44:48 -04:00
parent 3c8c046e67
commit 1a7f07cff5
13 changed files with 234 additions and 188 deletions

View file

@ -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)

View file

@ -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);

View file

@ -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)

View file

@ -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);
};

View file

@ -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()) {

View file

@ -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);
};

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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); }