diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 24a37cc6ea..3825a742e9 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1505,7 +1505,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no { if (!access_violation_recovered) { - vm_log.notice("\n%s", cpu->dump()); + vm_log.notice("\n%s", cpu->dump_all()); vm_log.error("Access violation %s location 0x%x (%s)", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory"); } @@ -1536,7 +1536,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no if (cpu && !access_violation_recovered) { - vm_log.notice("\n%s", cpu->dump()); + vm_log.notice("\n%s", cpu->dump_all()); } // Note: a thread may access violate more than once after hack_alloc recovery @@ -1617,7 +1617,7 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp) noexcept if (const auto cpu = get_current_cpu_thread()) { - sys_log.notice("\n%s", cpu->dump()); + sys_log.notice("\n%s", cpu->dump_all()); } } @@ -1746,7 +1746,7 @@ static void signal_handler(int sig, siginfo_t* info, void* uct) noexcept if (const auto cpu = get_current_cpu_thread()) { - sys_log.notice("\n%s", cpu->dump()); + sys_log.notice("\n%s", cpu->dump_all()); } std::string msg = fmt::format("Segfault %s location %p at %p.\n", cause, info->si_addr, RIP(context)); diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 4e107a6bb9..e1212ac8fe 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -412,7 +412,7 @@ void cpu_thread::operator()() { if (_this) { - sys_log.warning("CPU Thread '%s' terminated abnormally:\n%s", name, _this->dump()); + sys_log.warning("CPU Thread '%s' terminated abnormally:\n%s", name, _this->dump_all()); cleanup(); } } @@ -599,7 +599,27 @@ std::string cpu_thread::get_name() const } } -std::string cpu_thread::dump() const +std::string cpu_thread::dump_all() const +{ + return {}; +} + +std::string cpu_thread::dump_regs() const +{ + return {}; +} + +std::string cpu_thread::dump_callstack() const +{ + return {}; +} + +std::vector cpu_thread::dump_callstack_list() const +{ + return {}; +} + +std::string cpu_thread::dump_misc() const { return fmt::format("Type: %s\n" "State: %s\n", typeid(*this).name(), state.load()); } diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 2a891db006..2d7cb5e7eb 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -1,8 +1,10 @@ -#pragma once +#pragma once #include "../Utilities/Thread.h" #include "../Utilities/bit_set.h" +#include + // Thread state flags enum class cpu_flag : u32 { @@ -91,8 +93,20 @@ public: // Get thread name (as assigned to named_thread) std::string get_name() const; - // Get CPU state dump - virtual std::string dump() const; + // Get CPU state dump (everything) + virtual std::string dump_all() const = 0; + + // Get CPU register dump + virtual std::string dump_regs() const; + + // Get CPU call stack dump + virtual std::string dump_callstack() const; + + // Get CPU call stack list + virtual std::vector dump_callstack_list() const; + + // Get CPU dump of misc information + virtual std::string dump_misc() const; // Thread entry point function virtual void cpu_task() = 0; diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 439f55e8d9..2e2ec623ad 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -58,6 +58,7 @@ #include #include +#include const bool s_use_ssse3 = utils::has_ssse3(); @@ -368,9 +369,96 @@ extern bool ppu_patch(u32 addr, u32 value) return true; } -std::string ppu_thread::dump() const +std::string ppu_thread::dump_all() const { - std::string ret = cpu_thread::dump(); + std::string ret = cpu_thread::dump_misc() + '\n'; + + ret += dump_misc() + '\n'; + ret += dump_regs() + '\n'; + ret += dump_callstack(); + + return ret; +} + +std::string ppu_thread::dump_regs() const +{ + std::string ret; + + for (uint i = 0; i < 32; ++i) fmt::append(ret, "GPR[%d] = 0x%llx\n", i, gpr[i]); + for (uint i = 0; i < 32; ++i) fmt::append(ret, "FPR[%d] = %.6G\n", i, fpr[i]); + for (uint i = 0; i < 32; ++i) fmt::append(ret, "VR[%d] = %s [x: %g y: %g z: %g w: %g]\n", i, vr[i], vr[i]._f[3], vr[i]._f[2], vr[i]._f[1], vr[i]._f[0]); + + fmt::append(ret, "CR = 0x%08x\n", cr.pack()); + fmt::append(ret, "LR = 0x%llx\n", lr); + fmt::append(ret, "CTR = 0x%llx\n", ctr); + fmt::append(ret, "VRSAVE = 0x%08x\n", vrsave); + fmt::append(ret, "XER = [CA=%u | OV=%u | SO=%u | CNT=%u]\n", xer.ca, xer.ov, xer.so, xer.cnt); + fmt::append(ret, "VSCR = [SAT=%u | NJ=%u]\n", sat, nj); + fmt::append(ret, "FPSCR = [FL=%u | FG=%u | FE=%u | FU=%u]\n", fpscr.fl, fpscr.fg, fpscr.fe, fpscr.fu); + + return ret; +} + +std::string ppu_thread::dump_callstack() const +{ + std::string ret; + + fmt::append(ret, "Call stack:\n=========\n0x%08x (0x0) called\n", cia); + + for (u32 sp : dump_callstack_list()) + { + // TODO: function addresses too + fmt::append(ret, "> from 0x%04llx (0x0)\n", vm::read64(static_cast(sp + 16))); + } + + return ret; +} + +std::vector ppu_thread::dump_callstack_list() const +{ + //std::shared_lock rlock(vm::g_mutex); // Needs optimizations + + // Determine stack range + const u32 stack_ptr = static_cast(gpr[1]); + + if (!vm::check_addr(stack_ptr, 1, vm::page_writable)) + { + // Normally impossible unless the code does not follow ABI rules + return {}; + } + + u32 stack_min = stack_ptr & ~0xfff; + u32 stack_max = stack_min + 4096; + + while (stack_min && vm::check_addr(stack_min - 4096, 4096, vm::page_writable)) + { + stack_min -= 4096; + } + + while (stack_max + 4096 && vm::check_addr(stack_max, 4096, vm::page_writable)) + { + stack_max += 4096; + } + + std::vector call_stack_list; + + for ( + u64 sp = *vm::get_super_ptr(stack_ptr); + sp >= stack_min && std::max(sp, sp + 0x200) < stack_max; + sp = *vm::get_super_ptr(static_cast(sp)) + ) + { + // TODO: function addresses too + call_stack_list.push_back(*vm::get_super_ptr(static_cast(sp + 16))); + } + + return call_stack_list; +} + +std::string ppu_thread::dump_misc() const +{ + std::string ret; + fmt::append(ret, "Priority: %d\n", +prio); fmt::append(ret, "Stack: 0x%x..0x%x\n", stack_addr, stack_addr + stack_size - 1); fmt::append(ret, "Joiner: %s\n", joiner.load()); @@ -411,51 +499,6 @@ std::string ppu_thread::dump() const { ret += '\n'; } - - ret += "\nRegisters:\n=========\n"; - for (uint i = 0; i < 32; ++i) fmt::append(ret, "GPR[%d] = 0x%llx\n", i, gpr[i]); - for (uint i = 0; i < 32; ++i) fmt::append(ret, "FPR[%d] = %.6G\n", i, fpr[i]); - for (uint i = 0; i < 32; ++i) fmt::append(ret, "VR[%d] = %s [x: %g y: %g z: %g w: %g]\n", i, vr[i], vr[i]._f[3], vr[i]._f[2], vr[i]._f[1], vr[i]._f[0]); - - fmt::append(ret, "CR = 0x%08x\n", cr.pack()); - fmt::append(ret, "LR = 0x%llx\n", lr); - fmt::append(ret, "CTR = 0x%llx\n", ctr); - fmt::append(ret, "VRSAVE = 0x%08x\n", vrsave); - fmt::append(ret, "XER = [CA=%u | OV=%u | SO=%u | CNT=%u]\n", xer.ca, xer.ov, xer.so, xer.cnt); - fmt::append(ret, "VSCR = [SAT=%u | NJ=%u]\n", sat, nj); - fmt::append(ret, "FPSCR = [FL=%u | FG=%u | FE=%u | FU=%u]\n", fpscr.fl, fpscr.fg, fpscr.fe, fpscr.fu); - fmt::append(ret, "\nCall stack:\n=========\n0x%08x (0x0) called\n", cia); - - //std::shared_lock rlock(vm::g_mutex); // Needs optimizations - - // Determine stack range - u32 stack_ptr = static_cast(gpr[1]); - - if (!vm::check_addr(stack_ptr, 1, vm::page_writable)) - { - // Normally impossible unless the code does not follow ABI rules - return ret; - } - - u32 stack_min = stack_ptr & ~0xfff; - u32 stack_max = stack_min + 4096; - - while (stack_min && vm::check_addr(stack_min - 4096, 4096, vm::page_writable)) - { - stack_min -= 4096; - } - - while (stack_max + 4096 && vm::check_addr(stack_max, 4096, vm::page_writable)) - { - stack_max += 4096; - } - - for (u64 sp = *vm::get_super_ptr(stack_ptr); sp >= stack_min && std::max(sp, sp + 0x200) < stack_max; sp = *vm::get_super_ptr(static_cast(sp))) - { - // TODO: print also function addresses - fmt::append(ret, "> from 0x%08llx (0x0)\n", *vm::get_super_ptr(static_cast(sp + 16))); - } - return ret; } diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 8ea091df1d..8f04e02f24 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -53,7 +53,11 @@ public: static const u32 id_step = 1; static const u32 id_count = 2048; - virtual std::string dump() const override; + virtual std::string dump_all() const override; + virtual std::string dump_regs() const override; + virtual std::string dump_callstack() const override; + virtual std::vector dump_callstack_list() const override; + virtual std::string dump_misc() const override; virtual void cpu_task() override final; virtual void cpu_sleep() override; virtual void cpu_mem() override; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index d1c58afe91..f9a9c165ab 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1009,9 +1009,41 @@ spu_imm_table_t::spu_imm_table_t() } } -std::string spu_thread::dump() const +std::string spu_thread::dump_all() const { - std::string ret = cpu_thread::dump(); + std::string ret = cpu_thread::dump_misc() + '\n'; + + ret += dump_misc() + '\n'; + ret += dump_regs(); + + return ret; +} + +std::string spu_thread::dump_regs() const +{ + std::string ret; + + for (u32 i = 0; i < 128; i++) + { + fmt::append(ret, "\nGPR[%d] = %s", i, gpr[i]); + } + + return ret; +} + +std::string spu_thread::dump_callstack() const +{ + return {}; +} + +std::vector spu_thread::dump_callstack_list() const +{ + return {}; +} + +std::string spu_thread::dump_misc() const +{ + std::string ret; fmt::append(ret, "\nBlock Weight: %u (Retreats: %u)", block_counter, block_failure); @@ -1028,7 +1060,6 @@ std::string spu_thread::dump() const // Print chunk address from lowest 16 bits fmt::append(ret, "...chunk-0x%05x", (name & 0xffff) * 4); } - fmt::append(ret, "\n[%s]", ch_mfc_cmd); fmt::append(ret, "\nLocal Storage: 0x%08x..0x%08x", offset, offset + 0x3ffff); fmt::append(ret, "\nTag Mask: 0x%08x", ch_tag_mask); @@ -1047,13 +1078,6 @@ std::string spu_thread::dump() const } } - ret += "\nRegisters:\n========="; - - for (u32 i = 0; i < 128; i++) - { - fmt::append(ret, "\nGPR[%d] = %s", i, gpr[i]); - } - return ret; } diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index a4f28230eb..4489cfe6b4 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -498,7 +498,11 @@ public: class spu_thread : public cpu_thread { public: - virtual std::string dump() const override; + virtual std::string dump_all() const override; + virtual std::string dump_regs() const override; + virtual std::string dump_callstack() const override; + virtual std::vector dump_callstack_list() const override; + virtual std::string dump_misc() const override; virtual void cpu_task() override final; virtual void cpu_mem() override; virtual void cpu_unmem() override;