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();