mirror of
https://github.com/kinnay/Wii-U-Firmware-Emulator.git
synced 2024-06-01 02:57:25 -04:00
591 lines
20 KiB
C++
591 lines
20 KiB
C++
|
|
#include "debugger/ppc.h"
|
|
#include "debugger/memorymap.h"
|
|
#include "debugger/common.h"
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
static uint32_t phys(uint32_t address) {
|
|
if (address >= 0xFFE00000) {
|
|
return address - 0xFFE00000 + 0x08000000;
|
|
}
|
|
return address;
|
|
}
|
|
|
|
|
|
bool PPCModule::compareText(Ref<PPCModule> a, Ref<PPCModule> b) {
|
|
return a->text < b->text;
|
|
}
|
|
|
|
|
|
PPCDebugger::PPCDebugger(PhysicalMemory *physmem, PPCProcessor *cpu, int index) {
|
|
this->physmem = physmem;
|
|
this->index = index;
|
|
this->cpu = cpu;
|
|
}
|
|
|
|
Processor *PPCDebugger::getProcessor() {
|
|
return cpu;
|
|
}
|
|
|
|
std::string PPCDebugger::name() {
|
|
return StringUtils::format("PPC%i", cpu->core.sprs[PPCCore::PIR]);
|
|
}
|
|
|
|
std::string PPCDebugger::format() {
|
|
return "%08X";
|
|
}
|
|
|
|
Ref<EvalContext> PPCDebugger::getContext() {
|
|
Ref<EvalContext> context = new EvalContext();
|
|
|
|
for (int i = 0; i < 32; i++) {
|
|
std::string reg = StringUtils::format("r%i", i);
|
|
context->add(reg, cpu->core.regs[i]);
|
|
}
|
|
|
|
context->add("pc", cpu->core.pc);
|
|
context->add("lr", cpu->core.sprs[PPCCore::LR]);
|
|
context->add("ctr", cpu->core.sprs[PPCCore::CTR]);
|
|
context->add("cr", cpu->core.cr);
|
|
|
|
context->add("srr0", cpu->core.sprs[PPCCore::SRR0]);
|
|
context->add("srr1", cpu->core.sprs[PPCCore::SRR1]);
|
|
|
|
return context;
|
|
}
|
|
|
|
uint32_t PPCDebugger::pc() {
|
|
return cpu->core.pc;
|
|
}
|
|
|
|
bool PPCDebugger::translate(uint32_t *address) {
|
|
return cpu->mmu.translate(address, MemoryAccess::DataRead, true);
|
|
}
|
|
|
|
void PPCDebugger::printState() {
|
|
Sys::out->write(
|
|
"r0 = %08X r1 = %08X r2 = %08X r3 = %08X r4 = %08X\n"
|
|
"r5 = %08X r6 = %08X r7 = %08X r8 = %08X r9 = %08X\n"
|
|
"r10 = %08X r11 = %08X r12 = %08X r13 = %08X r14 = %08X\n"
|
|
"r15 = %08X r16 = %08X r17 = %08X r18 = %08X r19 = %08X\n"
|
|
"r20 = %08X r21 = %08X r22 = %08X r23 = %08X r24 = %08X\n"
|
|
"r25 = %08X r26 = %08X r27 = %08X r28 = %08X r29 = %08X\n"
|
|
"r30 = %08X r31 = %08X pc = %08X lr = %08X ctr = %08X\n"
|
|
"cr = %08X\n",
|
|
cpu->core.regs[0], cpu->core.regs[1], cpu->core.regs[2],
|
|
cpu->core.regs[3], cpu->core.regs[4], cpu->core.regs[5],
|
|
cpu->core.regs[6], cpu->core.regs[7], cpu->core.regs[8],
|
|
cpu->core.regs[9], cpu->core.regs[10], cpu->core.regs[11],
|
|
cpu->core.regs[12], cpu->core.regs[13], cpu->core.regs[14],
|
|
cpu->core.regs[15], cpu->core.regs[16], cpu->core.regs[17],
|
|
cpu->core.regs[18], cpu->core.regs[19], cpu->core.regs[20],
|
|
cpu->core.regs[21], cpu->core.regs[22], cpu->core.regs[23],
|
|
cpu->core.regs[24], cpu->core.regs[25], cpu->core.regs[26],
|
|
cpu->core.regs[27], cpu->core.regs[28], cpu->core.regs[29],
|
|
cpu->core.regs[30], cpu->core.regs[31], cpu->core.pc,
|
|
cpu->core.sprs[PPCCore::LR], cpu->core.sprs[PPCCore::CTR],
|
|
cpu->core.cr
|
|
);
|
|
}
|
|
|
|
void PPCDebugger::printStateDetailed() {
|
|
Sys::out->write(
|
|
"r0 = %08X r1 = %08X r2 = %08X r3 = %08X r4 = %08X\n"
|
|
"r5 = %08X r6 = %08X r7 = %08X r8 = %08X r9 = %08X\n"
|
|
"r10 = %08X r11 = %08X r12 = %08X r13 = %08X r14 = %08X\n"
|
|
"r15 = %08X r16 = %08X r17 = %08X r18 = %08X r19 = %08X\n"
|
|
"r20 = %08X r21 = %08X r22 = %08X r23 = %08X r24 = %08X\n"
|
|
"r25 = %08X r26 = %08X r27 = %08X r28 = %08X r29 = %08X\n"
|
|
"r30 = %08X r31 = %08X pc = %08X lr = %08X ctr = %08X\n"
|
|
"cr = %08X xer = %08X\n",
|
|
cpu->core.regs[0], cpu->core.regs[1], cpu->core.regs[2],
|
|
cpu->core.regs[3], cpu->core.regs[4], cpu->core.regs[5],
|
|
cpu->core.regs[6], cpu->core.regs[7], cpu->core.regs[8],
|
|
cpu->core.regs[9], cpu->core.regs[10], cpu->core.regs[11],
|
|
cpu->core.regs[12], cpu->core.regs[13], cpu->core.regs[14],
|
|
cpu->core.regs[15], cpu->core.regs[16], cpu->core.regs[17],
|
|
cpu->core.regs[18], cpu->core.regs[19], cpu->core.regs[20],
|
|
cpu->core.regs[21], cpu->core.regs[22], cpu->core.regs[23],
|
|
cpu->core.regs[24], cpu->core.regs[25], cpu->core.regs[26],
|
|
cpu->core.regs[27], cpu->core.regs[28], cpu->core.regs[29],
|
|
cpu->core.regs[30], cpu->core.regs[31], cpu->core.pc,
|
|
cpu->core.sprs[PPCCore::LR], cpu->core.sprs[PPCCore::CTR],
|
|
cpu->core.cr, cpu->core.sprs[PPCCore::XER]
|
|
);
|
|
Sys::out->write("\n");
|
|
Sys::out->write(
|
|
"f0 = %08X:%08X f1 = %08X:%08X f2 = %08X:%08X\n"
|
|
"f3 = %08X:%08X f4 = %08X:%08X f5 = %08X:%08X\n"
|
|
"f6 = %08X:%08X f7 = %08X:%08X f8 = %08X:%08X\n"
|
|
"f9 = %08X:%08X f10 = %08X:%08X f11 = %08X:%08X\n"
|
|
"f12 = %08X:%08X f13 = %08X:%08X f14 = %08X:%08X\n"
|
|
"f15 = %08X:%08X f16 = %08X:%08X f17 = %08X:%08X\n"
|
|
"f18 = %08X:%08X f19 = %08X:%08X f20 = %08X:%08X\n"
|
|
"f21 = %08X:%08X f22 = %08X:%08X f23 = %08X:%08X\n"
|
|
"f24 = %08X:%08X f25 = %08X:%08X f26 = %08X:%08X\n"
|
|
"f27 = %08X:%08X f28 = %08X:%08X f29 = %08X:%08X\n"
|
|
"f30 = %08X:%08X f31 = %08X:%08X\n",
|
|
cpu->core.fprs[0].uw0, cpu->core.fprs[0].uw1,
|
|
cpu->core.fprs[1].uw0, cpu->core.fprs[1].uw1,
|
|
cpu->core.fprs[2].uw0, cpu->core.fprs[2].uw1,
|
|
cpu->core.fprs[3].uw0, cpu->core.fprs[3].uw1,
|
|
cpu->core.fprs[4].uw0, cpu->core.fprs[4].uw1,
|
|
cpu->core.fprs[5].uw0, cpu->core.fprs[5].uw1,
|
|
cpu->core.fprs[6].uw0, cpu->core.fprs[6].uw1,
|
|
cpu->core.fprs[7].uw0, cpu->core.fprs[7].uw1,
|
|
cpu->core.fprs[8].uw0, cpu->core.fprs[8].uw1,
|
|
cpu->core.fprs[9].uw0, cpu->core.fprs[9].uw1,
|
|
cpu->core.fprs[10].uw0, cpu->core.fprs[10].uw1,
|
|
cpu->core.fprs[11].uw0, cpu->core.fprs[11].uw1,
|
|
cpu->core.fprs[12].uw0, cpu->core.fprs[12].uw1,
|
|
cpu->core.fprs[13].uw0, cpu->core.fprs[13].uw1,
|
|
cpu->core.fprs[14].uw0, cpu->core.fprs[14].uw1,
|
|
cpu->core.fprs[15].uw0, cpu->core.fprs[15].uw1,
|
|
cpu->core.fprs[16].uw0, cpu->core.fprs[16].uw1,
|
|
cpu->core.fprs[17].uw0, cpu->core.fprs[17].uw1,
|
|
cpu->core.fprs[18].uw0, cpu->core.fprs[18].uw1,
|
|
cpu->core.fprs[19].uw0, cpu->core.fprs[19].uw1,
|
|
cpu->core.fprs[20].uw0, cpu->core.fprs[20].uw1,
|
|
cpu->core.fprs[21].uw0, cpu->core.fprs[21].uw1,
|
|
cpu->core.fprs[22].uw0, cpu->core.fprs[22].uw1,
|
|
cpu->core.fprs[23].uw0, cpu->core.fprs[23].uw1,
|
|
cpu->core.fprs[24].uw0, cpu->core.fprs[24].uw1,
|
|
cpu->core.fprs[25].uw0, cpu->core.fprs[25].uw1,
|
|
cpu->core.fprs[26].uw0, cpu->core.fprs[26].uw1,
|
|
cpu->core.fprs[27].uw0, cpu->core.fprs[27].uw1,
|
|
cpu->core.fprs[28].uw0, cpu->core.fprs[28].uw1,
|
|
cpu->core.fprs[29].uw0, cpu->core.fprs[29].uw1,
|
|
cpu->core.fprs[30].uw0, cpu->core.fprs[30].uw1,
|
|
cpu->core.fprs[31].uw0, cpu->core.fprs[31].uw1
|
|
);
|
|
Sys::out->write("\n");
|
|
Sys::out->write(
|
|
"srr0 = %08X srr1 = %08X dar = %08X dsisr= %08X\n"
|
|
"msr = %08X dec = %08X dabr = %08X iabr = %08X\n",
|
|
cpu->core.sprs[PPCCore::SRR0], cpu->core.sprs[PPCCore::SRR1],
|
|
cpu->core.sprs[PPCCore::DAR], cpu->core.sprs[PPCCore::DSISR],
|
|
cpu->core.msr, cpu->core.sprs[PPCCore::DEC],
|
|
cpu->core.sprs[PPCCore::DABR], cpu->core.sprs[PPCCore::IABR]
|
|
);
|
|
Sys::out->write("\n");
|
|
Sys::out->write(
|
|
"hid0 = %08X hid1 = %08X hid2 = %08X hid4 = %08X hid5 = %08X\n"
|
|
"pcsr = %08X scr = %08X car = %08X bcr = %08X pir = %08X\n"
|
|
"pvr = %08X wpar = %08X wpsar= %08X\n",
|
|
cpu->core.sprs[PPCCore::HID0], cpu->core.sprs[PPCCore::HID1],
|
|
cpu->core.sprs[PPCCore::HID2], cpu->core.sprs[PPCCore::HID4],
|
|
cpu->core.sprs[PPCCore::HID5], cpu->core.sprs[PPCCore::PCSR],
|
|
cpu->core.sprs[PPCCore::SCR], cpu->core.sprs[PPCCore::CAR],
|
|
cpu->core.sprs[PPCCore::BCR], cpu->core.sprs[PPCCore::PIR],
|
|
cpu->core.sprs[PPCCore::PVR], cpu->core.sprs[PPCCore::WPAR],
|
|
cpu->core.sprs[PPCCore::WPSAR]
|
|
);
|
|
}
|
|
|
|
void PPCDebugger::printStackTrace() {
|
|
ModuleList modules = getModules();
|
|
|
|
uint32_t sp = cpu->core.regs[1];
|
|
uint32_t lr = cpu->core.sprs[PPCCore::LR];
|
|
uint32_t pc = cpu->core.pc;
|
|
|
|
Sys::out->write("\n");
|
|
Sys::out->write("pc = %s\n", formatAddress(pc, modules));
|
|
Sys::out->write("lr = %s\n", formatAddress(lr, modules));
|
|
Sys::out->write("\n");
|
|
|
|
translate(&sp);
|
|
sp = physmem->read<uint32_t>(sp);
|
|
|
|
printStackTraceForThread(sp, modules);
|
|
}
|
|
|
|
void PPCDebugger::printStackTraceForThread(uint32_t sp, ModuleList &modules) {
|
|
Sys::out->write("Stack trace:\n");
|
|
while (sp) {
|
|
translate(&sp);
|
|
|
|
uint32_t lr = physmem->read<uint32_t>(sp + 4);
|
|
if (!lr) break;
|
|
|
|
Sys::out->write(" %s\n", formatAddress(lr, modules));
|
|
|
|
sp = physmem->read<uint32_t>(sp);
|
|
}
|
|
}
|
|
|
|
MemoryRegion::Access AccessProt[] = {
|
|
MemoryRegion::ReadWrite, MemoryRegion::ReadWrite,
|
|
MemoryRegion::ReadWrite, MemoryRegion::ReadOnly,
|
|
MemoryRegion::NoAccess, MemoryRegion::ReadOnly,
|
|
MemoryRegion::ReadWrite, MemoryRegion::ReadOnly
|
|
};
|
|
|
|
void PPCDebugger::printMemoryMap() {
|
|
Sys::out->write("DBAT:\n");
|
|
for (int i = 0; i < 8; i++) {
|
|
uint32_t batu = cpu->core.sprs[PPCCore::DBAT0U + i * 2 + i / 4 * 8];
|
|
uint32_t batl = cpu->core.sprs[PPCCore::DBAT0L + i * 2 + i / 4 * 8];
|
|
Sys::out->write(" dbat%i: ", i);
|
|
printBAT(batu, batl);
|
|
}
|
|
|
|
Sys::out->write("\nIBAT:\n");
|
|
for (int i = 0; i < 8; i++) {
|
|
uint32_t batu = cpu->core.sprs[PPCCore::IBAT0U + i * 2 + i / 4 * 8];
|
|
uint32_t batl = cpu->core.sprs[PPCCore::IBAT0L + i * 2 + i / 4 * 8];
|
|
Sys::out->write(" ibat%i: ", i);
|
|
printBAT(batu, batl);
|
|
}
|
|
|
|
uint32_t sdr1 = cpu->core.sprs[PPCCore::SDR1];
|
|
uint32_t pagetbl = phys(sdr1 & 0xFFFF0000);
|
|
uint32_t pagemask = sdr1 & 0x1FF;
|
|
uint32_t hashmask = (pagemask << 10) | 0x3FF;
|
|
|
|
Sys::out->write("\nPage table (%08X):\n", pagetbl);
|
|
|
|
MemoryMap memory(true);
|
|
|
|
for (uint32_t segment = 0; segment < 16; segment++) {
|
|
uint32_t sr = cpu->core.sr[segment];
|
|
if (sr >> 31) continue;
|
|
|
|
bool ks = (sr >> 30) & 1;
|
|
bool kp = (sr >> 29) & 1;
|
|
bool nx = (sr >> 28) & 1;
|
|
uint32_t vsid = sr & 0xFFFFFF;
|
|
|
|
for (uint32_t pageidx = 0; pageidx < 2048; pageidx++) {
|
|
uint32_t hash = ((vsid & 0x7FFFF) ^ pageidx) & hashmask;
|
|
uint32_t api = pageidx >> 5;
|
|
|
|
uint32_t pteaddr = pagetbl | (hash << 6);
|
|
for (int i = 0; i < 8; i++) {
|
|
uint64_t pte = physmem->read<uint64_t>(pteaddr + i * 8);
|
|
if (!(pte >> 63)) continue;
|
|
if ((pte >> 38) & 1) continue;
|
|
if (((pte >> 39) & 0xFFFFFF) != vsid) continue;
|
|
if (((pte >> 32) & 0x3F) != api) continue;
|
|
|
|
int pp = pte & 3;
|
|
|
|
Ref<MemoryRegion> region = new MemoryRegion();
|
|
region->virt = (segment << 28) | (pageidx << 17);
|
|
region->phys = pte & 0xFFFFF000;
|
|
region->size = 0x20000;
|
|
region->user = AccessProt[kp * 4 + pp];
|
|
region->system = AccessProt[ks * 4 + pp];
|
|
region->executable = !nx;
|
|
memory.add(region);
|
|
}
|
|
}
|
|
}
|
|
|
|
memory.print();
|
|
}
|
|
|
|
const char *BATValidity[] = {
|
|
"user mode only", "supervisor only", "user/supervisor"
|
|
};
|
|
|
|
const char *BATAccess[] = {
|
|
"no access", "read only", "read/write", "read only"
|
|
};
|
|
|
|
void PPCDebugger::printBAT(uint32_t batu, uint32_t batl) {
|
|
if (batu & 3) {
|
|
char caching[5] = "WIMG";
|
|
for (int i = 0; i < 4; i++) {
|
|
if (!(batl & (1 << (6 - i)))) {
|
|
caching[i] = '-';
|
|
}
|
|
}
|
|
|
|
const char *access = BATAccess[batl & 3];
|
|
const char *validity = BATValidity[(batu & 3) - 1];
|
|
|
|
uint32_t bl = (batu >> 2) & 0x7FF;
|
|
uint32_t size = (bl + 1) << 17;
|
|
uint64_t vaddr = batu & 0xFFFE0000;
|
|
uint64_t paddr = batl & 0xFFFE0000;
|
|
|
|
Sys::out->write(
|
|
"%08X-%08X => %08X-%08X (%s, %s, %s)\n",
|
|
vaddr, vaddr + size, paddr, paddr + size,
|
|
caching, access, validity
|
|
);
|
|
}
|
|
else {
|
|
Sys::out->write("disabled\n");
|
|
}
|
|
}
|
|
|
|
void PPCDebugger::printModules() {
|
|
ModuleList modules = getModules();
|
|
std::sort(modules.begin(), modules.end(), PPCModule::compareText);
|
|
|
|
for (Ref<PPCModule> module : modules) {
|
|
Sys::out->write(" %08X: %s\n", module->text, module->path);
|
|
}
|
|
}
|
|
|
|
void PPCDebugger::printModuleDetails(std::string name) {
|
|
ModuleList modules = getModules();
|
|
for (Ref<PPCModule> module : modules) {
|
|
if (module->path.find(name) != std::string::npos) {
|
|
Sys::out->write("%s:\n", module->path);
|
|
Sys::out->write(" .text: %08X - %08X\n", module->text, module->text + module->textsize);
|
|
Sys::out->write(" .data: %08X - %08X\n", module->data, module->data + module->datasize);
|
|
}
|
|
}
|
|
}
|
|
|
|
const char *ThreadAffinity[] = {
|
|
"invalid", "core 0", "core 1", "core 0/1",
|
|
"core 2", "core 0/2", "core 1/2", "any core"
|
|
};
|
|
|
|
void PPCDebugger::printThreads() {
|
|
if (!(cpu->core.msr & 0x10)) return;
|
|
|
|
ModuleList modules = getModules();
|
|
|
|
uint32_t thread = 0x100567F8;
|
|
if (!translate(&thread)) return;
|
|
|
|
thread = physmem->read<uint32_t>(thread);
|
|
while (thread) {
|
|
uint32_t addr = thread;
|
|
if (!translate(&thread)) break;
|
|
|
|
uint32_t entryPoint = physmem->read<uint32_t>(thread + 0x39C);
|
|
|
|
std::string owner;
|
|
for (Ref<PPCModule> module : modules) {
|
|
if (module->text <= entryPoint && entryPoint < module->text + module->textsize) {
|
|
owner = module->name;
|
|
}
|
|
}
|
|
|
|
std::string name = "<no name>";
|
|
|
|
uint32_t nameptr = physmem->read<uint32_t>(thread + 0x5C0);
|
|
if (nameptr) {
|
|
if (!translate(&nameptr)) break;
|
|
|
|
name = physmem->read<std::string>(nameptr);
|
|
}
|
|
|
|
uint32_t affinity = physmem->read<uint32_t>(thread + 0x304) & 7;
|
|
std::string core = StringUtils::format("[%s]", ThreadAffinity[affinity]);
|
|
|
|
uint8_t stateId = physmem->read<uint8_t>(thread + 0x324);
|
|
uint32_t priority = physmem->read<uint32_t>(thread + 0x32C);
|
|
|
|
std::string stateName = "invalid";
|
|
if (stateId == 1) stateName = "ready";
|
|
else if (stateId == 2) stateName = "running";
|
|
else if (stateId == 4) stateName = "waiting";
|
|
else if (stateId == 8) stateName = "dead";
|
|
|
|
std::string state = StringUtils::format("(%s)", stateName);
|
|
|
|
Sys::out->write(" %08X: %-12s %-10s p=%-2i %-9s %s\n", addr, owner, core, priority, state, name);
|
|
|
|
thread = physmem->read<uint32_t>(thread + 0x38C);
|
|
}
|
|
}
|
|
|
|
void PPCDebugger::printThreadDetails(uint32_t thread) {
|
|
if (!(cpu->core.msr & 0x10)) {
|
|
Sys::out->write("MMU is disabled.\n");
|
|
return;
|
|
}
|
|
|
|
if (!translate(&thread)) {
|
|
Sys::out->write("Address translation failed.\n");
|
|
return;
|
|
}
|
|
|
|
uint32_t tag = physmem->read<uint32_t>(thread + 0x320);
|
|
if (tag != 0x74487244) { //tHrD
|
|
Sys::out->write("This is not a valid thread.\n");
|
|
return;
|
|
}
|
|
|
|
ModuleList modules = getModules();
|
|
|
|
std::string name;
|
|
uint32_t nameptr = physmem->read<uint32_t>(thread + 0x5C0);
|
|
if (nameptr) {
|
|
translate(&nameptr);
|
|
name = physmem->read<std::string>(nameptr);
|
|
}
|
|
|
|
uint32_t sp = physmem->read<uint32_t>(thread + 0xC);
|
|
uint32_t stackBase = physmem->read<uint32_t>(thread + 0x394);
|
|
uint32_t stackTop = physmem->read<uint32_t>(thread + 0x398);
|
|
uint32_t entryPoint = physmem->read<uint32_t>(thread + 0x39C);
|
|
|
|
Sys::out->write("Name: %s\n\n", name);
|
|
Sys::out->write("Entry point: %s\n\n", formatAddress(entryPoint, modules));
|
|
Sys::out->write("Stack: 0x%08X - 0x%08X (0x%X bytes)\n\n", stackTop, stackBase, stackBase - stackTop);
|
|
printStackTraceForThread(sp, modules);
|
|
Sys::out->write("\n");
|
|
|
|
uint8_t state = physmem->read<uint8_t>(thread + 0x324);
|
|
if (state == 1) Sys::out->write("This thread is ready to run.\n");
|
|
else if (state == 2) Sys::out->write("This thread is running right now.\n");
|
|
else if (state == 4) printThreadWait(thread);
|
|
else if (state == 8) Sys::out->write("This thread is dead.\n");
|
|
else {
|
|
Sys::out->write("This thread has an invalid state.\n");
|
|
}
|
|
}
|
|
|
|
void PPCDebugger::printThreadWait(uint32_t thread) {
|
|
uint32_t queue = physmem->read<uint32_t>(thread + 0x35C);
|
|
if (queue && translate(&queue)) {
|
|
uint32_t parent = physmem->read<uint32_t>(queue + 8);
|
|
if (parent && translate(&parent)) {
|
|
std::string name = "<no name>";
|
|
uint32_t namePtr = physmem->read<uint32_t>(parent + 4);
|
|
if (namePtr && translate(&namePtr)) {
|
|
name = physmem->read<std::string>(namePtr);
|
|
}
|
|
|
|
uint32_t tag = physmem->read<uint32_t>(parent);
|
|
if (tag == 0x65566E54) Sys::out->write("This thread is waiting for an event: %s\n", name);
|
|
else if (tag == 0x614C724D) Sys::out->write("This thread is waiting for an alarm: %s\n", name);
|
|
else if (tag == 0x6D557458) Sys::out->write("This thread is waiting for a mutex: %s\n", name);
|
|
else if (tag == 0x634E6456) Sys::out->write("This thread is waiting for a condition variable: %s\n", name);
|
|
else if (tag == 0x73506852) Sys::out->write("This thread is waiting for a semaphore: %s\n", name);
|
|
else if (tag == 0x6D536751) Sys::out->write("This thread is waiting for a message queue: %s\n", name);
|
|
else if (tag == 0x614C6D51) Sys::out->write("This thread is waiting for an alarm queue: %s\n", name);
|
|
else {
|
|
Sys::out->write("This thread is currently waiting.\n");
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
Sys::out->write("This thread is currently waiting.\n");
|
|
}
|
|
|
|
std::string PPCDebugger::formatAddress(uint32_t addr, ModuleList &modules) {
|
|
for (Ref<PPCModule> module : modules) {
|
|
if (module->text <= addr && addr <= module->text + module->textsize) {
|
|
return StringUtils::format("%08X: %s:text+0x%X", addr, module->name, addr - module->text);
|
|
}
|
|
if (module->data <= addr && addr <= module->data + module->datasize) {
|
|
return StringUtils::format("%08X: %s:data+0x%X", addr, module->name, addr - module->data);
|
|
}
|
|
}
|
|
return StringUtils::format("%08X", addr);
|
|
}
|
|
|
|
PPCDebugger::ModuleList PPCDebugger::getModules() {
|
|
ModuleList modules;
|
|
|
|
uint32_t addr = 0x10081018;
|
|
if ((cpu->core.msr & 0x10) && translate(&addr)) {
|
|
addr = physmem->read<uint32_t>(addr);
|
|
while (addr) {
|
|
if (!translate(&addr)) break;
|
|
|
|
uint32_t info = physmem->read<uint32_t>(addr + 0x28);
|
|
if (!translate(&info)) break;
|
|
|
|
uint32_t pathAddr = physmem->read<uint32_t>(info);
|
|
if (!translate(&pathAddr)) break;
|
|
|
|
Ref<PPCModule> module = new PPCModule();
|
|
module->path = physmem->read<std::string>(pathAddr);
|
|
module->name = module->path.substr(module->path.rfind('\\') + 1);
|
|
module->text = physmem->read<uint32_t>(info + 4);
|
|
module->textsize = physmem->read<uint32_t>(info + 0xC);
|
|
module->data = physmem->read<uint32_t>(info + 0x10);
|
|
module->datasize = physmem->read<uint32_t>(info + 0x18);
|
|
modules.push_back(module);
|
|
|
|
addr = physmem->read<uint32_t>(addr + 0x54);
|
|
}
|
|
}
|
|
|
|
return modules;
|
|
}
|
|
|
|
void PPCDebugger::printIPC() {
|
|
Sys::out->write("PPC %i:\n", index);
|
|
|
|
uint32_t driver = phys(0xFFE86760 + index * 0x2178);
|
|
|
|
uint32_t fifo = driver + 0x3E8;
|
|
Sys::out->write(" Sending: %i\n", physmem->read<uint32_t>(fifo + 8));
|
|
Sys::out->write(" Peak: %i\n", physmem->read<uint32_t>(fifo + 12));
|
|
|
|
Sys::out->write("\n");
|
|
Sys::out->write(" Waiting for reply:\n");
|
|
for (int i = 0; i < 0xB0; i++) {
|
|
uint32_t addr = driver + 0x13B8 + i * 0x14;
|
|
uint32_t callback = physmem->read<uint32_t>(addr + 4);
|
|
if (callback) {
|
|
uint32_t request = phys(physmem->read<uint32_t>(addr + 0x10));
|
|
printIPCRequest(request);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PPCDebugger::printIPCRequest(uint32_t request) {
|
|
uint32_t cmd = physmem->read<uint32_t>(request);
|
|
uint32_t arg0 = physmem->read<uint32_t>(request + 0x24);
|
|
uint32_t arg1 = physmem->read<uint32_t>(request + 0x28);
|
|
uint32_t arg2 = physmem->read<uint32_t>(request + 0x2C);
|
|
uint32_t arg3 = physmem->read<uint32_t>(request + 0x30);
|
|
uint32_t arg4 = physmem->read<uint32_t>(request + 0x34);
|
|
if (cmd == 1) {
|
|
std::string name = physmem->read<std::string>(arg0);
|
|
Sys::out->write(" OPEN(%s)\n", name);
|
|
}
|
|
else if (cmd == 2) Sys::out->write(" CLOSE()\n");
|
|
else if (cmd == 3) Sys::out->write(" READ(0x%X, 0x%X)\n", arg0, arg1);
|
|
else if (cmd == 4) Sys::out->write(" WRITE(0xX, 0x%X)\n", arg0, arg1);
|
|
else if (cmd == 5) Sys::out->write(" SEEK(0x%X, %i)\n", arg0, arg1);
|
|
else if (cmd == 6) Sys::out->write(" IOCTL(%i, 0x%X, 0x%X, 0x%X, 0x%X)\n", arg0, arg1, arg2, arg3, arg4);
|
|
else if (cmd == 7) Sys::out->write(" IOCTLV(%i, %i, %i, 0x%X)\n", arg0, arg1, arg2, arg3);
|
|
else {
|
|
Sys::out->write(" ?\n");
|
|
}
|
|
}
|
|
|
|
#if STATS
|
|
void PPCDebugger::printStats() {
|
|
Sys::out->write("\n");
|
|
Sys::out->write("PPC %i:\n", index);
|
|
Sys::out->write(" Instructions executed: %i\n", cpu->instrsExecuted);
|
|
Sys::out->write(
|
|
" Instructions executed (jit): %i (%i%%)\n", cpu->jit.instrsExecuted,
|
|
percentage(cpu->jit.instrsExecuted, cpu->instrsExecuted)
|
|
);
|
|
Sys::out->write(
|
|
" Instructions compiled (jit): %i (avg usage: %i)\n", cpu->jit.instrsCompiled,
|
|
divide(cpu->jit.instrsExecuted, cpu->jit.instrsCompiled)
|
|
);
|
|
Sys::out->write(
|
|
" JIT memory usage: %i bytes (%i per instr)\n", cpu->jit.instrSize,
|
|
divide(cpu->jit.instrSize, cpu->jit.instrsCompiled)
|
|
);
|
|
Sys::out->write(" \n");
|
|
Sys::out->write(" MMU cache hits: %i\n", cpu->mmu.cache.hits);
|
|
Sys::out->write(" MMU cache misses: %i\n", cpu->mmu.cache.misses);
|
|
Sys::out->write(" \n");
|
|
Sys::out->write(" DSI exceptions %i\n", cpu->core.dsiExceptions);
|
|
Sys::out->write(" ISI exceptions: %i\n", cpu->core.isiExceptions);
|
|
Sys::out->write(" External intr: %i\n", cpu->core.externalInterrupts);
|
|
Sys::out->write(" Decrementer intr: %i\n", cpu->core.decrementerInterrupts);
|
|
Sys::out->write(" System calls: %i\n", cpu->core.systemCalls);
|
|
}
|
|
#endif
|