Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debugger/Disasm: Name PPU Syscalls #10939

Merged
merged 2 commits into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
148 changes: 148 additions & 0 deletions rpcs3/Emu/Cell/PPUDisAsm.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
#include "stdafx.h"
#include "PPUDisAsm.h"
#include "PPUFunction.h"
#include "PPUAnalyser.h"
#include "Emu/IdManager.h"

const ppu_decoder<PPUDisAsm> s_ppu_disasm;
const ppu_decoder<ppu_itype> s_ppu_itype;

extern const std::unordered_map<u32, std::string_view>& get_exported_function_names_as_addr_indexed_map();

enum class ppu_syscall_code : u64;

u32 PPUDisAsm::disasm(u32 pc)
{
dump_pc = pc;
Expand All @@ -14,6 +19,11 @@ u32 PPUDisAsm::disasm(u32 pc)
m_op = op;
(this->*(s_ppu_disasm.decode(m_op)))({ m_op });

if (m_mode != cpu_disasm_mode::interpreter && m_mode != cpu_disasm_mode::normal)
{
return 4;
}

const auto& map = get_exported_function_names_as_addr_indexed_map();

if (auto it = map.find(pc); it != map.end())
Expand All @@ -25,6 +35,137 @@ u32 PPUDisAsm::disasm(u32 pc)
return 4;
}

std::pair<bool, u64> PPUDisAsm::try_get_const_gpr_value(u32 reg, u32 pc) const
{
if (m_mode != cpu_disasm_mode::interpreter && m_mode != cpu_disasm_mode::normal)
{
return {};
}

if (pc == umax)
{
pc = dump_pc;
}

if (!vm::check_addr(pc, vm::page_executable))
{
return {};
}

// Scan PPU executable memory backwards until unmapped or non-executable memory block is encountered

for (u32 i = pc - 4; vm::check_addr(i, vm::page_executable); i -= 4)
{
const u32 opcode = *reinterpret_cast<const be_t<u32>*>(m_offset + i);
const ppu_opcode_t op{ opcode };

const auto type = s_ppu_itype.decode(opcode);

auto is_branch = [](enum ppu_itype::type itype)
{
return itype == ppu_itype::BC || itype == ppu_itype::B || itype == ppu_itype::BCLR || itype == ppu_itype::BCCTR;
};

if (is_branch(type) || type == ppu_itype::UNK)
{
// TODO: Detect calls, ignore them if reg is a non-volatile register
return {};
}

// Get constant register value
#define GET_CONST_REG(var, reg) \
{\
/* Search for the constant value of the register*/\
const auto [is_const, value] = try_get_const_gpr_value(reg, i);\
\
if (!is_const)\
{\
/* Cannot compute constant value if register is not constant*/\
return {};\
}\
\
var = value;\
} void() /*<- Require a semicolon*/

switch (type)
{
case ppu_itype::ADDI:
{
if (op.rd != reg)
{
// Destination register is not relevant to us
break;
}

u64 reg_ra = 0;

if (op.ra)
{
GET_CONST_REG(reg_ra, op.ra);
}

return { true, reg_ra + op.simm16 };
}
case ppu_itype::ADDIS:
{
if (op.rd != reg)
{
break;
}

u64 reg_ra = 0;

if (op.ra)
{
GET_CONST_REG(reg_ra, op.ra);
}

return { true, reg_ra + op.simm16 * 65536 };
}
case ppu_itype::ORI:
{
if (op.ra != reg)
{
// Destination register is not relevant to us
break;
}

u64 reg_rs = 0;

GET_CONST_REG(reg_rs, op.rs);

return { true, reg_rs | op.uimm16 };
}
case ppu_itype::ORIS:
{
if (op.ra != reg)
{
break;
}

u64 reg_rs = 0;

GET_CONST_REG(reg_rs, op.rs);

return { true, reg_rs | (u64{op.uimm16} << 16)};
}
default:
{
// Ordinary test
// TODO: Proper detection of destination register(s) modification (if there are any)
if (op.ra == reg || op.rd == reg)
{
return {};
}

break;
}
}
}

return {};
}

constexpr std::pair<const char*, char> get_BC_info(u32 bo, u32 bi)
{
std::pair<const char*, char> info{};
Expand Down Expand Up @@ -999,6 +1140,13 @@ void PPUDisAsm::SC(ppu_opcode_t op)
return UNK(op);
}

// Try to get constant syscall index
if (auto [is_const, index] = try_get_const_gpr_value(11); is_const && index < 1024u)
{
Write(fmt::format("sc #%s", ppu_syscall_code{index}));
return;
}

Write("sc");
}

Expand Down
1 change: 1 addition & 0 deletions rpcs3/Emu/Cell/PPUDisAsm.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ class PPUDisAsm final : public PPCDisAsm

public:
u32 disasm(u32 pc) override;
std::pair<bool, u64> try_get_const_gpr_value(u32 reg, u32 pc = -1) const;

void MFVSCR(ppu_opcode_t op);
void MTVSCR(ppu_opcode_t op);
Expand Down
1 change: 0 additions & 1 deletion rpcs3/Emu/Cell/PPUThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,6 @@ bool ppu_form_branch_to_code(u32 entry, u32 target, bool link, bool with_toc, st
return false;
}

if (module_name.empty())
g_fxo->init<ppu_far_jumps_t>();

if (!module_name.empty())
Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Emu/Cell/SPUDisAsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ u32 SPUDisAsm::disasm(u32 pc)

std::pair<bool, v128> SPUDisAsm::try_get_const_value(u32 reg, u32 pc) const
{
if (m_mode != cpu_disasm_mode::interpreter)
if (m_mode != cpu_disasm_mode::interpreter && m_mode != cpu_disasm_mode::normal)
{
return {};
}
Expand Down