diff --git a/pcsx2-qt/Debugger/DebuggerWindow.cpp b/pcsx2-qt/Debugger/DebuggerWindow.cpp index 2cce7168d8039..a90ff3fdbc023 100644 --- a/pcsx2-qt/Debugger/DebuggerWindow.cpp +++ b/pcsx2-qt/Debugger/DebuggerWindow.cpp @@ -525,8 +525,7 @@ void DebuggerWindow::onStepOut() cpu->getPC(), cpu->getRegister(0, 31), cpu->getRegister(0, 29), - thread->EntryPoint(), - thread->StackTop()); + thread->EntryPoint()); break; } } diff --git a/pcsx2-qt/Debugger/StackModel.cpp b/pcsx2-qt/Debugger/StackModel.cpp index 203b0b98cdeeb..4ebcf60d9da32 100644 --- a/pcsx2-qt/Debugger/StackModel.cpp +++ b/pcsx2-qt/Debugger/StackModel.cpp @@ -111,8 +111,7 @@ void StackModel::refreshData() { if (thread->Status() == ThreadStatus::THS_RUN) { - m_stackFrames = MipsStackWalk::Walk(&m_cpu, m_cpu.getPC(), m_cpu.getRegister(0, 31), m_cpu.getRegister(0, 29), - thread->EntryPoint(), thread->StackTop()); + m_stackFrames = m_cpu.StackTrace(*thread); break; } } diff --git a/pcsx2-qt/Debugger/ThreadModel.h b/pcsx2-qt/Debugger/ThreadModel.h index c46b729aeee55..b65fb2e3283c3 100644 --- a/pcsx2-qt/Debugger/ThreadModel.h +++ b/pcsx2-qt/Debugger/ThreadModel.h @@ -71,8 +71,6 @@ class ThreadModel : public QAbstractTableModel //: Refers to a Thread Wait State in the Debugger. {WaitState::NONE, tr("NONE")}, //: Refers to a Thread Wait State in the Debugger. - {WaitState::WAKEUP_REQ, tr("WAKEUP REQUEST")}, - //: Refers to a Thread Wait State in the Debugger. {WaitState::SEMA, tr("SEMAPHORE")}, //: Refers to a Thread Wait State in the Debugger. {WaitState::SLEEP, tr("SLEEP")}, diff --git a/pcsx2/DebugTools/BiosDebugData.cpp b/pcsx2/DebugTools/BiosDebugData.cpp index a825f54d7c716..344b9e84ff086 100644 --- a/pcsx2/DebugTools/BiosDebugData.cpp +++ b/pcsx2/DebugTools/BiosDebugData.cpp @@ -49,7 +49,8 @@ std::vector> getIOPThreads() return {}; } - data.stackTop = iopMemRead32(item + 0x3c); + data.stacMem = iopMemRead32(item + 0x3c); + data.stackSize = iopMemRead32(item + 0x40); data.status = iopMemRead8(item + 0xc); data.tid = iopMemRead16(item + 0xa); data.entrypoint = iopMemRead32(item + 0x38); @@ -57,9 +58,9 @@ std::vector> getIOPThreads() data.waitId = iopMemRead32(item + 0x20); data.initPriority = iopMemRead16(item + 0xe); - data.SavedSP = iopMemRead32(item + 0x10); + data.regCtx = iopMemRead32(item + 0x10); - data.PC = iopMemRead32(data.SavedSP + 0x8c); + data.PC = iopMemRead32(data.regCtx + 0x8c); threads.emplace_back(std::make_unique(data)); diff --git a/pcsx2/DebugTools/BiosDebugData.h b/pcsx2/DebugTools/BiosDebugData.h index 92c0282f20811..36e89954c17a7 100644 --- a/pcsx2/DebugTools/BiosDebugData.h +++ b/pcsx2/DebugTools/BiosDebugData.h @@ -18,26 +18,37 @@ enum class ThreadStatus THS_DORMANT = 0x10, }; +struct EEInternalCtx +{ + u32 sa; + u32 fcsr; + u32 float_thing; + u32 unk; + // gpr excluding $zero + // k0/k1 contains hi, hi1, lo, lo1 + u128 gpr[31]; + float fpr[32]; +}; struct EEInternalThread { // internal struct u32 prev; u32 next; int status; - u32 entry; - u32 stack; + u32 resumeAddr; // address to return to when switching + u32 regCtx; // points to the saved regs on stack u32 gpReg; - short currentPriority; short initPriority; + short currentPriority; int waitType; int semaId; int wakeupCount; int attr; int option; - u32 entry_init; + u32 entry; int argc; u32 argstring; - u32 stack_bottom; //FIXME + u32 stackMem; int stackSize; u32 root; u32 heap_base; @@ -48,8 +59,9 @@ struct IOPInternalThread { u32 tid; u32 PC; - u32 stackTop; - u32 SavedSP; + u32 stacMem; + u32 stackSize; + u32 regCtx; u32 status; u32 entrypoint; u32 waitstate; @@ -71,14 +83,13 @@ enum class IOPWaitStatus enum class EEWaitStatus { WAIT_NONE = 0, - WAIT_WAKEUP_REQ = 1, + WAIT_SLEEP = 1, WAIT_SEMA = 2, }; enum class WaitState { NONE, - WAKEUP_REQ, SEMA, SLEEP, DELAY, @@ -98,8 +109,10 @@ class BiosThread [[nodiscard]] virtual WaitState Wait() const = 0; [[nodiscard]] virtual u32 WaitId() const = 0; [[nodiscard]] virtual u32 EntryPoint() const = 0; - [[nodiscard]] virtual u32 StackTop() const = 0; [[nodiscard]] virtual u32 Priority() const = 0; + + // Only call RegCtx on threads that aren't running + [[nodiscard]] virtual u32 RegCtx() const = 0; }; class EEThread : public BiosThread @@ -113,7 +126,7 @@ class EEThread : public BiosThread ~EEThread() override = default; [[nodiscard]] u32 TID() const override { return tid; }; - [[nodiscard]] u32 PC() const override { return data.entry; }; + [[nodiscard]] u32 PC() const override { return data.resumeAddr; }; [[nodiscard]] ThreadStatus Status() const override { return static_cast(data.status); }; [[nodiscard]] WaitState Wait() const override { @@ -122,17 +135,17 @@ class EEThread : public BiosThread { case EEWaitStatus::WAIT_NONE: return WaitState::NONE; - case EEWaitStatus::WAIT_WAKEUP_REQ: - return WaitState::WAKEUP_REQ; + case EEWaitStatus::WAIT_SLEEP: + return WaitState::SLEEP; case EEWaitStatus::WAIT_SEMA: return WaitState::SEMA; } return WaitState::NONE; }; [[nodiscard]] u32 WaitId() const override { return data.semaId; }; - [[nodiscard]] u32 EntryPoint() const override { return data.entry_init; }; - [[nodiscard]] u32 StackTop() const override { return data.stack; }; + [[nodiscard]] u32 EntryPoint() const override { return data.entry; }; [[nodiscard]] u32 Priority() const override { return data.currentPriority; }; + [[nodiscard]] u32 RegCtx() const override { return data.regCtx; }; private: u32 tid; @@ -175,8 +188,8 @@ class IOPThread : public BiosThread }; [[nodiscard]] u32 WaitId() const override { return data.waitId; }; [[nodiscard]] u32 EntryPoint() const override { return data.entrypoint; }; - [[nodiscard]] u32 StackTop() const override { return data.stackTop; }; [[nodiscard]] u32 Priority() const override { return data.initPriority; }; + [[nodiscard]] u32 RegCtx() const override { return data.regCtx; }; private: IOPInternalThread data; diff --git a/pcsx2/DebugTools/DebugInterface.cpp b/pcsx2/DebugTools/DebugInterface.cpp index c8715f7875bed..a64b9b348db84 100644 --- a/pcsx2/DebugTools/DebugInterface.cpp +++ b/pcsx2/DebugTools/DebugInterface.cpp @@ -708,6 +708,23 @@ std::vector> R5900DebugInterface::GetThreadList() co return getEEThreads(); } +std::vector R5900DebugInterface::StackTrace(const BiosThread& thread) +{ + if (thread.Status() == ThreadStatus::THS_RUN) + { + return MipsStackWalk::Walk(this, getPC(), getRegister(0, 31), getRegister(0, 29), + thread.EntryPoint()); + } + + EEInternalCtx* ctx = static_cast(PSM(thread.RegCtx())); + u32 pc = thread.PC(); + // $zero is not in the array so subtract 1 + u32 ra = ctx->gpr[31 - 1]._u32[0]; + u32 sp = ctx->gpr[29 - 1]._u32[0]; + + return MipsStackWalk::Walk(this, pc, ra, sp, thread.EntryPoint()); +} + std::vector R5900DebugInterface::GetModuleList() const { return {}; @@ -1049,6 +1066,22 @@ std::vector> R3000DebugInterface::GetThreadList() co return getIOPThreads(); } +std::vector R3000DebugInterface::StackTrace(const BiosThread& thread) +{ + if (thread.Status() == ThreadStatus::THS_RUN) + { + return MipsStackWalk::Walk(this, getPC(), getRegister(0, 31), getRegister(0, 29), + thread.EntryPoint()); + } + + u32 p = thread.RegCtx(); + u32 pc = Read32(p + 0x8c); + u32 ra = Read32(p + 0x7c); + u32 sp = Read32(p + 0x74); + + return MipsStackWalk::Walk(this, pc, ra, sp, thread.EntryPoint()); +} + std::vector R3000DebugInterface::GetModuleList() const { return getIOPModules(); diff --git a/pcsx2/DebugTools/DebugInterface.h b/pcsx2/DebugTools/DebugInterface.h index a5f9862265002..48b266ba56d39 100644 --- a/pcsx2/DebugTools/DebugInterface.h +++ b/pcsx2/DebugTools/DebugInterface.h @@ -7,6 +7,7 @@ #include "ExpressionParser.h" #include "SymbolGuardian.h" #include "SymbolImporter.h" +#include "MipsStackWalk.h" #include "common/MemoryInterface.h" @@ -72,6 +73,7 @@ class DebugInterface : public MemoryInterface virtual SymbolGuardian& GetSymbolGuardian() const = 0; virtual SymbolImporter* GetSymbolImporter() const = 0; virtual std::vector> GetThreadList() const = 0; + virtual std::vector StackTrace(const BiosThread& thread) = 0; virtual std::vector GetModuleList() const = 0; bool isAlive(); @@ -135,6 +137,7 @@ class R5900DebugInterface : public DebugInterface SymbolGuardian& GetSymbolGuardian() const override; SymbolImporter* GetSymbolImporter() const override; std::vector> GetThreadList() const override; + std::vector StackTrace(const BiosThread& thread) override; std::vector GetModuleList() const override; std::string disasm(u32 address, bool simplify) override; @@ -180,6 +183,7 @@ class R3000DebugInterface : public DebugInterface SymbolGuardian& GetSymbolGuardian() const override; SymbolImporter* GetSymbolImporter() const override; std::vector> GetThreadList() const override; + std::vector StackTrace(const BiosThread& thread) override; std::vector GetModuleList() const override; std::string disasm(u32 address, bool simplify) override; diff --git a/pcsx2/DebugTools/MipsStackWalk.cpp b/pcsx2/DebugTools/MipsStackWalk.cpp index cafcbfeacebd1..a77b79367fecb 100644 --- a/pcsx2/DebugTools/MipsStackWalk.cpp +++ b/pcsx2/DebugTools/MipsStackWalk.cpp @@ -183,7 +183,7 @@ namespace MipsStackWalk return ScanForEntry(cpu, frame, newPossibleEntry, ra); } - std::vector Walk(DebugInterface* cpu, u32 pc, u32 ra, u32 sp, u32 threadEntry, u32 threadStackTop) + std::vector Walk(DebugInterface* cpu, u32 pc, u32 ra, u32 sp, u32 threadEntry) { std::vector frames; StackFrame current; diff --git a/pcsx2/DebugTools/MipsStackWalk.h b/pcsx2/DebugTools/MipsStackWalk.h index 364b874a5b8d5..e4d6ddc425c2e 100644 --- a/pcsx2/DebugTools/MipsStackWalk.h +++ b/pcsx2/DebugTools/MipsStackWalk.h @@ -20,5 +20,5 @@ namespace MipsStackWalk { int stackSize; }; - std::vector Walk(DebugInterface* cpu, u32 pc, u32 ra, u32 sp, u32 threadEntry, u32 threadStackTop); + std::vector Walk(DebugInterface* cpu, u32 pc, u32 ra, u32 sp, u32 threadEntry); };