diff --git a/Core/Debugger/Breakpoints.cpp b/Core/Debugger/Breakpoints.cpp index d1b293c57..dd6184d2c 100644 --- a/Core/Debugger/Breakpoints.cpp +++ b/Core/Debugger/Breakpoints.cpp @@ -297,7 +297,7 @@ void CBreakPoints::ClearTemporaryBreakPoints() void CBreakPoints::ChangeBreakPointAddCond(u32 addr, const BreakPointCond &cond) { std::unique_lock 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 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 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; diff --git a/Core/Debugger/Breakpoints.h b/Core/Debugger/Breakpoints.h index 45f91d3cc..bd3dd670e 100644 --- a/Core/Debugger/Breakpoints.h +++ b/Core/Debugger/Breakpoints.h @@ -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); diff --git a/Core/Debugger/WebSocket/SteppingSubscriber.cpp b/Core/Debugger/WebSocket/SteppingSubscriber.cpp index 594726e2e..e1347f3a1 100644 --- a/Core/Debugger/WebSocket/SteppingSubscriber.cpp +++ b/Core/Debugger/WebSocket/SteppingSubscriber.cpp @@ -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(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); +} diff --git a/Core/MIPS/MIPSDebugInterface.cpp b/Core/MIPS/MIPSDebugInterface.cpp index 943e56493..ae1a9a7a6 100644 --- a/Core/MIPS/MIPSDebugInterface.cpp +++ b/Core/MIPS/MIPSDebugInterface.cpp @@ -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)