Debugger: Allow conditions on threadID/moduleID.

And now step over/out/into can tie to the correct thread.
This commit is contained in:
Unknown W. Brackets 2018-05-12 06:11:55 -07:00
parent a863ce79ad
commit b114656321
4 changed files with 56 additions and 23 deletions

View File

@ -297,7 +297,7 @@ void CBreakPoints::ClearTemporaryBreakPoints()
void CBreakPoints::ChangeBreakPointAddCond(u32 addr, const BreakPointCond &cond)
{
std::unique_lock<std::mutex> guard(breakPointsMutex_);
size_t bp = FindBreakpoint(addr, true, false);
size_t bp = FindBreakpoint(addr);
if (bp != INVALID_BREAKPOINT)
{
breakPoints_[bp].hasCond = true;
@ -310,7 +310,7 @@ void CBreakPoints::ChangeBreakPointAddCond(u32 addr, const BreakPointCond &cond)
void CBreakPoints::ChangeBreakPointRemoveCond(u32 addr)
{
std::unique_lock<std::mutex> guard(breakPointsMutex_);
size_t bp = FindBreakpoint(addr, true, false);
size_t bp = FindBreakpoint(addr);
if (bp != INVALID_BREAKPOINT)
{
breakPoints_[bp].hasCond = false;
@ -322,7 +322,7 @@ void CBreakPoints::ChangeBreakPointRemoveCond(u32 addr)
BreakPointCond *CBreakPoints::GetBreakPointCondition(u32 addr)
{
std::lock_guard<std::mutex> guard(breakPointsMutex_);
size_t bp = FindBreakpoint(addr, true, false);
size_t bp = FindBreakpoint(addr);
if (bp != INVALID_BREAKPOINT && breakPoints_[bp].hasCond)
return &breakPoints_[bp].cond;
return NULL;

View File

@ -133,7 +133,7 @@ public:
static void ClearAllBreakPoints();
static void ClearTemporaryBreakPoints();
// Makes a copy. Temporary breakpoints can't have conditions.
// Makes a copy of the condition.
static void ChangeBreakPointAddCond(u32 addr, const BreakPointCond &cond);
static void ChangeBreakPointRemoveCond(u32 addr);
static BreakPointCond *GetBreakPointCondition(u32 addr);

View File

@ -43,9 +43,10 @@ struct WebSocketSteppingState {
void HLE(DebuggerRequest &req);
protected:
u32 GetNextAddress(DebugInterface *cpuDebug);
uint32_t GetNextAddress(DebugInterface *cpuDebug);
int GetNextInstructionCount(DebugInterface *cpuDebug);
void PrepareResume();
void AddThreadCondition(uint32_t breakpointAddress, uint32_t threadID);
DisassemblyManager disasm_;
};
@ -65,14 +66,14 @@ void WebSocketSteppingShutdown(void *p) {
delete static_cast<WebSocketSteppingState *>(p);
}
static DebugInterface *CPUFromRequest(DebuggerRequest &req, u32 *threadID = nullptr) {
static DebugInterface *CPUFromRequest(DebuggerRequest &req, uint32_t *threadID = nullptr) {
if (!req.HasParam("thread")) {
if (threadID)
*threadID = -1;
return currentDebugMIPS;
}
u32 uid;
uint32_t uid;
if (!req.ParamU32("thread", &uid))
return nullptr;
@ -100,7 +101,8 @@ void WebSocketSteppingState::Into(DebuggerRequest &req) {
return;
}
auto cpuDebug = CPUFromRequest(req);
uint32_t threadID;
auto cpuDebug = CPUFromRequest(req, &threadID);
if (!cpuDebug)
return;
@ -113,13 +115,14 @@ void WebSocketSteppingState::Into(DebuggerRequest &req) {
Core_DoSingleStep();
}
} else {
u32 breakpointAddress = cpuDebug->GetPC();
uint32_t breakpointAddress = cpuDebug->GetPC();
PrepareResume();
// Could have advanced to the breakpoint already in PrepareResume().
// Note: we need to get cpuDebug again anyway (in case we ran some HLE above.)
cpuDebug = CPUFromRequest(req);
if (cpuDebug != currentDebugMIPS) {
CBreakPoints::AddBreakPoint(breakpointAddress, true);
AddThreadCondition(breakpointAddress, threadID);
Core_EnableStepping(false);
}
}
@ -140,12 +143,14 @@ void WebSocketSteppingState::Over(DebuggerRequest &req) {
return req.Fail("CPU not started");
if (!Core_IsStepping())
return req.Fail("CPU currently running (cpu.stepping first)");
auto cpuDebug = CPUFromRequest(req);
uint32_t threadID;
auto cpuDebug = CPUFromRequest(req, &threadID);
if (!cpuDebug)
return;
MipsOpcodeInfo info = GetOpcodeInfo(cpuDebug, cpuDebug->GetPC());
u32 breakpointAddress = GetNextAddress(cpuDebug);
uint32_t breakpointAddress = GetNextAddress(cpuDebug);
if (info.isBranch) {
if (info.isConditional && !info.isLinkedBranch) {
if (info.conditionMet) {
@ -170,6 +175,8 @@ void WebSocketSteppingState::Over(DebuggerRequest &req) {
cpuDebug = CPUFromRequest(req);
if (cpuDebug->GetPC() != breakpointAddress) {
CBreakPoints::AddBreakPoint(breakpointAddress, true);
if (cpuDebug != currentDebugMIPS)
AddThreadCondition(breakpointAddress, threadID);
Core_EnableStepping(false);
}
}
@ -187,14 +194,15 @@ void WebSocketSteppingState::Out(DebuggerRequest &req) {
return req.Fail("CPU not started");
if (!Core_IsStepping())
return req.Fail("CPU currently running (cpu.stepping first)");
u32 threadID;
uint32_t threadID;
auto cpuDebug = CPUFromRequest(req, &threadID);
if (!cpuDebug)
return;
auto threads = GetThreadsInfo();
u32 entry = cpuDebug->GetPC();
u32 stackTop = 0;
uint32_t entry = cpuDebug->GetPC();
uint32_t stackTop = 0;
for (const DebugThreadInfo &th : threads) {
if ((threadID == -1 && th.isCurrent) || th.id == threadID) {
entry = th.entrypoint;
@ -203,20 +211,21 @@ void WebSocketSteppingState::Out(DebuggerRequest &req) {
}
}
u32 ra = cpuDebug->GetRegValue(0, MIPS_REG_RA);
u32 sp = cpuDebug->GetRegValue(0, MIPS_REG_SP);
uint32_t ra = cpuDebug->GetRegValue(0, MIPS_REG_RA);
uint32_t sp = cpuDebug->GetRegValue(0, MIPS_REG_SP);
auto frames = MIPSStackWalk::Walk(cpuDebug->GetPC(), ra, sp, entry, stackTop);
if (frames.size() < 2) {
// TODO: Respond in some way?
return;
return req.Fail("Could not find function call to step out into");
}
u32 breakpointAddress = frames[1].pc;
uint32_t breakpointAddress = frames[1].pc;
PrepareResume();
// Could have advanced to the breakpoint already in PrepareResume().
cpuDebug = CPUFromRequest(req);
if (cpuDebug->GetPC() != breakpointAddress) {
CBreakPoints::AddBreakPoint(breakpointAddress, true);
if (cpuDebug != currentDebugMIPS)
AddThreadCondition(breakpointAddress, threadID);
Core_EnableStepping(false);
}
}
@ -232,7 +241,7 @@ void WebSocketSteppingState::RunUntil(DebuggerRequest &req) {
return req.Fail("CPU not started");
}
u32 address = 0;
uint32_t address = 0;
if (!req.ParamU32("address", &address)) {
// Error already sent.
return;
@ -262,8 +271,8 @@ void WebSocketSteppingState::HLE(DebuggerRequest &req) {
Core_EnableStepping(false);
}
u32 WebSocketSteppingState::GetNextAddress(DebugInterface *cpuDebug) {
u32 current = disasm_.getStartAddress(cpuDebug->GetPC());
uint32_t WebSocketSteppingState::GetNextAddress(DebugInterface *cpuDebug) {
uint32_t current = disasm_.getStartAddress(cpuDebug->GetPC());
return disasm_.getNthNextAddress(current, 1);
}
@ -280,3 +289,10 @@ void WebSocketSteppingState::PrepareResume() {
}
}
void WebSocketSteppingState::AddThreadCondition(uint32_t breakpointAddress, uint32_t threadID) {
BreakPointCond cond;
cond.debug = currentDebugMIPS;
cond.expressionString = StringFromFormat("threadid == 0x%08x", threadID);
if (currentDebugMIPS->initExpression(cond.expressionString.c_str(), cond.expression))
CBreakPoints::ChangeBreakPointAddCond(breakpointAddress, cond);
}

View File

@ -23,6 +23,7 @@
#include "Core/Debugger/DebugInterface.h"
#include "Core/MIPS/MIPSDebugInterface.h"
#include "Core/HLE/sceKernelThread.h"
#include "Core/MemMap.h"
#include "Core/MIPS/MIPSTables.h"
#include "Core/MIPS/MIPS.h"
@ -37,13 +38,16 @@ enum ReferenceIndexType {
REF_INDEX_VFPU = 0x4000,
REF_INDEX_VFPU_INT = 0x8000,
REF_INDEX_IS_FLOAT = REF_INDEX_FPU | REF_INDEX_VFPU,
REF_INDEX_HLE = 0x10000,
REF_INDEX_THREAD = REF_INDEX_HLE | 0,
REF_INDEX_MODULE = REF_INDEX_HLE | 1,
};
class MipsExpressionFunctions: public IExpressionFunctions
{
public:
MipsExpressionFunctions(DebugInterface* cpu): cpu(cpu) { };
MipsExpressionFunctions(DebugInterface* cpu): cpu(cpu) { }
bool parseReference(char* str, uint32_t& referenceIndex) override
{
@ -106,6 +110,15 @@ public:
return true;
}
if (strcasecmp(str, "threadid") == 0) {
referenceIndex = REF_INDEX_THREAD;
return true;
}
if (strcasecmp(str, "moduleid") == 0) {
referenceIndex = REF_INDEX_MODULE;
return true;
}
return false;
}
@ -124,6 +137,10 @@ public:
return cpu->GetHi();
if (referenceIndex == REF_INDEX_LO)
return cpu->GetLo();
if (referenceIndex == REF_INDEX_THREAD)
return __KernelGetCurThread();
if (referenceIndex == REF_INDEX_MODULE)
return __KernelGetCurThreadModuleId();
if ((referenceIndex & ~(REF_INDEX_FPU | REF_INDEX_FPU_INT)) < 32)
return cpu->GetRegValue(1, referenceIndex & ~(REF_INDEX_FPU | REF_INDEX_FPU_INT));
if ((referenceIndex & ~(REF_INDEX_VFPU | REF_INDEX_VFPU_INT)) < 128)