From 5670fc03ae00b817ff0f6a87bb683812df8f7917 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 9 May 2018 17:51:27 -0700 Subject: [PATCH] Debugger: Add debug interfaces for threads. This way we can switch context. --- Core/Core.vcxproj | 1 + Core/Core.vcxproj.filters | 3 + Core/Debugger/DisassemblyManager.cpp | 42 +++++---- Core/Debugger/DisassemblyManager.h | 14 +-- Core/Debugger/WebSocket/CPUCoreSubscriber.cpp | 85 +++++++++++++----- Core/Debugger/WebSocket/DisasmSubscriber.cpp | 35 ++++++-- Core/HLE/KernelThreadDebugInterface.h | 90 +++++++++++++++++++ Core/HLE/sceKernelThread.cpp | 30 +++++-- Core/HLE/sceKernelThread.h | 2 + 9 files changed, 239 insertions(+), 63 deletions(-) create mode 100644 Core/HLE/KernelThreadDebugInterface.h diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index a9d703869f..1b95d40373 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -553,6 +553,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index c5fe328767..f4803dd56c 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1337,6 +1337,9 @@ Debugger\WebSocket + + HLE\Kernel + diff --git a/Core/Debugger/DisassemblyManager.cpp b/Core/Debugger/DisassemblyManager.cpp index 54ffae28d4..2c0a6edd54 100644 --- a/Core/Debugger/DisassemblyManager.cpp +++ b/Core/Debugger/DisassemblyManager.cpp @@ -236,7 +236,7 @@ std::vector DisassemblyManager::getBranchLines(u32 start, u32 size) return result; } -void DisassemblyManager::getLine(u32 address, bool insertSymbols, DisassemblyLineInfo& dest) +void DisassemblyManager::getLine(u32 address, bool insertSymbols, DisassemblyLineInfo &dest, DebugInterface *cpuDebug) { // This is here really to avoid lock ordering issues. auto memLock = Memory::Lock(); @@ -250,7 +250,7 @@ void DisassemblyManager::getLine(u32 address, bool insertSymbols, DisassemblyLin if (it != entries.end()) { DisassemblyEntry *entry = it->second; - if (entry->disassemble(address, dest, insertSymbols)) + if (entry->disassemble(address, dest, insertSymbols, cpuDebug)) return; } @@ -432,14 +432,14 @@ u32 DisassemblyFunction::getLineAddress(int line) return lineAddresses[line]; } -bool DisassemblyFunction::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) +bool DisassemblyFunction::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug) { std::lock_guard guard(lock_); auto it = findDisassemblyEntry(entries,address,false); if (it == entries.end()) return false; - return it->second->disassemble(address,dest,insertSymbols); + return it->second->disassemble(address, dest, insertSymbols, cpuDebug); } void DisassemblyFunction::getBranchLines(u32 start, u32 size, std::vector& dest) @@ -720,16 +720,19 @@ void DisassemblyFunction::clear() hash = 0; } -bool DisassemblyOpcode::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) +bool DisassemblyOpcode::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug) { + if (!cpuDebug) + cpuDebug = DisassemblyManager::getCpu(); + char opcode[64],arguments[256]; - const char *dizz = DisassemblyManager::getCpu()->disasm(address,4); + const char *dizz = cpuDebug->disasm(address, 4); parseDisasm(dizz,opcode,arguments,insertSymbols); dest.type = DISTYPE_OPCODE; dest.name = opcode; dest.params = arguments; dest.totalSize = 4; - dest.info = MIPSAnalyst::GetOpcodeInfo(DisassemblyManager::getCpu(),address); + dest.info = MIPSAnalyst::GetOpcodeInfo(cpuDebug, address); return true; } @@ -789,11 +792,14 @@ void DisassemblyMacro::setMacroMemory(std::string _name, u32 _immediate, u8 _rt, numOpcodes = 2; } -bool DisassemblyMacro::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) +bool DisassemblyMacro::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug) { + if (!cpuDebug) + cpuDebug = DisassemblyManager::getCpu(); + char buffer[64]; dest.type = DISTYPE_MACRO; - dest.info = MIPSAnalyst::GetOpcodeInfo(DisassemblyManager::getCpu(),address); + dest.info = MIPSAnalyst::GetOpcodeInfo(cpuDebug, address); std::string addressSymbol; switch (type) @@ -802,11 +808,10 @@ bool DisassemblyMacro::disassemble(u32 address, DisassemblyLineInfo& dest, bool dest.name = name; addressSymbol = g_symbolMap->GetLabelString(immediate); - if (!addressSymbol.empty() && insertSymbols) - { - sprintf(buffer,"%s,%s",DisassemblyManager::getCpu()->GetRegName(0,rt),addressSymbol.c_str()); + if (!addressSymbol.empty() && insertSymbols) { + sprintf(buffer, "%s,%s", cpuDebug->GetRegName(0, rt), addressSymbol.c_str()); } else { - sprintf(buffer,"%s,0x%08X",DisassemblyManager::getCpu()->GetRegName(0,rt),immediate); + sprintf(buffer, "%s,0x%08X", cpuDebug->GetRegName(0, rt), immediate); } dest.params = buffer; @@ -818,11 +823,10 @@ bool DisassemblyMacro::disassemble(u32 address, DisassemblyLineInfo& dest, bool dest.name = name; addressSymbol = g_symbolMap->GetLabelString(immediate); - if (!addressSymbol.empty() && insertSymbols) - { - sprintf(buffer,"%s,%s",DisassemblyManager::getCpu()->GetRegName(0,rt),addressSymbol.c_str()); + if (!addressSymbol.empty() && insertSymbols) { + sprintf(buffer, "%s,%s", cpuDebug->GetRegName(0, rt), addressSymbol.c_str()); } else { - sprintf(buffer,"%s,0x%08X",DisassemblyManager::getCpu()->GetRegName(0,rt),immediate); + sprintf(buffer, "%s,0x%08X", cpuDebug->GetRegName(0, rt), immediate); } dest.params = buffer; @@ -867,7 +871,7 @@ void DisassemblyData::recheck() } } -bool DisassemblyData::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) +bool DisassemblyData::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug) { dest.type = DISTYPE_DATA; @@ -1065,7 +1069,7 @@ DisassemblyComment::DisassemblyComment(u32 _address, u32 _size, std::string _nam } -bool DisassemblyComment::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) +bool DisassemblyComment::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug) { dest.type = DISTYPE_OTHER; dest.name = name; diff --git a/Core/Debugger/DisassemblyManager.h b/Core/Debugger/DisassemblyManager.h index 7d84805b01..44ae397f6c 100644 --- a/Core/Debugger/DisassemblyManager.h +++ b/Core/Debugger/DisassemblyManager.h @@ -63,7 +63,7 @@ public: virtual int getLineNum(u32 address, bool findStart) = 0; virtual u32 getLineAddress(int line) = 0; virtual u32 getTotalSize() = 0; - virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) = 0; + virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols, DebugInterface *cpuDebug) = 0; virtual void getBranchLines(u32 start, u32 size, std::vector& dest) { }; }; @@ -77,7 +77,7 @@ public: int getLineNum(u32 address, bool findStart) override; u32 getLineAddress(int line) override; u32 getTotalSize() override { return size; }; - bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) override; + bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols, DebugInterface *cpuDebug) override; void getBranchLines(u32 start, u32 size, std::vector& dest) override; private: @@ -105,7 +105,7 @@ public: int getLineNum(u32 address, bool findStart) override { return (address - this->address) / 4; }; u32 getLineAddress(int line) override { return address + line * 4; }; u32 getTotalSize() override { return num * 4; }; - bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) override; + bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols, DebugInterface *cpuDebug) override; void getBranchLines(u32 start, u32 size, std::vector& dest) override; private: @@ -128,7 +128,7 @@ public: int getLineNum(u32 address, bool findStart) override { return 0; }; u32 getLineAddress(int line) override { return address; }; u32 getTotalSize() override { return numOpcodes * 4; }; - bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) override; + bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols, DebugInterface *cpuDebug) override; private: enum MacroType { MACRO_LI, MACRO_MEMORYIMM }; @@ -153,7 +153,7 @@ public: int getLineNum(u32 address, bool findStart) override; u32 getLineAddress(int line) override { return lineAddresses[line]; }; u32 getTotalSize() override { return size; }; - bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) override; + bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols, DebugInterface *cpuDebug) override; private: void createLines(); @@ -185,7 +185,7 @@ public: int getLineNum(u32 address, bool findStart) override { return 0; }; u32 getLineAddress(int line) override { return address; }; u32 getTotalSize() override { return size; }; - bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) override; + bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols, DebugInterface *cpuDebug) override; private: u32 address; @@ -205,7 +205,7 @@ public: void setCpu(DebugInterface* _cpu) { cpu = _cpu; }; void setMaxParamChars(int num) { maxParamChars = num; clear(); }; - void getLine(u32 address, bool insertSymbols, DisassemblyLineInfo& dest); + void getLine(u32 address, bool insertSymbols, DisassemblyLineInfo &dest, DebugInterface *cpuDebug = nullptr); void analyze(u32 address, u32 size); std::vector getBranchLines(u32 start, u32 size); diff --git a/Core/Debugger/WebSocket/CPUCoreSubscriber.cpp b/Core/Debugger/WebSocket/CPUCoreSubscriber.cpp index 7b1ffb68ac..0d2c42f66c 100644 --- a/Core/Debugger/WebSocket/CPUCoreSubscriber.cpp +++ b/Core/Debugger/WebSocket/CPUCoreSubscriber.cpp @@ -21,6 +21,7 @@ #include "Core/Debugger/Breakpoints.h" #include "Core/Debugger/WebSocket/CPUCoreSubscriber.h" #include "Core/Debugger/WebSocket/WebSocketUtils.h" +#include "Core/HLE/sceKernelThread.h" #include "Core/MIPS/MIPS.h" #include "Core/MIPS/MIPSDebugInterface.h" @@ -45,6 +46,20 @@ static std::string RegValueAsFloat(uint32_t u) { return StringFromFormat("%f", bits.f); } +static DebugInterface *CPUFromRequest(DebuggerRequest &req) { + if (!req.HasParam("thread")) + return currentDebugMIPS; + + u32 uid; + if (!req.ParamU32("thread", &uid)) + return nullptr; + + DebugInterface *cpuDebug = KernelDebugThread((SceUID)uid); + if (!cpuDebug) + req.Fail("Thread could not be found"); + return cpuDebug; +} + // Begin stepping and pause the CPU (cpu.stepping) // // No parameters. @@ -100,7 +115,8 @@ void WebSocketCPUStatus(DebuggerRequest &req) { // Retrieve all regs and their values (cpu.getAllRegs) // -// No parameters. +// Parameters: +// - thread: optional number indicating the thread id to get regs for. // // Response (same event name): // - categories: array of objects: @@ -110,19 +126,23 @@ void WebSocketCPUStatus(DebuggerRequest &req) { // - uintValues: array of unsigned integer values for the registers. // - floatValues: array of strings showing float representation. May be "nan", "inf", or "-inf". void WebSocketCPUGetAllRegs(DebuggerRequest &req) { + auto cpuDebug = CPUFromRequest(req); + if (!cpuDebug) + return; + JsonWriter &json = req.Respond(); json.pushArray("categories"); - for (int c = 0; c < currentDebugMIPS->GetNumCategories(); ++c) { + for (int c = 0; c < cpuDebug->GetNumCategories(); ++c) { json.pushDict(); json.writeInt("id", c); - json.writeString("name", currentDebugMIPS->GetCategoryName(c)); + json.writeString("name", cpuDebug->GetCategoryName(c)); - int total = currentDebugMIPS->GetNumRegsInCategory(c); + int total = cpuDebug->GetNumRegsInCategory(c); json.pushArray("registerNames"); for (int r = 0; r < total; ++r) - json.writeString(currentDebugMIPS->GetRegName(c, r)); + json.writeString(cpuDebug->GetRegName(c, r)); if (c == 0) { json.writeString("pc"); json.writeString("hi"); @@ -133,22 +153,22 @@ void WebSocketCPUGetAllRegs(DebuggerRequest &req) { json.pushArray("uintValues"); // Writing as floating point to avoid negatives. Actually double, so safe. for (int r = 0; r < total; ++r) - json.writeUint(currentDebugMIPS->GetRegValue(c, r)); + json.writeUint(cpuDebug->GetRegValue(c, r)); if (c == 0) { - json.writeUint(currentDebugMIPS->GetPC()); - json.writeUint(currentDebugMIPS->GetHi()); - json.writeUint(currentDebugMIPS->GetLo()); + json.writeUint(cpuDebug->GetPC()); + json.writeUint(cpuDebug->GetHi()); + json.writeUint(cpuDebug->GetLo()); } json.pop(); json.pushArray("floatValues"); // Note: String so it can have Infinity and NaN. for (int r = 0; r < total; ++r) - json.writeString(RegValueAsFloat(currentDebugMIPS->GetRegValue(c, r))); + json.writeString(RegValueAsFloat(cpuDebug->GetRegValue(c, r))); if (c == 0) { - json.writeString(RegValueAsFloat(currentDebugMIPS->GetPC())); - json.writeString(RegValueAsFloat(currentDebugMIPS->GetHi())); - json.writeString(RegValueAsFloat(currentDebugMIPS->GetLo())); + json.writeString(RegValueAsFloat(cpuDebug->GetPC())); + json.writeString(RegValueAsFloat(cpuDebug->GetHi())); + json.writeString(RegValueAsFloat(cpuDebug->GetLo())); } json.pop(); @@ -232,9 +252,11 @@ static DebuggerRegType ValidateCatReg(DebuggerRequest &req, int *cat, int *reg) // Retrieve the value of a single register (cpu.getReg) // // Parameters (by name): +// - thread: optional number indicating the thread id to get from. // - name: string name of register to lookup. // // Parameters (by category id and index, ignored if name specified): +// - thread: optional number indicating the thread id to get from. // - category: id of category for the register. // - register: index into array of registers. // @@ -244,21 +266,25 @@ static DebuggerRegType ValidateCatReg(DebuggerRequest &req, int *cat, int *reg) // - uintValue: value in register. // - floatValue: string showing float representation. May be "nan", "inf", or "-inf". void WebSocketCPUGetReg(DebuggerRequest &req) { + auto cpuDebug = CPUFromRequest(req); + if (!cpuDebug) + return; + int cat, reg; uint32_t val; switch (ValidateCatReg(req, &cat, ®)) { case DebuggerRegType::NORMAL: - val = currentDebugMIPS->GetRegValue(cat, reg); + val = cpuDebug->GetRegValue(cat, reg); break; case DebuggerRegType::PC: - val = currentDebugMIPS->GetPC(); + val = cpuDebug->GetPC(); break; case DebuggerRegType::HI: - val = currentDebugMIPS->GetHi(); + val = cpuDebug->GetHi(); break; case DebuggerRegType::LO: - val = currentDebugMIPS->GetLo(); + val = cpuDebug->GetLo(); break; case DebuggerRegType::INVALID: @@ -276,11 +302,13 @@ void WebSocketCPUGetReg(DebuggerRequest &req) { // Update the value of a single register (cpu.setReg) // // Parameters (by name): +// - thread: optional number indicating the thread id to update. // - name: string name of register to lookup. // - value: number (uint values only) or string to set to. Values may include // "0x1234", "1.5", "nan", "-inf", etc. For a float, use a string with decimal e.g. "1.0". // // Parameters (by category id and index, ignored if name specified): +// - thread: optional number indicating the thread id to update. // - category: id of category for the register. // - register: index into array of registers. // - value: number (uint values only) or string to set to. Values may include @@ -301,6 +329,10 @@ void WebSocketCPUSetReg(DebuggerRequest &req) { return req.Fail("CPU currently running (cpu.stepping first)"); } + auto cpuDebug = CPUFromRequest(req); + if (!cpuDebug) + return; + uint32_t val; if (!req.ParamU32("value", &val, true)) { // Already sent error. @@ -313,19 +345,19 @@ void WebSocketCPUSetReg(DebuggerRequest &req) { if (cat == 0 && reg == 0 && val != 0) { return req.Fail("Cannot change reg zero"); } - currentDebugMIPS->SetRegValue(cat, reg, val); + cpuDebug->SetRegValue(cat, reg, val); // In case part of it was ignored (e.g. flags reg.) - val = currentDebugMIPS->GetRegValue(cat, reg); + val = cpuDebug->GetRegValue(cat, reg); break; case DebuggerRegType::PC: - currentDebugMIPS->SetPC(val); + cpuDebug->SetPC(val); break; case DebuggerRegType::HI: - currentDebugMIPS->SetHi(val); + cpuDebug->SetHi(val); break; case DebuggerRegType::LO: - currentDebugMIPS->SetLo(val); + cpuDebug->SetLo(val); break; case DebuggerRegType::INVALID: @@ -344,6 +376,7 @@ void WebSocketCPUSetReg(DebuggerRequest &req) { // Evaluate an expression (cpu.evaluate) // // Parameters: +// - thread: optional number indicating the thread id to update. // - expression: string containing labels, operators, regs, etc. // // Response (same event name): @@ -354,6 +387,10 @@ void WebSocketCPUEvaluate(DebuggerRequest &req) { return req.Fail("CPU not started"); } + auto cpuDebug = CPUFromRequest(req); + if (!cpuDebug) + return; + std::string exp; if (!req.ParamString("expression", &exp)) { // Already sent error. @@ -362,10 +399,10 @@ void WebSocketCPUEvaluate(DebuggerRequest &req) { u32 val; PostfixExpression postfix; - if (!currentDebugMIPS->initExpression(exp.c_str(), postfix)) { + if (!cpuDebug->initExpression(exp.c_str(), postfix)) { return req.Fail(StringFromFormat("Could not parse expression syntax: %s", getExpressionError())); } - if (!currentDebugMIPS->parseExpression(postfix, val)) { + if (!cpuDebug->parseExpression(postfix, val)) { return req.Fail(StringFromFormat("Could not evaluate expression: %s", getExpressionError())); } diff --git a/Core/Debugger/WebSocket/DisasmSubscriber.cpp b/Core/Debugger/WebSocket/DisasmSubscriber.cpp index 95dddcebb8..9971505a84 100644 --- a/Core/Debugger/WebSocket/DisasmSubscriber.cpp +++ b/Core/Debugger/WebSocket/DisasmSubscriber.cpp @@ -23,6 +23,7 @@ #include "Core/Debugger/DisassemblyManager.h" #include "Core/Debugger/WebSocket/DisasmSubscriber.h" #include "Core/Debugger/WebSocket/WebSocketUtils.h" +#include "Core/HLE/sceKernelThread.h" #include "Core/MemMap.h" #include "Core/MIPS/MIPSAsm.h" #include "Core/MIPS/MIPSDebugInterface.h" @@ -62,6 +63,20 @@ void WebSocketDisasmShutdown(void *p) { delete static_cast(p); } +static DebugInterface *CPUFromRequest(DebuggerRequest &req) { + if (!req.HasParam("thread")) + return currentDebugMIPS; + + u32 uid; + if (!req.ParamU32("thread", &uid)) + return nullptr; + + DebugInterface *cpuDebug = KernelDebugThread((SceUID)uid); + if (!cpuDebug) + req.Fail("Thread could not be found"); + return cpuDebug; +} + void WebSocketDisasmState::WriteDisasmLine(JsonWriter &json, const DisassemblyLineInfo &l) { u32 addr = l.info.opcodeAddress; json.pushDict(); @@ -112,6 +127,7 @@ void WebSocketDisasmState::WriteDisasmLine(JsonWriter &json, const DisassemblyLi json.writeNull("breakpoint"); } + // This is always the current execution's PC. json.writeBool("isCurrentPC", currentDebugMIPS->GetPC() == addr); if (l.info.isBranch) { json.pushDict("branch"); @@ -229,11 +245,13 @@ void WebSocketDisasmState::Base(DebuggerRequest &req) { // Disassemble a range of memory as CPU instructions (memory.disasm) // // Parameters (by count): +// - thread: optional number indicating the thread id for branch info. // - address: number specifying the start address. // - count: number of lines to return (may be clamped to an internal limit.) // - displaySymbols: boolean true to show symbol names in instruction params. // // Parameters (by end address): +// - thread: optional number indicating the thread id for branch info. // - address: number specifying the start address. // - end: number which must be after the start address (may be clamped to an internal limit.) // - displaySymbols: boolean true to show symbol names in instruction params. @@ -256,9 +274,11 @@ void WebSocketDisasmState::Base(DebuggerRequest &req) { // - params: formatted parameters for the instruction. // - (other info about the disassembled line.) void WebSocketDisasmState::Disasm(DebuggerRequest &req) { - if (!currentDebugMIPS->isAlive() || !Memory::IsActive()) { + if (!currentDebugMIPS->isAlive() || !Memory::IsActive()) return req.Fail("CPU not started"); - } + auto cpuDebug = CPUFromRequest(req); + if (!cpuDebug) + return; // In case of client errors, we limit the range to something that won't make us crash. static const uint32_t MAX_RANGE = 10000; @@ -310,7 +330,7 @@ void WebSocketDisasmState::Disasm(DebuggerRequest &req) { DisassemblyLineInfo line; uint32_t addr = start; for (uint32_t i = 0; i < count; ++i) { - disasm_.getLine(addr, displaySymbols, line); + disasm_.getLine(addr, displaySymbols, line, cpuDebug); WriteDisasmLine(json, line); addr += line.totalSize; @@ -330,6 +350,7 @@ void WebSocketDisasmState::Disasm(DebuggerRequest &req) { // Search disassembly for some text (cpu.searchDisasm) // // Parameters: +// - thread: optional number indicating the thread id (may not affect search much.) // - address: starting address as a number. // - end: optional end address as a number (otherwise uses start.) // - match: string to search for. @@ -338,9 +359,11 @@ void WebSocketDisasmState::Disasm(DebuggerRequest &req) { // Response (same event name): // - address: number address of match or null if none was found. void WebSocketDisasmState::SearchDisasm(DebuggerRequest &req) { - if (!currentDebugMIPS->isAlive() || !Memory::IsActive()) { + if (!currentDebugMIPS->isAlive() || !Memory::IsActive()) return req.Fail("CPU not started"); - } + auto cpuDebug = CPUFromRequest(req); + if (!cpuDebug) + return; uint32_t start; if (!req.ParamU32("address", &start)) @@ -373,7 +396,7 @@ void WebSocketDisasmState::SearchDisasm(DebuggerRequest &req) { bool found = false; uint32_t addr = start; do { - disasm_.getLine(addr, displaySymbols, line); + disasm_.getLine(addr, displaySymbols, line, cpuDebug); const std::string addressSymbol = g_symbolMap->GetLabelString(addr); std::string mergeForSearch; diff --git a/Core/HLE/KernelThreadDebugInterface.h b/Core/HLE/KernelThreadDebugInterface.h new file mode 100644 index 0000000000..012a93fc37 --- /dev/null +++ b/Core/HLE/KernelThreadDebugInterface.h @@ -0,0 +1,90 @@ +// 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 +#include "Core/HLE/sceKernelThread.h" +#include "Core/MIPS/MIPSDebugInterface.h" + +class KernelThreadDebugInterface : public MIPSDebugInterface { +public: + KernelThreadDebugInterface(MIPSState *c, ThreadContext &t) : MIPSDebugInterface(c), ctx(t) { + } + + unsigned int getPC() override { return ctx.pc; } + void setPC(unsigned int address) override { ctx.pc = address; } + + u32 GetGPR32Value(int reg) override { return ctx.r[reg]; } + u32 GetPC() override { return ctx.pc; } + u32 GetLR() override { return ctx.r[MIPS_REG_RA]; } + void SetPC(u32 _pc) override { ctx.pc = _pc; } + + void PrintRegValue(int cat, int index, char *out) override { + switch (cat) { + case 0: sprintf(out, "%08X", ctx.r[index]); break; + case 1: sprintf(out, "%f", ctx.f[index]); break; + case 2: sprintf(out, "N/A"); break; + } + } + + u32 GetHi() override { + return ctx.hi; + } + + u32 GetLo() override { + return ctx.lo; + } + + void SetHi(u32 val) override { + ctx.hi = val; + } + + void SetLo(u32 val) override { + ctx.lo = val; + } + + u32 GetRegValue(int cat, int index) override { + switch (cat) { + case 0: return ctx.r[index]; + case 1: return ctx.fi[index]; + case 2: return ctx.vi[voffset[index]]; + default: return 0; + } + } + + void SetRegValue(int cat, int index, u32 value) override { + switch (cat) { + case 0: + if (index != 0) + ctx.r[index] = value; + break; + + case 1: + ctx.fi[index] = value; + break; + + case 2: + ctx.vi[voffset[index]] = value; + break; + + default: + break; + } + } + +protected: + ThreadContext &ctx; +}; diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index fccf608db1..11d246576e 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -29,6 +29,7 @@ #include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" #include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSDebugInterface.h" #include "Core/CoreTiming.h" #include "Core/MemMapHelpers.h" #include "Core/MIPS/JitCommon/JitCommon.h" @@ -41,6 +42,7 @@ #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceKernelModule.h" #include "Core/HLE/sceKernelInterrupt.h" +#include "Core/HLE/KernelThreadDebugInterface.h" #include "Core/HLE/KernelWaitHelpers.h" #include "Core/HLE/ThreadQueueList.h" @@ -493,7 +495,7 @@ public: return true; } - Thread() + Thread() : debug(currentMIPS, context) { currentStack.start = 0; } @@ -586,6 +588,7 @@ public: SceUID currentCallbackId; ThreadContext context; + KernelThreadDebugInterface debug; std::vector callbacks; @@ -3510,14 +3513,13 @@ std::vector GetThreadsInfo() std::vector threadList; u32 error; - for (auto iter = threadqueue.begin(); iter != threadqueue.end(); ++iter) - { - Thread *t = kernelObjects.Get(*iter, error); + for (const auto uid : threadqueue) { + Thread *t = kernelObjects.Get(uid, error); if (!t) continue; DebugThreadInfo info; - info.id = *iter; + info.id = uid; strncpy(info.name,t->GetName(),KERNELOBJECT_MAX_NAME_LENGTH); info.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0; info.status = t->nt.status; @@ -3526,17 +3528,31 @@ std::vector GetThreadsInfo() info.stackSize = (u32)t->nt.stackSize; info.priority = t->nt.currentPriority; info.waitType = (WaitType)(u32)t->nt.waitType; - if(*iter == currentThread) + info.isCurrent = uid == currentThread; + if (info.isCurrent) info.curPC = currentMIPS->pc; else info.curPC = t->context.pc; - info.isCurrent = (*iter == currentThread); threadList.push_back(info); } return threadList; } +DebugInterface *KernelDebugThread(SceUID threadID) { + if (threadID == currentThread) { + return currentDebugMIPS; + } + + u32 error; + Thread *t = kernelObjects.Get(threadID, error); + if (t) { + return &t->debug; + } + + return nullptr; +} + void __KernelChangeThreadState(SceUID threadId, ThreadStatus newStatus) { u32 error; diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 53fa5e4367..6216fc02ec 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -27,6 +27,7 @@ // http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/ThreadManForUser.java class Thread; +class DebugInterface; int sceKernelChangeThreadPriority(SceUID threadID, int priority); SceUID __KernelCreateThreadInternal(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr); @@ -316,6 +317,7 @@ struct DebugThreadInfo }; std::vector GetThreadsInfo(); +DebugInterface *KernelDebugThread(SceUID threadID); void __KernelChangeThreadState(SceUID threadId, ThreadStatus newStatus); int LoadExecForUser_362A956B();