mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Debugger: Initial disasm API.
This commit is contained in:
parent
4da97b3f9e
commit
944948a5f4
@ -1406,6 +1406,8 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||
Core/Debugger/WebSocket.h
|
||||
Core/Debugger/WebSocket/CPUCoreSubscriber.cpp
|
||||
Core/Debugger/WebSocket/CPUCoreSubscriber.h
|
||||
Core/Debugger/WebSocket/DisasmSubscriber.cpp
|
||||
Core/Debugger/WebSocket/DisasmSubscriber.h
|
||||
Core/Debugger/WebSocket/GameBroadcaster.cpp
|
||||
Core/Debugger/WebSocket/GameBroadcaster.h
|
||||
Core/Debugger/WebSocket/GameSubscriber.cpp
|
||||
|
@ -189,6 +189,7 @@
|
||||
<ClCompile Include="Debugger\WebSocket\GameBroadcaster.cpp" />
|
||||
<ClCompile Include="Debugger\WebSocket\GameSubscriber.cpp" />
|
||||
<ClCompile Include="Debugger\WebSocket\LogBroadcaster.cpp" />
|
||||
<ClCompile Include="Debugger\WebSocket\DisasmSubscriber.cpp" />
|
||||
<ClCompile Include="Debugger\WebSocket\SteppingBroadcaster.cpp" />
|
||||
<ClCompile Include="Debugger\WebSocket\WebSocketUtils.cpp" />
|
||||
<ClCompile Include="FileSystems\BlobFileSystem.cpp" />
|
||||
@ -541,6 +542,7 @@
|
||||
<ClInclude Include="AVIDump.h" />
|
||||
<ClInclude Include="Debugger\WebSocket.h" />
|
||||
<ClInclude Include="Debugger\WebSocket\GameSubscriber.h" />
|
||||
<ClInclude Include="Debugger\WebSocket\DisasmSubscriber.h" />
|
||||
<ClInclude Include="Debugger\WebSocket\WebSocketUtils.h" />
|
||||
<ClInclude Include="Debugger\WebSocket\CPUCoreSubscriber.h" />
|
||||
<ClInclude Include="Debugger\WebSocket\GameBroadcaster.h" />
|
||||
|
@ -716,6 +716,9 @@
|
||||
<ClCompile Include="Debugger\WebSocket\GameSubscriber.cpp">
|
||||
<Filter>Debugger\WebSocket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\WebSocket\DisasmSubscriber.cpp">
|
||||
<Filter>Debugger\WebSocket</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ELF\ElfReader.h">
|
||||
@ -1319,6 +1322,9 @@
|
||||
<ClInclude Include="Debugger\WebSocket\GameSubscriber.h">
|
||||
<Filter>Debugger\WebSocket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\WebSocket\DisasmSubscriber.h">
|
||||
<Filter>Debugger\WebSocket</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "Core/Debugger/WebSocket/SteppingBroadcaster.h"
|
||||
|
||||
#include "Core/Debugger/WebSocket/CPUCoreSubscriber.h"
|
||||
#include "Core/Debugger/WebSocket/DisasmSubscriber.h"
|
||||
#include "Core/Debugger/WebSocket/GameSubscriber.h"
|
||||
|
||||
typedef void *(*SubscriberInit)(DebuggerEventHandlerMap &map);
|
||||
@ -59,6 +60,7 @@ struct SubscriberInfo {
|
||||
|
||||
static const std::vector<SubscriberInfo> subscribers({
|
||||
{ &WebSocketCPUCoreInit, nullptr },
|
||||
{ &WebSocketDisasmInit, &WebSocketDisasmShutdown },
|
||||
{ &WebSocketGameInit, nullptr },
|
||||
});
|
||||
|
||||
|
@ -296,7 +296,7 @@ void WebSocketCPUSetReg(DebuggerRequest &req) {
|
||||
}
|
||||
|
||||
uint32_t val;
|
||||
if (!req.ParamU32OrFloatBits("value", &val)) {
|
||||
if (!req.ParamU32("value", &val, true)) {
|
||||
// Already sent error.
|
||||
return;
|
||||
}
|
||||
|
244
Core/Debugger/WebSocket/DisasmSubscriber.cpp
Normal file
244
Core/Debugger/WebSocket/DisasmSubscriber.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
// Copyright (c) 2018- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "base/stringutil.h"
|
||||
#include "Core/Debugger/Breakpoints.h"
|
||||
#include "Core/Debugger/DisassemblyManager.h"
|
||||
#include "Core/Debugger/WebSocket/DisasmSubscriber.h"
|
||||
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/MIPS/MIPSDebugInterface.h"
|
||||
|
||||
struct WebSocketDisasmState {
|
||||
WebSocketDisasmState() {
|
||||
disasm_.setCpu(currentDebugMIPS);
|
||||
}
|
||||
|
||||
void Base(DebuggerRequest &req);
|
||||
void Disasm(DebuggerRequest &req);
|
||||
|
||||
protected:
|
||||
void WriteDisasmLine(JsonWriter &json, const DisassemblyLineInfo &l);
|
||||
void WriteBranchGuide(JsonWriter &json, const BranchLine &l);
|
||||
|
||||
DisassemblyManager disasm_;
|
||||
};
|
||||
|
||||
void *WebSocketDisasmInit(DebuggerEventHandlerMap &map) {
|
||||
auto p = new WebSocketDisasmState();
|
||||
map["memory.base"] = std::bind(&WebSocketDisasmState::Base, p, std::placeholders::_1);
|
||||
map["memory.disasm"] = std::bind(&WebSocketDisasmState::Disasm, p, std::placeholders::_1);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void WebSocketDisasmShutdown(void *p) {
|
||||
delete static_cast<WebSocketDisasmState *>(p);
|
||||
}
|
||||
|
||||
void WebSocketDisasmState::WriteDisasmLine(JsonWriter &json, const DisassemblyLineInfo &l) {
|
||||
u32 addr = l.info.opcodeAddress;
|
||||
json.pushDict();
|
||||
if (l.type == DISTYPE_OPCODE)
|
||||
json.writeString("type", "opcode");
|
||||
else if (l.type == DISTYPE_MACRO)
|
||||
json.writeString("type", "macro");
|
||||
else if (l.type == DISTYPE_DATA)
|
||||
json.writeString("type", "data");
|
||||
else if (l.type == DISTYPE_OTHER)
|
||||
json.writeString("type", "other");
|
||||
|
||||
json.writeFloat("address", addr);
|
||||
json.writeInt("addressSize", l.totalSize);
|
||||
json.writeFloat("encoding", l.info.encodedOpcode.encoding);
|
||||
int c = currentDebugMIPS->getColor(addr) & 0x00FFFFFF;
|
||||
json.writeString("backgroundColor", StringFromFormat("#%02x%02x%02x", c & 0xFF, (c >> 8) & 0xFF, c >> 16));
|
||||
json.writeString("name", l.name);
|
||||
json.writeString("params", l.params);
|
||||
|
||||
const std::string addressSymbol = g_symbolMap->GetLabelString(addr);
|
||||
if (addressSymbol.empty())
|
||||
json.writeRaw("symbol", "null");
|
||||
else
|
||||
json.writeString("symbol", addressSymbol);
|
||||
|
||||
bool enabled;
|
||||
// TODO: Account for bp inside macro?
|
||||
if (CBreakPoints::IsAddressBreakPoint(addr, &enabled)) {
|
||||
json.pushDict("breakpoint");
|
||||
json.writeBool("enabled", enabled);
|
||||
auto cond = CBreakPoints::GetBreakPointCondition(addr);
|
||||
if (cond)
|
||||
json.writeString("expression", cond->expressionString);
|
||||
else
|
||||
json.writeRaw("expression", "null");
|
||||
json.pop();
|
||||
} else {
|
||||
json.writeRaw("breakpoint", "null");
|
||||
}
|
||||
|
||||
json.writeBool("isCurrentPC", currentDebugMIPS->GetPC() == addr);
|
||||
if (l.info.isBranch) {
|
||||
json.pushDict("branch");
|
||||
if (!l.info.isBranchToRegister) {
|
||||
json.writeFloat("targetAddress", l.info.branchTarget);
|
||||
json.writeRaw("register", "null");
|
||||
} else {
|
||||
json.writeRaw("targetAddress", "null");
|
||||
json.writeInt("register", l.info.branchRegisterNum);
|
||||
}
|
||||
json.writeBool("isLinked", l.info.isLinkedBranch);
|
||||
json.writeBool("isLikely", l.info.isLikelyBranch);
|
||||
json.pop();
|
||||
} else {
|
||||
json.writeRaw("branch", "null");
|
||||
}
|
||||
|
||||
if (l.info.hasRelevantAddress) {
|
||||
json.pushDict("relevantData");
|
||||
json.writeFloat("address", l.info.relevantAddress);
|
||||
if (Memory::IsValidRange(l.info.relevantAddress, 4))
|
||||
json.writeFloat("uintValue", Memory::ReadUnchecked_U32(l.info.relevantAddress));
|
||||
else
|
||||
json.writeRaw("uintValue", "null");
|
||||
json.pop();
|
||||
} else {
|
||||
json.writeRaw("relevantData", "null");
|
||||
}
|
||||
|
||||
if (l.info.isConditional)
|
||||
json.writeBool("conditionMet", l.info.conditionMet);
|
||||
else
|
||||
json.writeRaw("conditionMet", "null");
|
||||
|
||||
if (l.info.isDataAccess) {
|
||||
json.pushDict("dataAccess");
|
||||
json.writeFloat("address", l.info.dataAddress);
|
||||
json.writeInt("size", l.info.dataSize);
|
||||
|
||||
std::string dataSymbol = g_symbolMap->GetLabelString(l.info.dataAddress);
|
||||
std::string valueSymbol;
|
||||
if (!Memory::IsValidRange(l.info.dataAddress, l.info.dataSize))
|
||||
json.writeRaw("uintValue", "null");
|
||||
else if (l.info.dataSize == 1)
|
||||
json.writeFloat("uintValue", Memory::ReadUnchecked_U8(l.info.dataAddress));
|
||||
else if (l.info.dataSize == 2)
|
||||
json.writeFloat("uintValue", Memory::ReadUnchecked_U16(l.info.dataAddress));
|
||||
else if (l.info.dataSize >= 4) {
|
||||
u32 data = Memory::ReadUnchecked_U32(l.info.dataAddress);
|
||||
valueSymbol = g_symbolMap->GetLabelString(data);
|
||||
json.writeFloat("uintValue", data);
|
||||
}
|
||||
|
||||
if (!dataSymbol.empty())
|
||||
json.writeString("symbol", dataSymbol);
|
||||
else
|
||||
json.writeRaw("symbol", "null");
|
||||
if (!valueSymbol.empty())
|
||||
json.writeString("valueSymbol", valueSymbol);
|
||||
else
|
||||
json.writeRaw("valueSymbol", "null");
|
||||
json.pop();
|
||||
} else {
|
||||
json.writeRaw("dataAccess", "null");
|
||||
}
|
||||
|
||||
json.pop();
|
||||
}
|
||||
|
||||
void WebSocketDisasmState::WriteBranchGuide(JsonWriter &json, const BranchLine &l) {
|
||||
json.pushDict();
|
||||
json.writeFloat("top", l.first);
|
||||
json.writeFloat("bottom", l.second);
|
||||
if (l.type == LINE_UP)
|
||||
json.writeString("direction", "up");
|
||||
else if (l.type == LINE_DOWN)
|
||||
json.writeString("direction", "down");
|
||||
else if (l.type == LINE_RIGHT)
|
||||
json.writeString("direction", "right");
|
||||
json.writeInt("lane", l.laneIndex);
|
||||
json.pop();
|
||||
}
|
||||
|
||||
void WebSocketDisasmState::Base(DebuggerRequest &req) {
|
||||
JsonWriter &json = req.Respond();
|
||||
json.writeString("addressHex", StringFromFormat("%016llx", Memory::base));
|
||||
}
|
||||
|
||||
void WebSocketDisasmState::Disasm(DebuggerRequest &req) {
|
||||
if (!currentDebugMIPS->isAlive() || !Memory::IsActive()) {
|
||||
return req.Fail("CPU not started");
|
||||
}
|
||||
|
||||
uint32_t start, end;
|
||||
if (!req.ParamU32("address", &start))
|
||||
return;
|
||||
uint32_t count = 0;
|
||||
if (!req.ParamU32("count", &count, false, DebuggerParamType::OPTIONAL))
|
||||
return;
|
||||
if (count != 0) {
|
||||
// Let's assume everything is two instructions.
|
||||
disasm_.analyze(start - 4, count * 8 + 8);
|
||||
start = disasm_.getStartAddress(start);
|
||||
if (start == -1)
|
||||
req.ParamU32("address", &start);
|
||||
end = disasm_.getNthNextAddress(start, count);
|
||||
} else if (req.ParamU32("end", &end)) {
|
||||
// Let's assume everything is two instructions.
|
||||
disasm_.analyze(start - 4, end - start + 8);
|
||||
start = disasm_.getStartAddress(start);
|
||||
if (start == -1)
|
||||
req.ParamU32("address", &start);
|
||||
|
||||
// Correct end and calculate count based on it.
|
||||
// This accounts for macros as one line, although two instructions.
|
||||
u32 stop = end;
|
||||
count = 0;
|
||||
for (end = start; end < stop; end = disasm_.getNthNextAddress(end, 1)) {
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
// Error message already sent.
|
||||
return;
|
||||
}
|
||||
|
||||
bool displaySymbols = true;
|
||||
if (!req.ParamBool("displaySymbols", &displaySymbols, DebuggerParamType::OPTIONAL))
|
||||
return;
|
||||
|
||||
JsonWriter &json = req.Respond();
|
||||
json.pushDict("range");
|
||||
json.writeFloat("start", start);
|
||||
json.writeFloat("end", end);
|
||||
json.pop();
|
||||
|
||||
json.pushArray("lines");
|
||||
DisassemblyLineInfo line;
|
||||
u32 addr = start;
|
||||
for (u32 i = 0; i < count; ++i) {
|
||||
disasm_.getLine(addr, displaySymbols, line);
|
||||
WriteDisasmLine(json, line);
|
||||
addr += line.totalSize;
|
||||
}
|
||||
json.pop();
|
||||
|
||||
json.pushArray("branchGuides");
|
||||
auto branchGuides = disasm_.getBranchLines(start, end - start);
|
||||
for (auto bl : branchGuides)
|
||||
WriteBranchGuide(json, bl);
|
||||
json.pop();
|
||||
}
|
23
Core/Debugger/WebSocket/DisasmSubscriber.h
Normal file
23
Core/Debugger/WebSocket/DisasmSubscriber.h
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2018- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
|
||||
|
||||
void *WebSocketDisasmInit(DebuggerEventHandlerMap &map);
|
||||
void WebSocketDisasmShutdown(void *p);
|
@ -74,19 +74,35 @@ static bool U32FromString(const char *str, uint32_t *out, bool allowFloat) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DebuggerRequest::ParamU32(const char *name, uint32_t *out) {
|
||||
bool DebuggerRequest::ParamU32(const char *name, uint32_t *out, bool allowFloatBits, 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) {
|
||||
Fail(StringFromFormat("Missing '%s' parameter", name));
|
||||
return false;
|
||||
if (required)
|
||||
Fail(StringFromFormat("Missing '%s' parameter", name));
|
||||
return !required;
|
||||
}
|
||||
|
||||
if (node->value.getTag() == JSON_NUMBER) {
|
||||
double val = node->value.toNumber();
|
||||
bool isInteger = trunc(val) == val;
|
||||
if (!isInteger) {
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: integer required", name));
|
||||
if (!isInteger && !allowLoose) {
|
||||
// JSON doesn't give a great way to differentiate ints and floats.
|
||||
// Let's play it safe and require a string.
|
||||
if (allowFloatBits)
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: use a string for non integer values", name));
|
||||
else
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: integer required", name));
|
||||
return false;
|
||||
} else if (!isInteger && allowFloatBits) {
|
||||
union {
|
||||
float f;
|
||||
uint32_t u;
|
||||
} bits = { (float)val };
|
||||
*out = bits.u;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (val < 0 && val >= std::numeric_limits<int32_t>::min()) {
|
||||
@ -96,61 +112,87 @@ bool DebuggerRequest::ParamU32(const char *name, uint32_t *out) {
|
||||
} else if (val >= 0 && val <= std::numeric_limits<uint32_t>::max()) {
|
||||
*out = (uint32_t)val;
|
||||
return true;
|
||||
} else if (allowLoose) {
|
||||
*out = val >= 0 ? std::numeric_limits<uint32_t>::max() : std::numeric_limits<uint32_t>::min();
|
||||
return true;
|
||||
}
|
||||
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: outside 32 bit range", name));
|
||||
if (allowFloatBits)
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: outside 32 bit range (use string for float)", name));
|
||||
else
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: outside 32 bit range", name));
|
||||
return false;
|
||||
}
|
||||
if (node->value.getTag() != JSON_STRING) {
|
||||
Fail(StringFromFormat("Invalid '%s' parameter type", name));
|
||||
return false;
|
||||
if (required || node->value.getTag() != JSON_NULL) {
|
||||
Fail(StringFromFormat("Invalid '%s' parameter type", name));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (U32FromString(node->value.toString(), out, false))
|
||||
if (U32FromString(node->value.toString(), out, allowFloatBits))
|
||||
return true;
|
||||
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: integer required", name));
|
||||
if (allowFloatBits)
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: number expected", name));
|
||||
else
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: integer required", name));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DebuggerRequest::ParamU32OrFloatBits(const char *name, uint32_t *out) {
|
||||
bool DebuggerRequest::ParamBool(const char *name, bool *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) {
|
||||
Fail(StringFromFormat("Missing '%s' parameter", name));
|
||||
return false;
|
||||
if (required)
|
||||
Fail(StringFromFormat("Missing '%s' parameter", name));
|
||||
return !required;
|
||||
}
|
||||
|
||||
if (node->value.getTag() == JSON_NUMBER) {
|
||||
double val = node->value.toNumber();
|
||||
bool isInteger = trunc(val) == val;
|
||||
|
||||
// JSON doesn't give a great way to differentiate ints and floats.
|
||||
// Let's play it safe and require a string.
|
||||
if (!isInteger) {
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: use a string for non integer values", name));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (val < 0 && val >= std::numeric_limits<int32_t>::min()) {
|
||||
// Convert to unsigned representation.
|
||||
*out = (uint32_t)(int32_t)val;
|
||||
return true;
|
||||
} else if (val >= 0 && val <= std::numeric_limits<uint32_t>::max()) {
|
||||
*out = (uint32_t)val;
|
||||
if (val == 1.0 || val == 0.0 || allowLoose) {
|
||||
*out = val != 0.0;
|
||||
return true;
|
||||
}
|
||||
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: outside 32 bit range (use string for float)", name));
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: should be true/1 or false/0", name));
|
||||
return false;
|
||||
}
|
||||
if (node->value.getTag() == JSON_TRUE) {
|
||||
*out = true;
|
||||
return true;
|
||||
}
|
||||
if (node->value.getTag() == JSON_FALSE) {
|
||||
*out = false;
|
||||
return true;
|
||||
}
|
||||
if (node->value.getTag() != JSON_STRING) {
|
||||
Fail(StringFromFormat("Invalid '%s' parameter type", name));
|
||||
return false;
|
||||
if (type == DebuggerParamType::REQUIRED || node->value.getTag() != JSON_NULL) {
|
||||
Fail(StringFromFormat("Invalid '%s' parameter type", name));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (U32FromString(node->value.toString(), out, true))
|
||||
const std::string s = node->value.toString();
|
||||
if (s == "1" || s == "true") {
|
||||
*out = true;
|
||||
return true;
|
||||
}
|
||||
if (s == "0" || s == "false" || (s == "" && allowLoose)) {
|
||||
*out = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: number expected", name));
|
||||
if (allowLoose) {
|
||||
*out = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
Fail(StringFromFormat("Could not parse '%s' parameter: boolean required", name));
|
||||
return false;
|
||||
}
|
||||
|
@ -59,6 +59,13 @@ struct DebuggerErrorEvent {
|
||||
}
|
||||
};
|
||||
|
||||
enum class DebuggerParamType {
|
||||
REQUIRED,
|
||||
OPTIONAL,
|
||||
REQUIRED_LOOSE,
|
||||
OPTIONAL_LOOSE,
|
||||
};
|
||||
|
||||
struct DebuggerRequest {
|
||||
DebuggerRequest(const char *n, net::WebSocketServer *w, const JsonGet &d)
|
||||
: name(n), ws(w), data(d) {
|
||||
@ -73,8 +80,8 @@ struct DebuggerRequest {
|
||||
responseSent_ = true;
|
||||
}
|
||||
|
||||
bool ParamU32(const char *name, uint32_t *out);
|
||||
bool ParamU32OrFloatBits(const char *name, uint32_t *out);
|
||||
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);
|
||||
|
||||
JsonWriter &Respond();
|
||||
void Finish();
|
||||
|
@ -299,9 +299,11 @@ EXEC_AND_LIB_FILES := \
|
||||
$(SRC)/Core/TextureReplacer.cpp \
|
||||
$(SRC)/Core/WebServer.cpp \
|
||||
$(SRC)/Core/Debugger/Breakpoints.cpp \
|
||||
$(SRC)/Core/Debugger/DisassemblyManager.cpp \
|
||||
$(SRC)/Core/Debugger/SymbolMap.cpp \
|
||||
$(SRC)/Core/Debugger/WebSocket.cpp \
|
||||
$(SRC)/Core/Debugger/WebSocket/CPUCoreSubscriber.cpp \
|
||||
$(SRC)/Core/Debugger/WebSocket/DisasmSubscriber.cpp \
|
||||
$(SRC)/Core/Debugger/WebSocket/GameBroadcaster.cpp \
|
||||
$(SRC)/Core/Debugger/WebSocket/GameSubscriber.cpp \
|
||||
$(SRC)/Core/Debugger/WebSocket/LogBroadcaster.cpp \
|
||||
|
Loading…
Reference in New Issue
Block a user