Skip to content
Permalink
Browse files

Debugger: Add cpu.evaluate method.

Probably useful for a bunch of things, really.
  • Loading branch information...
unknownbrackets committed Apr 30, 2018
1 parent 8a0e02e commit f66738eac705d39378b1a2de60bd6c648433fd4b
@@ -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));
}
@@ -27,3 +27,4 @@ void WebSocketCPUStatus(DebuggerRequest &req);
void WebSocketCPUGetAllRegs(DebuggerRequest &req);
void WebSocketCPUGetReg(DebuggerRequest &req);
void WebSocketCPUSetReg(DebuggerRequest &req);
void WebSocketCPUEvaluate(DebuggerRequest &req);
@@ -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;
}
@@ -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();

0 comments on commit f66738e

Please sign in to comment.
You can’t perform that action at this time.