mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-11 13:36:24 +02:00
Debugger: Add memory breakpoint management.
This commit is contained in:
1 parent
29d93c56c7
commit
b2cc4a0965
9 files changed
+227
-13
No files matched your search
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Core/Debugger/Breakpoints.h"
|
||||
#include "Core/Debugger/DisassemblyManager.h"
|
||||
#include "Core/Debugger/SymbolMap.h"
|
||||
#include "Core/Debugger/WebSocket/BreakpointSubscriber.h"
|
||||
#include "Core/Debugger/WebSocket/WebSocketUtils.h"
|
||||
#include "Core/MIPS/MIPSDebugInterface.h"
|
||||
@@ -28,6 +30,11 @@ void *WebSocketBreakpointInit(DebuggerEventHandlerMap &map) {
|
||||
map["cpu.breakpoint.remove"] = &WebSocketCPUBreakpointRemove;
|
||||
map["cpu.breakpoint.list"] = &WebSocketCPUBreakpointList;
|
||||
|
||||
map["memory.breakpoint.add"] = &WebSocketMemoryBreakpointAdd;
|
||||
map["memory.breakpoint.update"] = &WebSocketMemoryBreakpointUpdate;
|
||||
map["memory.breakpoint.remove"] = &WebSocketMemoryBreakpointRemove;
|
||||
map["memory.breakpoint.list"] = &WebSocketMemoryBreakpointList;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -57,12 +64,12 @@ struct WebSocketCPUBreakpointParams {
|
||||
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))
|
||||
@@ -173,6 +180,172 @@ void WebSocketCPUBreakpointList(DebuggerRequest &req) {
|
||||
json.writeString("logFormat", bp.logFormat);
|
||||
else
|
||||
json.writeNull("logFormat");
|
||||
std::string symbol = g_symbolMap->GetLabelString(bp.addr);
|
||||
if (symbol.empty())
|
||||
json.writeNull("symbol");
|
||||
else
|
||||
json.writeString("symbol", symbol);
|
||||
|
||||
DisassemblyManager manager;
|
||||
DisassemblyLineInfo line;
|
||||
manager.getLine(manager.getStartAddress(bp.addr), true, line);
|
||||
json.writeString("code", line.name + " " + line.params);
|
||||
|
||||
json.pop();
|
||||
}
|
||||
json.pop();
|
||||
}
|
||||
|
||||
struct WebSocketMemoryBreakpointParams {
|
||||
uint32_t address = 0;
|
||||
uint32_t end = 0;
|
||||
bool hasEnabled = false;
|
||||
bool hasLog = false;
|
||||
bool hasCond = false;
|
||||
bool hasLogFormat = false;
|
||||
|
||||
bool enabled = true;
|
||||
bool log = true;
|
||||
MemCheckCondition cond = MEMCHECK_READWRITE;
|
||||
std::string logFormat;
|
||||
|
||||
bool Parse(DebuggerRequest &req) {
|
||||
if (!currentDebugMIPS->isAlive()) {
|
||||
req.Fail("CPU not started");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!req.ParamU32("address", &address))
|
||||
return false;
|
||||
uint32_t size;
|
||||
if (!req.ParamU32("size", &size))
|
||||
return false;
|
||||
if (address + size < address) {
|
||||
req.Fail("Size is too large");
|
||||
return false;
|
||||
}
|
||||
end = size == 0 ? 0 : address + size;
|
||||
|
||||
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;
|
||||
}
|
||||
hasCond = req.HasParam("read") || req.HasParam("write") || req.HasParam("change");
|
||||
if (hasCond) {
|
||||
bool read, write, change;
|
||||
if (!req.ParamBool("read", &read) || !req.ParamBool("write", &write) || !req.ParamBool("change", &change))
|
||||
return false;
|
||||
int bits = (read ? MEMCHECK_READ : 0) | (write ? MEMCHECK_WRITE : 0) | (change ? MEMCHECK_WRITE_ONCHANGE : 0);
|
||||
cond = MemCheckCondition(bits);
|
||||
}
|
||||
hasLogFormat = req.HasParam("logFormat");
|
||||
if (hasLogFormat) {
|
||||
if (!req.ParamString("logFormat", &logFormat))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BreakAction Result(bool adding) {
|
||||
int bits = MEMCHECK_READWRITE;
|
||||
if (adding || (hasLog && hasEnabled)) {
|
||||
bits = (enabled ? BREAK_ACTION_PAUSE : 0) | (log ? BREAK_ACTION_LOG : 0);
|
||||
} else {
|
||||
MemCheck prev;
|
||||
if (CBreakPoints::GetMemCheck(address, end, &prev))
|
||||
bits = prev.result;
|
||||
|
||||
if (hasEnabled)
|
||||
bits = (bits & ~BREAK_ACTION_PAUSE) | (enabled ? BREAK_ACTION_PAUSE : 0);
|
||||
if (hasLog)
|
||||
bits = (bits & ~BREAK_ACTION_LOG) | (log ? BREAK_ACTION_LOG : 0);
|
||||
}
|
||||
|
||||
return BreakAction(bits);
|
||||
}
|
||||
|
||||
void Apply() {
|
||||
if (hasLogFormat) {
|
||||
CBreakPoints::ChangeMemCheckLogFormat(address, end, logFormat);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void WebSocketMemoryBreakpointAdd(DebuggerRequest &req) {
|
||||
WebSocketMemoryBreakpointParams params;
|
||||
if (!params.Parse(req))
|
||||
return;
|
||||
|
||||
CBreakPoints::AddMemCheck(params.address, params.end, params.cond, params.Result(true));
|
||||
params.Apply();
|
||||
req.Respond();
|
||||
}
|
||||
|
||||
void WebSocketMemoryBreakpointUpdate(DebuggerRequest &req) {
|
||||
WebSocketMemoryBreakpointParams params;
|
||||
if (!params.Parse(req))
|
||||
return;
|
||||
|
||||
MemCheck mc;
|
||||
if (!CBreakPoints::GetMemCheck(params.address, params.end, &mc))
|
||||
return req.Fail("Breakpoint not found");
|
||||
|
||||
CBreakPoints::ChangeMemCheck(params.address, params.end, params.cond, params.Result(true));
|
||||
params.Apply();
|
||||
req.Respond();
|
||||
}
|
||||
|
||||
void WebSocketMemoryBreakpointRemove(DebuggerRequest &req) {
|
||||
if (!currentDebugMIPS->isAlive()) {
|
||||
return req.Fail("CPU not started");
|
||||
}
|
||||
|
||||
uint32_t address;
|
||||
if (!req.ParamU32("address", &address))
|
||||
return;
|
||||
uint32_t size;
|
||||
if (!req.ParamU32("size", &size))
|
||||
return;
|
||||
|
||||
CBreakPoints::RemoveMemCheck(address, size == 0 ? 0 : address + size);
|
||||
req.Respond();
|
||||
}
|
||||
|
||||
void WebSocketMemoryBreakpointList(DebuggerRequest &req) {
|
||||
if (!currentDebugMIPS->isAlive()) {
|
||||
return req.Fail("CPU not started");
|
||||
}
|
||||
|
||||
JsonWriter &json = req.Respond();
|
||||
json.pushArray("breakpoints");
|
||||
auto mcs = CBreakPoints::GetMemChecks();
|
||||
for (const auto &mc : mcs) {
|
||||
json.pushDict();
|
||||
json.writeUint("address", mc.start);
|
||||
json.writeUint("size", mc.end == 0 ? 0 : mc.end - mc.start);
|
||||
json.writeBool("enabled", mc.IsEnabled());
|
||||
json.writeBool("log", (mc.result & BREAK_ACTION_LOG) != 0);
|
||||
json.writeBool("read", (mc.cond & MEMCHECK_READ) != 0);
|
||||
json.writeBool("write", (mc.cond & MEMCHECK_WRITE) != 0);
|
||||
json.writeBool("change", (mc.cond & MEMCHECK_WRITE_ONCHANGE) != 0);
|
||||
json.writeUint("hits", mc.numHits);
|
||||
if (!mc.logFormat.empty())
|
||||
json.writeString("logFormat", mc.logFormat);
|
||||
else
|
||||
json.writeNull("logFormat");
|
||||
std::string symbol = g_symbolMap->GetLabelString(mc.start);
|
||||
if (symbol.empty())
|
||||
json.writeNull("symbol");
|
||||
else
|
||||
json.writeString("symbol", symbol);
|
||||
|
||||
json.pop();
|
||||
}
|
||||
json.pop();
|
||||
|
||||
Reference in new issue
Block a user