mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 11:36:13 +00:00
Debugger: Implement code flow tracking
This commit is contained in:
parent
427cf91447
commit
15a12afe25
6 changed files with 100 additions and 1 deletions
|
@ -72,6 +72,8 @@ constexpr u32 ppu_decode(u32 inst)
|
|||
return ((inst >> 26) | (inst << 6)) & 0x1ffff; // Rotate + mask
|
||||
}
|
||||
|
||||
std::array<u32, 2> op_branch_targets(u32 pc, ppu_opcode_t op);
|
||||
|
||||
// PPU decoder object. D provides functions. T is function pointer type returned.
|
||||
template <typename D, typename T = decltype(&D::UNK)>
|
||||
class ppu_decoder
|
||||
|
|
|
@ -422,6 +422,31 @@ extern bool ppu_patch(u32 addr, u32 value)
|
|||
return true;
|
||||
}
|
||||
|
||||
std::array<u32, 2> op_branch_targets(u32 pc, ppu_opcode_t op)
|
||||
{
|
||||
std::array<u32, 2> res{pc + 4, UINT32_MAX};
|
||||
|
||||
switch (const auto type = g_ppu_itype.decode(op.opcode))
|
||||
{
|
||||
case ppu_itype::B:
|
||||
case ppu_itype::BC:
|
||||
{
|
||||
res[type == ppu_itype::BC ? 1 : 0] = ((op.aa ? 0 : pc) + (type == ppu_itype::B ? +op.bt24 : +op.bt14));
|
||||
break;
|
||||
}
|
||||
case ppu_itype::BCCTR:
|
||||
case ppu_itype::BCLR:
|
||||
case ppu_itype::UNK:
|
||||
{
|
||||
res[0] = UINT32_MAX;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string ppu_thread::dump_all() const
|
||||
{
|
||||
std::string ret = cpu_thread::dump_misc();
|
||||
|
|
|
@ -41,6 +41,8 @@ static u32 spu_decode(u32 inst)
|
|||
return inst >> 21;
|
||||
}
|
||||
|
||||
std::array<u32, 2> op_branch_targets(u32 pc, spu_opcode_t op);
|
||||
|
||||
// SPU decoder object. D provides functions. T is function pointer type returned.
|
||||
template <typename D, typename T = decltype(&D::UNK)>
|
||||
class spu_decoder
|
||||
|
|
|
@ -373,6 +373,45 @@ namespace spu
|
|||
}
|
||||
}
|
||||
|
||||
std::array<u32, 2> op_branch_targets(u32 pc, spu_opcode_t op)
|
||||
{
|
||||
std::array<u32, 2> res{spu_branch_target(pc + 4), UINT32_MAX};
|
||||
|
||||
switch (const auto type = s_spu_itype.decode(op.opcode))
|
||||
{
|
||||
case spu_itype::BR:
|
||||
case spu_itype::BRA:
|
||||
case spu_itype::BRNZ:
|
||||
case spu_itype::BRZ:
|
||||
case spu_itype::BRHNZ:
|
||||
case spu_itype::BRHZ:
|
||||
case spu_itype::BRSL:
|
||||
case spu_itype::BRASL:
|
||||
{
|
||||
const int index = (type == spu_itype::BR || type == spu_itype::BRA || type == spu_itype::BRSL || type == spu_itype::BRASL ? 0 : 1);
|
||||
res[index] = (spu_branch_target(type == spu_itype::BRASL || type == spu_itype::BRA ? 0 : pc, op.i16));
|
||||
break;
|
||||
}
|
||||
case spu_itype::IRET:
|
||||
case spu_itype::BI:
|
||||
case spu_itype::BISLED:
|
||||
case spu_itype::BISL:
|
||||
case spu_itype::BIZ:
|
||||
case spu_itype::BINZ:
|
||||
case spu_itype::BIHZ:
|
||||
case spu_itype::BIHNZ: // TODO (detect constant address branches, such as for interrupts enable/disable pattern)
|
||||
|
||||
case spu_itype::UNK:
|
||||
{
|
||||
res[0] = UINT32_MAX;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
const auto spu_putllc_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime, void* _old, const void* _new)>([](asmjit::X86Assembler& c, auto& args)
|
||||
{
|
||||
using namespace asmjit;
|
||||
|
|
|
@ -283,6 +283,37 @@ void debugger_frame::keyPressEvent(QKeyEvent* event)
|
|||
}
|
||||
return;
|
||||
}
|
||||
case Qt::Key_N:
|
||||
{
|
||||
// Next instruction according to code flow
|
||||
// Known branch targets are selected over next PC for conditional branches
|
||||
// Indirect branches (unknown targets, such as function return) do not proceed to any instruction
|
||||
std::array<u32, 2> res{UINT32_MAX, UINT32_MAX};
|
||||
|
||||
switch (cpu->id_type())
|
||||
{
|
||||
case 2:
|
||||
{
|
||||
res = op_branch_targets(pc, spu_opcode_t{static_cast<spu_thread*>(cpu.get())->_ref<u32>(pc)});
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
be_t<ppu_opcode_t> op{};
|
||||
|
||||
if (vm::try_access(pc, &op, 4, false))
|
||||
res = op_branch_targets(pc, op);
|
||||
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (auto pos = std::basic_string_view<u32>(res.data(), 2).find_last_not_of(UINT32_MAX); pos != umax)
|
||||
m_debugger_list->ShowAddress(res[pos] - std::max(i, 0) * 4, true);
|
||||
|
||||
return;
|
||||
}
|
||||
case Qt::Key_F10:
|
||||
{
|
||||
DoStep(true);
|
||||
|
|
|
@ -134,7 +134,7 @@ void debugger_list::ShowAddress(u32 addr, bool force)
|
|||
|
||||
void debugger_list::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
if (!isActiveWindow() || currentRow() < 0 || !this->cpu.lock())
|
||||
if (!isActiveWindow())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue