From f66738eac705d39378b1a2de60bd6c648433fd4b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Apr 2018 19:30:14 -0700 Subject: [PATCH] Debugger: Add cpu.evaluate method. Probably useful for a bunch of things, really. --- Core/Debugger/WebSocket/CPUCoreSubscriber.cpp | 34 ++++++++++ Core/Debugger/WebSocket/CPUCoreSubscriber.h | 1 + Core/Debugger/WebSocket/WebSocketUtils.cpp | 63 ++++++++++++++++--- Core/Debugger/WebSocket/WebSocketUtils.h | 1 + 4 files changed, 91 insertions(+), 8 deletions(-) diff --git a/Core/Debugger/WebSocket/CPUCoreSubscriber.cpp b/Core/Debugger/WebSocket/CPUCoreSubscriber.cpp index 2d6ee2f9e8..1b795899a7 100644 --- a/Core/Debugger/WebSocket/CPUCoreSubscriber.cpp +++ b/Core/Debugger/WebSocket/CPUCoreSubscriber.cpp @@ -31,6 +31,7 @@ void *WebSocketCPUCoreInit(DebuggerEventHandlerMap &map) { map["cpu.getAllRegs"] = &WebSocketCPUGetAllRegs; map["cpu.getReg"] = &WebSocketCPUGetReg; map["cpu.setReg"] = &WebSocketCPUSetReg; + map["cpu.evaluate"] = &WebSocketCPUEvaluate; return nullptr; } @@ -334,3 +335,36 @@ void WebSocketCPUSetReg(DebuggerRequest &req) { json.writeFloat("uintValue", val); json.writeString("floatValue", RegValueAsFloat(val)); } + +// Evaluate an expression (cpu.evaluate) +// +// Parameters: +// - expression: string containing labels, operators, regs, etc. +// +// Response (same event name): +// - uintValue: value in register. +// - floatValue: string showing float representation. May be "nan", "inf", or "-inf". +void WebSocketCPUEvaluate(DebuggerRequest &req) { + if (!currentDebugMIPS->isAlive()) { + return req.Fail("CPU not started"); + } + + std::string exp; + if (!req.ParamString("expression", &exp)) { + // Already sent error. + return; + } + + u32 val; + PostfixExpression postfix; + if (!currentDebugMIPS->initExpression(exp.c_str(), postfix)) { + return req.Fail(StringFromFormat("Could not parse expression syntax: %s", getExpressionError())); + } + if (!currentDebugMIPS->parseExpression(postfix, val)) { + return req.Fail(StringFromFormat("Could not evaluate expression: %s", getExpressionError())); + } + + JsonWriter &json = req.Respond(); + json.writeFloat("uintValue", val); + json.writeString("floatValue", RegValueAsFloat(val)); +} diff --git a/Core/Debugger/WebSocket/CPUCoreSubscriber.h b/Core/Debugger/WebSocket/CPUCoreSubscriber.h index effff73a76..3667979e96 100644 --- a/Core/Debugger/WebSocket/CPUCoreSubscriber.h +++ b/Core/Debugger/WebSocket/CPUCoreSubscriber.h @@ -27,3 +27,4 @@ void WebSocketCPUStatus(DebuggerRequest &req); void WebSocketCPUGetAllRegs(DebuggerRequest &req); void WebSocketCPUGetReg(DebuggerRequest &req); void WebSocketCPUSetReg(DebuggerRequest &req); +void WebSocketCPUEvaluate(DebuggerRequest &req); diff --git a/Core/Debugger/WebSocket/WebSocketUtils.cpp b/Core/Debugger/WebSocket/WebSocketUtils.cpp index 140ff8da82..d21b93e9d3 100644 --- a/Core/Debugger/WebSocket/WebSocketUtils.cpp +++ b/Core/Debugger/WebSocket/WebSocketUtils.cpp @@ -85,7 +85,8 @@ bool DebuggerRequest::ParamU32(const char *name, uint32_t *out, bool allowFloatB return !required; } - if (node->value.getTag() == JSON_NUMBER) { + auto tag = node->value.getTag(); + if (tag == JSON_NUMBER) { double val = node->value.toNumber(); bool isInteger = trunc(val) == val; if (!isInteger && !allowLoose) { @@ -123,8 +124,8 @@ bool DebuggerRequest::ParamU32(const char *name, uint32_t *out, bool allowFloatB Fail(StringFromFormat("Could not parse '%s' parameter: outside 32 bit range", name)); return false; } - if (node->value.getTag() != JSON_STRING) { - if (required || node->value.getTag() != JSON_NULL) { + if (tag != JSON_STRING) { + if (required || tag != JSON_NULL) { Fail(StringFromFormat("Invalid '%s' parameter type", name)); return false; } @@ -152,7 +153,8 @@ bool DebuggerRequest::ParamBool(const char *name, bool *out, DebuggerParamType t return !required; } - if (node->value.getTag() == JSON_NUMBER) { + auto tag = node->value.getTag(); + if (tag == JSON_NUMBER) { double val = node->value.toNumber(); if (val == 1.0 || val == 0.0 || allowLoose) { *out = val != 0.0; @@ -162,16 +164,16 @@ bool DebuggerRequest::ParamBool(const char *name, bool *out, DebuggerParamType t Fail(StringFromFormat("Could not parse '%s' parameter: should be true/1 or false/0", name)); return false; } - if (node->value.getTag() == JSON_TRUE) { + if (tag == JSON_TRUE) { *out = true; return true; } - if (node->value.getTag() == JSON_FALSE) { + if (tag == JSON_FALSE) { *out = false; return true; } - if (node->value.getTag() != JSON_STRING) { - if (type == DebuggerParamType::REQUIRED || node->value.getTag() != JSON_NULL) { + if (tag != JSON_STRING) { + if (type == DebuggerParamType::REQUIRED || tag != JSON_NULL) { Fail(StringFromFormat("Invalid '%s' parameter type", name)); return false; } @@ -196,3 +198,48 @@ bool DebuggerRequest::ParamBool(const char *name, bool *out, DebuggerParamType t Fail(StringFromFormat("Could not parse '%s' parameter: boolean required", name)); return false; } + +bool DebuggerRequest::ParamString(const char *name, std::string *out, DebuggerParamType type) { + bool allowLoose = type == DebuggerParamType::REQUIRED_LOOSE || type == DebuggerParamType::OPTIONAL_LOOSE; + bool required = type == DebuggerParamType::REQUIRED || type == DebuggerParamType::REQUIRED_LOOSE; + + const JsonNode *node = data.get(name); + if (!node) { + if (required) + Fail(StringFromFormat("Missing '%s' parameter", name)); + return !required; + } + + auto tag = node->value.getTag(); + if (tag == JSON_STRING) { + *out = node->value.toString(); + return true; + } else if (!allowLoose) { + if (required || tag != JSON_NULL) { + Fail(StringFromFormat("Invalid '%s' parameter type", name)); + return false; + } + return true; + } + + // For loose, let's allow a few things. + if (tag == JSON_TRUE) { + *out = "true"; + return true; + } else if (tag == JSON_FALSE) { + *out = "false"; + return true; + } else if (tag == JSON_NULL) { + if (required) { + *out = ""; + } + return true; + } else if (tag == JSON_NUMBER) { + // Will have a decimal place, though. + *out = StringFromFormat("%f", node->value.toNumber()); + return true; + } + + Fail(StringFromFormat("Invalid '%s' parameter type", name)); + return false; +} diff --git a/Core/Debugger/WebSocket/WebSocketUtils.h b/Core/Debugger/WebSocket/WebSocketUtils.h index 132789b26d..1391e6614c 100644 --- a/Core/Debugger/WebSocket/WebSocketUtils.h +++ b/Core/Debugger/WebSocket/WebSocketUtils.h @@ -82,6 +82,7 @@ struct DebuggerRequest { bool ParamU32(const char *name, uint32_t *out, bool allowFloatBits = false, DebuggerParamType type = DebuggerParamType::REQUIRED); bool ParamBool(const char *name, bool *out, DebuggerParamType type = DebuggerParamType::REQUIRED); + bool ParamString(const char *name, std::string *out, DebuggerParamType type = DebuggerParamType::REQUIRED); JsonWriter &Respond(); void Finish();