mirror of
https://github.com/emu-russia/pureikyubu.git
synced 2025-04-02 10:42:15 -04:00
277 lines
7 KiB
C++
277 lines
7 KiB
C++
// Dump DolphinOS threads.
|
|
|
|
// Details on the DolphinOS threads can be found in \Docs\RE\thread.txt. Fairly simple and clean design.
|
|
// We catch on to the list of active threads (__OSLinkActive) and display them in turn. You can use the DumpContext command to display context.
|
|
|
|
#include "pch.h"
|
|
|
|
using namespace Debug;
|
|
|
|
namespace HLE
|
|
{
|
|
|
|
static bool LoadOsThread(uint32_t ea, OSThread* thread)
|
|
{
|
|
int WIMG;
|
|
|
|
// Translate effective address
|
|
|
|
uint32_t threadPa = Gekko::Gekko->EffectiveToPhysical(ea, Gekko::MmuAccess::Read, WIMG);
|
|
if (threadPa == Gekko::BadAddress)
|
|
{
|
|
Report(Channel::Norm, "Invalid thread effective address: 0x%08X\n", ea);
|
|
return false;
|
|
}
|
|
|
|
uint8_t* ptr = MITranslatePhysicalAddress(threadPa, sizeof(OSThread));
|
|
|
|
if (ptr == nullptr)
|
|
{
|
|
Report(Channel::Norm, "Invalid thread physical address: 0x%08X\n", threadPa);
|
|
return false;
|
|
}
|
|
|
|
// Load thread struct and swap values
|
|
|
|
*thread = *(OSThread*)ptr;
|
|
|
|
thread->state = _BYTESWAP_UINT16(thread->state);
|
|
thread->attr = _BYTESWAP_UINT16(thread->attr);
|
|
thread->suspend = _BYTESWAP_UINT32(thread->suspend);
|
|
thread->priority = _BYTESWAP_UINT32(thread->priority);
|
|
thread->base = _BYTESWAP_UINT32(thread->base);
|
|
thread->val = _BYTESWAP_UINT32(thread->val);
|
|
|
|
thread->linkActive.next = _BYTESWAP_UINT32(thread->linkActive.next);
|
|
thread->linkActive.prev = _BYTESWAP_UINT32(thread->linkActive.prev);
|
|
|
|
thread->stackBase = _BYTESWAP_UINT32(thread->stackBase);
|
|
thread->stackEnd = _BYTESWAP_UINT32(thread->stackEnd);
|
|
|
|
// No need for other properties
|
|
|
|
return true;
|
|
}
|
|
|
|
static void DumpOsThread(size_t count, OSThread* thread, uint32_t threadEa)
|
|
{
|
|
Report(Channel::Norm, "Thread %zi, context: 0x%08X:\n", count, threadEa);
|
|
Report(Channel::Norm, "state: 0x%04X, attr: 0x%04X\n", thread->state, thread->attr);
|
|
Report(Channel::Norm, "suspend: %i, priority: 0x%08X, base: 0x%08X, val: 0x%08X\n", (int)thread->suspend, thread->priority, thread->base, thread->val);
|
|
}
|
|
|
|
Json::Value* DumpDolphinOsThreads(bool displayOnScreen)
|
|
{
|
|
int WIMG;
|
|
|
|
// Get pointer to __OSLinkActive
|
|
|
|
uint32_t linkActiveEffectiveAddr = OS_LINK_ACTIVE;
|
|
|
|
uint32_t linkActivePa = Gekko::Gekko->EffectiveToPhysical(linkActiveEffectiveAddr, Gekko::MmuAccess::Read, WIMG);
|
|
if (linkActivePa == Gekko::BadAddress)
|
|
{
|
|
if (displayOnScreen)
|
|
{
|
|
Report(Channel::Norm, "Invalid active threads link effective address: 0x%08X\n", linkActiveEffectiveAddr);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
uint8_t* ptr = MITranslatePhysicalAddress(linkActivePa, sizeof(OSThreadLink));
|
|
|
|
if (ptr == nullptr)
|
|
{
|
|
if (displayOnScreen)
|
|
{
|
|
Report(Channel::Norm, "Invalid active threads link physical address: 0x%08X\n", linkActivePa);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
OSThreadLink linkActive = *(OSThreadLink*)ptr;
|
|
|
|
linkActive.next = _BYTESWAP_UINT32(linkActive.next);
|
|
linkActive.prev = _BYTESWAP_UINT32(linkActive.prev);
|
|
|
|
// Walk active threads
|
|
|
|
Json::Value* output = new Json::Value();
|
|
output->type = Json::ValueType::Array;
|
|
|
|
if (displayOnScreen)
|
|
{
|
|
Report(Channel::Norm, "Dumping active DolphinOS threads:\n\n");
|
|
}
|
|
|
|
size_t activeThreadsCount = 0;
|
|
uint32_t threadEa = linkActive.next;
|
|
|
|
while (threadEa != 0)
|
|
{
|
|
OSThread thread = { 0 };
|
|
|
|
if (!LoadOsThread(threadEa, &thread))
|
|
break;
|
|
|
|
if (displayOnScreen)
|
|
{
|
|
DumpOsThread(activeThreadsCount, &thread, threadEa);
|
|
}
|
|
|
|
threadEa = thread.linkActive.next;
|
|
activeThreadsCount++;
|
|
|
|
output->AddUInt32(nullptr, threadEa);
|
|
|
|
if (displayOnScreen)
|
|
{
|
|
Report(Channel::Norm, "\n");
|
|
}
|
|
}
|
|
|
|
if (displayOnScreen)
|
|
{
|
|
Report(Channel::Norm, "Active threads: %zi. Use DumpContext command to dump thread context.\n", activeThreadsCount);
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
Json::Value* DumpDolphinOsContext(uint32_t effectiveAddr, bool displayOnScreen)
|
|
{
|
|
int WIMG;
|
|
|
|
// Get context pointer
|
|
|
|
uint32_t physAddr = Gekko::Gekko->EffectiveToPhysical(effectiveAddr, Gekko::MmuAccess::Read, WIMG);
|
|
|
|
if (physAddr == Gekko::BadAddress)
|
|
{
|
|
if (displayOnScreen)
|
|
{
|
|
Report(Channel::Norm, "Invalid context effective address: 0x%08X\n", effectiveAddr);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
uint8_t* ptr = MITranslatePhysicalAddress(physAddr, sizeof(OSContext));
|
|
|
|
if (ptr == nullptr)
|
|
{
|
|
if (displayOnScreen)
|
|
{
|
|
Report(Channel::Norm, "Invalid context physical address: 0x%08X\n", physAddr);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Copyout context and swap values
|
|
|
|
OSContext context = *(OSContext*)ptr;
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
context.gpr[i] = _BYTESWAP_UINT32(context.gpr[i]);
|
|
context.fprAsUint[i] = _BYTESWAP_UINT64(context.fprAsUint[i]);
|
|
context.psrAsUint[i] = _BYTESWAP_UINT64(context.psrAsUint[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
context.gqr[i] = _BYTESWAP_UINT32(context.gqr[i]);
|
|
}
|
|
|
|
context.cr = _BYTESWAP_UINT32(context.cr);
|
|
context.lr = _BYTESWAP_UINT32(context.lr);
|
|
context.ctr = _BYTESWAP_UINT32(context.ctr);
|
|
context.xer = _BYTESWAP_UINT32(context.xer);
|
|
|
|
context.fpscr = _BYTESWAP_UINT32(context.fpscr);
|
|
|
|
context.srr[0] = _BYTESWAP_UINT32(context.srr[0]);
|
|
context.srr[1] = _BYTESWAP_UINT32(context.srr[1]);
|
|
|
|
context.mode = _BYTESWAP_UINT16(context.mode);
|
|
context.state = _BYTESWAP_UINT16(context.state);
|
|
|
|
// Dump contents
|
|
|
|
if (displayOnScreen)
|
|
{
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
Report(Channel::Norm, "gpr[%i] = 0x%08X\n", i, context.gpr[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
Report(Channel::Norm, "fpr[%i] = %f (0x%llx)\n", i, context.fpr[i], context.fprAsUint[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
Report(Channel::Norm, "psr[%i] = %f (0x%llx)\n", i, context.psr[i], context.psrAsUint[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
Report(Channel::Norm, "gqr[%i] = 0x%08X\n", i, context.gqr[i]);
|
|
}
|
|
|
|
Report(Channel::Norm, "cr = 0x%08X\n", context.cr);
|
|
Report(Channel::Norm, "lr = 0x%08X\n", context.lr);
|
|
Report(Channel::Norm, "ctr = 0x%08X\n", context.ctr);
|
|
Report(Channel::Norm, "xer = 0x%08X\n", context.xer);
|
|
|
|
Report(Channel::Norm, "fpscr = 0x%08X\n", context.fpscr);
|
|
|
|
Report(Channel::Norm, "srr[0] = 0x%08X\n", context.srr[0]);
|
|
Report(Channel::Norm, "srr[1] = 0x%08X\n", context.srr[1]);
|
|
|
|
Report(Channel::Norm, "mode = 0x%02X\n", (uint8_t)context.mode);
|
|
Report(Channel::Norm, "state = 0x%02X\n", (uint8_t)context.state);
|
|
}
|
|
|
|
// Serialize
|
|
|
|
Json::Value* output = new Json::Value();
|
|
output->type = Json::ValueType::Array;
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
output->AddUInt32(nullptr, context.gpr[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
output->AddFloat(nullptr, (float)context.fpr[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
output->AddFloat(nullptr, (float)context.psr[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
output->AddUInt32(nullptr, context.gqr[i]);
|
|
}
|
|
|
|
output->AddUInt32(nullptr, context.cr);
|
|
output->AddUInt32(nullptr, context.lr);
|
|
output->AddUInt32(nullptr, context.ctr);
|
|
output->AddUInt32(nullptr, context.xer);
|
|
|
|
output->AddUInt32(nullptr, context.fpscr);
|
|
|
|
output->AddUInt32(nullptr, context.srr[0]);
|
|
output->AddUInt32(nullptr, context.srr[1]);
|
|
|
|
output->AddUInt16(nullptr, context.mode);
|
|
output->AddUInt16(nullptr, context.state);
|
|
|
|
return output;
|
|
}
|
|
|
|
}
|