pureikyubu/SRC/HighLevel/DumpThreads.cpp
2020-08-09 12:46:30 +03:00

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;
}
}