mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-26 23:10:38 +00:00
Debugger: Initial breakpoint APIs.
This commit is contained in:
parent
18dcea4cdc
commit
29d93c56c7
@ -1404,6 +1404,8 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||
Core/Debugger/DisassemblyManager.h
|
||||
Core/Debugger/WebSocket.cpp
|
||||
Core/Debugger/WebSocket.h
|
||||
Core/Debugger/WebSocket/BreakpointSubscriber.cpp
|
||||
Core/Debugger/WebSocket/BreakpointSubscriber.h
|
||||
Core/Debugger/WebSocket/CPUCoreSubscriber.cpp
|
||||
Core/Debugger/WebSocket/CPUCoreSubscriber.h
|
||||
Core/Debugger/WebSocket/DisasmSubscriber.cpp
|
||||
|
@ -185,6 +185,7 @@
|
||||
<ClCompile Include="..\ext\udis86\udis86.c" />
|
||||
<ClCompile Include="AVIDump.cpp" />
|
||||
<ClCompile Include="Debugger\WebSocket.cpp" />
|
||||
<ClCompile Include="Debugger\WebSocket\BreakpointSubscriber.cpp" />
|
||||
<ClCompile Include="Debugger\WebSocket\CPUCoreSubscriber.cpp" />
|
||||
<ClCompile Include="Debugger\WebSocket\GameBroadcaster.cpp" />
|
||||
<ClCompile Include="Debugger\WebSocket\GameSubscriber.cpp" />
|
||||
@ -542,6 +543,7 @@
|
||||
<ClInclude Include="..\ext\udis86\udis86.h" />
|
||||
<ClInclude Include="AVIDump.h" />
|
||||
<ClInclude Include="Debugger\WebSocket.h" />
|
||||
<ClInclude Include="Debugger\WebSocket\BreakpointSubscriber.h" />
|
||||
<ClInclude Include="Debugger\WebSocket\GameSubscriber.h" />
|
||||
<ClInclude Include="Debugger\WebSocket\DisasmSubscriber.h" />
|
||||
<ClInclude Include="Debugger\WebSocket\SteppingSubscriber.h" />
|
||||
|
@ -722,6 +722,9 @@
|
||||
<ClCompile Include="Debugger\WebSocket\SteppingSubscriber.cpp">
|
||||
<Filter>Debugger\WebSocket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\WebSocket\BreakpointSubscriber.cpp">
|
||||
<Filter>Debugger\WebSocket</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ELF\ElfReader.h">
|
||||
@ -1331,6 +1334,9 @@
|
||||
<ClInclude Include="Debugger\WebSocket\SteppingSubscriber.h">
|
||||
<Filter>Debugger\WebSocket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\WebSocket\BreakpointSubscriber.h">
|
||||
<Filter>Debugger\WebSocket</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "Core/Debugger/WebSocket/LogBroadcaster.h"
|
||||
#include "Core/Debugger/WebSocket/SteppingBroadcaster.h"
|
||||
|
||||
#include "Core/Debugger/WebSocket/BreakpointSubscriber.h"
|
||||
#include "Core/Debugger/WebSocket/CPUCoreSubscriber.h"
|
||||
#include "Core/Debugger/WebSocket/DisasmSubscriber.h"
|
||||
#include "Core/Debugger/WebSocket/GameSubscriber.h"
|
||||
@ -60,6 +61,7 @@ struct SubscriberInfo {
|
||||
};
|
||||
|
||||
static const std::vector<SubscriberInfo> subscribers({
|
||||
{ &WebSocketBreakpointInit, nullptr },
|
||||
{ &WebSocketCPUCoreInit, nullptr },
|
||||
{ &WebSocketDisasmInit, &WebSocketDisasmShutdown },
|
||||
{ &WebSocketGameInit, nullptr },
|
||||
|
179
Core/Debugger/WebSocket/BreakpointSubscriber.cpp
Normal file
179
Core/Debugger/WebSocket/BreakpointSubscriber.cpp
Normal file
@ -0,0 +1,179 @@
|
||||
// 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 "Common/StringUtils.h"
|
||||
#include "Core/Debugger/Breakpoints.h"
|
||||
#include "Core/Debugger/WebSocket/BreakpointSubscriber.h"
|
||||
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
|
||||
#include "Core/MIPS/MIPSDebugInterface.h"
|
||||
|
||||
void *WebSocketBreakpointInit(DebuggerEventHandlerMap &map) {
|
||||
// No need to bind or alloc state, these are all global.
|
||||
map["cpu.breakpoint.add"] = &WebSocketCPUBreakpointAdd;
|
||||
map["cpu.breakpoint.update"] = &WebSocketCPUBreakpointUpdate;
|
||||
map["cpu.breakpoint.remove"] = &WebSocketCPUBreakpointRemove;
|
||||
map["cpu.breakpoint.list"] = &WebSocketCPUBreakpointList;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct WebSocketCPUBreakpointParams {
|
||||
uint32_t address = 0;
|
||||
bool hasEnabled = false;
|
||||
bool hasLog = false;
|
||||
bool hasCondition = false;
|
||||
bool hasLogFormat = false;
|
||||
|
||||
bool enabled;
|
||||
bool log;
|
||||
std::string condition;
|
||||
PostfixExpression compiledCondition;
|
||||
std::string logFormat;
|
||||
|
||||
bool Parse(DebuggerRequest &req) {
|
||||
if (!currentDebugMIPS->isAlive()) {
|
||||
req.Fail("CPU not started");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!req.ParamU32("address", &address))
|
||||
return false;
|
||||
|
||||
hasEnabled = req.HasParam("enabled");
|
||||
if (hasEnabled) {
|
||||
if (!req.ParamBool("enabled", &enabled))
|
||||
return false;
|
||||
}
|
||||
hasLog = req.HasParam("log");
|
||||
if (hasLog) {
|
||||
if (!req.ParamBool("log", &log))
|
||||
return false;
|
||||
}
|
||||
hasCondition = req.HasParam("condition");
|
||||
if (hasCondition) {
|
||||
if (!req.ParamString("condition", &condition))
|
||||
return false;
|
||||
if (!currentDebugMIPS->initExpression(condition.c_str(), compiledCondition)) {
|
||||
req.Fail(StringFromFormat("Could not parse expression syntax: %s", getExpressionError()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
hasLogFormat = req.HasParam("logFormat");
|
||||
if (hasLogFormat) {
|
||||
if (!req.ParamString("logFormat", &logFormat))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Apply() {
|
||||
if (hasCondition && !condition.empty()) {
|
||||
BreakPointCond cond;
|
||||
cond.debug = currentDebugMIPS;
|
||||
cond.expressionString = condition;
|
||||
cond.expression = compiledCondition;
|
||||
CBreakPoints::ChangeBreakPointAddCond(address, cond);
|
||||
} else if (hasCondition && condition.empty()) {
|
||||
CBreakPoints::ChangeBreakPointRemoveCond(address);
|
||||
}
|
||||
|
||||
if (hasLogFormat) {
|
||||
CBreakPoints::ChangeBreakPointLogFormat(address, logFormat);
|
||||
}
|
||||
|
||||
// TODO: Fix this interface.
|
||||
if (hasLog && !hasEnabled) {
|
||||
CBreakPoints::IsAddressBreakPoint(address, &enabled);
|
||||
hasEnabled = true;
|
||||
}
|
||||
if (hasLog && hasEnabled) {
|
||||
BreakAction result = BREAK_ACTION_IGNORE;
|
||||
if (log)
|
||||
result |= BREAK_ACTION_LOG;
|
||||
if (enabled)
|
||||
result |= BREAK_ACTION_PAUSE;
|
||||
CBreakPoints::ChangeBreakPoint(address, result);
|
||||
} else if (hasEnabled) {
|
||||
CBreakPoints::ChangeBreakPoint(address, enabled);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void WebSocketCPUBreakpointAdd(DebuggerRequest &req) {
|
||||
WebSocketCPUBreakpointParams params;
|
||||
if (!params.Parse(req))
|
||||
return;
|
||||
|
||||
CBreakPoints::AddBreakPoint(params.address);
|
||||
params.Apply();
|
||||
req.Respond();
|
||||
}
|
||||
|
||||
void WebSocketCPUBreakpointUpdate(DebuggerRequest &req) {
|
||||
WebSocketCPUBreakpointParams params;
|
||||
if (!params.Parse(req))
|
||||
return;
|
||||
bool enabled;
|
||||
if (!CBreakPoints::IsAddressBreakPoint(params.address, &enabled))
|
||||
return req.Fail("Breakpoint not found");
|
||||
|
||||
params.Apply();
|
||||
req.Respond();
|
||||
}
|
||||
|
||||
void WebSocketCPUBreakpointRemove(DebuggerRequest &req) {
|
||||
if (!currentDebugMIPS->isAlive()) {
|
||||
return req.Fail("CPU not started");
|
||||
}
|
||||
|
||||
uint32_t address;
|
||||
if (!req.ParamU32("address", &address))
|
||||
return;
|
||||
|
||||
CBreakPoints::RemoveBreakPoint(address);
|
||||
req.Respond();
|
||||
}
|
||||
|
||||
void WebSocketCPUBreakpointList(DebuggerRequest &req) {
|
||||
if (!currentDebugMIPS->isAlive()) {
|
||||
return req.Fail("CPU not started");
|
||||
}
|
||||
|
||||
JsonWriter &json = req.Respond();
|
||||
json.pushArray("breakpoints");
|
||||
auto bps = CBreakPoints::GetBreakpoints();
|
||||
for (const auto &bp : bps) {
|
||||
if (bp.temporary)
|
||||
continue;
|
||||
|
||||
json.pushDict();
|
||||
json.writeUint("address", bp.addr);
|
||||
json.writeBool("enabled", bp.IsEnabled());
|
||||
json.writeBool("log", (bp.result & BREAK_ACTION_LOG) != 0);
|
||||
if (bp.hasCond)
|
||||
json.writeString("condition", bp.cond.expressionString);
|
||||
else
|
||||
json.writeNull("condition");
|
||||
if (!bp.logFormat.empty())
|
||||
json.writeString("logFormat", bp.logFormat);
|
||||
else
|
||||
json.writeNull("logFormat");
|
||||
json.pop();
|
||||
}
|
||||
json.pop();
|
||||
}
|
27
Core/Debugger/WebSocket/BreakpointSubscriber.h
Normal file
27
Core/Debugger/WebSocket/BreakpointSubscriber.h
Normal file
@ -0,0 +1,27 @@
|
||||
// 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 *WebSocketBreakpointInit(DebuggerEventHandlerMap &map);
|
||||
|
||||
void WebSocketCPUBreakpointAdd(DebuggerRequest &req);
|
||||
void WebSocketCPUBreakpointUpdate(DebuggerRequest &req);
|
||||
void WebSocketCPUBreakpointRemove(DebuggerRequest &req);
|
||||
void WebSocketCPUBreakpointList(DebuggerRequest &req);
|
@ -85,6 +85,17 @@ static bool U32FromString(const char *str, uint32_t *out, bool allowFloat) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DebuggerRequest::HasParam(const char *name, bool ignoreNull) {
|
||||
const JsonNode *node = data.get(name);
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
if (node->value.getTag() == JSON_NULL) {
|
||||
return !ignoreNull;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -136,7 +147,7 @@ bool DebuggerRequest::ParamU32(const char *name, uint32_t *out, bool allowFloatB
|
||||
return false;
|
||||
}
|
||||
if (tag != JSON_STRING) {
|
||||
if (required || tag != JSON_NULL) {
|
||||
if (type == DebuggerParamType::REQUIRED || tag != JSON_NULL) {
|
||||
Fail(StringFromFormat("Invalid '%s' parameter type", name));
|
||||
return false;
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ struct DebuggerRequest {
|
||||
responseSent_ = true;
|
||||
}
|
||||
|
||||
bool HasParam(const char *name, bool ignoreNull = false);
|
||||
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);
|
||||
|
@ -302,6 +302,7 @@ EXEC_AND_LIB_FILES := \
|
||||
$(SRC)/Core/Debugger/DisassemblyManager.cpp \
|
||||
$(SRC)/Core/Debugger/SymbolMap.cpp \
|
||||
$(SRC)/Core/Debugger/WebSocket.cpp \
|
||||
$(SRC)/Core/Debugger/WebSocket/BreakpointSubscriber.cpp \
|
||||
$(SRC)/Core/Debugger/WebSocket/CPUCoreSubscriber.cpp \
|
||||
$(SRC)/Core/Debugger/WebSocket/DisasmSubscriber.cpp \
|
||||
$(SRC)/Core/Debugger/WebSocket/GameBroadcaster.cpp \
|
||||
|
Loading…
Reference in New Issue
Block a user