RSX-Debugger: Implement backwards scrolling

* Use 2 points of known true RSX code roots and follow them in order to peek at the current section of valid RSX code:
These roots are: current RSX instruction address and the last targeted address by a branch instruction.
This commit is contained in:
Eladash 2022-03-25 18:17:25 +03:00 committed by Ivan
parent 26d8120168
commit 1d51f3af0c
10 changed files with 108 additions and 34 deletions

View file

@ -10,6 +10,7 @@ enum class cpu_disasm_mode
normal,
compiler_elf,
list, // RSX exclusive
survey_cmd_size, // RSX exclusive
};
class cpu_thread;

View file

@ -1146,7 +1146,7 @@ error_code cellGameGetParamString(s32 id, vm::ptr<char> buf, u32 bufsize)
return CELL_GAME_ERROR_NOTSUPPORTED;
}
const auto value = psf::get_string(perm.sfo, std::string(key.name));
const auto value = psf::get_string(perm.sfo, key.name);
if (value.empty() && !perm.sfo.count(std::string(key.name)))
{
@ -1189,7 +1189,7 @@ error_code cellGameSetParamString(s32 id, vm::cptr<char> buf)
return CELL_GAME_ERROR_NOTSUPPORTED;
}
psf::assign(perm.sfo, std::string(key.name), psf::string(key.max_size, buf.get_ptr()));
psf::assign(perm.sfo, key.name, psf::string(key.max_size, buf.get_ptr()));
return CELL_OK;
}

View file

@ -433,6 +433,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
const u64 get = static_cast<u32>(a3);
const u64 put = static_cast<u32>(a4);
vm::_ref<atomic_be_t<u64>>(render->dma_address + ::offset32(&RsxDmaControl::put)).release(put << 32 | get);
render->last_known_code_start = get;
render->sync_point_request.release(true);
render->unpause();
break;

View file

@ -109,7 +109,7 @@ u32 RSXDisAsm::disasm(u32 pc)
pc += 4;
for (u32 i = 0; i < (m_mode == cpu_disasm_mode::list ? count : 1); i++, pc += 4)
for (u32 i = 0; i < count; i++, pc += 4)
{
if (!try_read_op(pc))
{
@ -127,6 +127,16 @@ u32 RSXDisAsm::disasm(u32 pc)
return 4;
}
if (m_mode == cpu_disasm_mode::survey_cmd_size)
{
continue;
}
if (m_mode != cpu_disasm_mode::list && !last_opcode.empty())
{
continue;
}
std::string str = rsx::get_pretty_printing_function(id)(id, m_op);
Write(str, m_mode == cpu_disasm_mode::list ? i : count, non_inc, id);
}
@ -145,7 +155,7 @@ std::unique_ptr<CPUDisAsm> RSXDisAsm::copy_type_erased() const
return std::make_unique<RSXDisAsm>(*this);
}
void RSXDisAsm::Write(const std::string& str, s32 count, bool is_non_inc, u32 id)
void RSXDisAsm::Write(std::string_view str, s32 count, bool is_non_inc, u32 id)
{
switch (m_mode)
{
@ -156,8 +166,7 @@ void RSXDisAsm::Write(const std::string& str, s32 count, bool is_non_inc, u32 id
auto& res = last_opcode;
res.resize(7 + 11);
std::replace(res.begin(), res.end(), '\0', ' ');
res.resize(7 + 11, ' ');
res += str;
break;

View file

@ -10,7 +10,7 @@ public:
}
private:
void Write(const std::string& str, s32 count, bool is_non_inc = false, u32 id = 0);
void Write(std::string_view str, s32 count, bool is_non_inc = false, u32 id = 0);
public:
u32 disasm(u32 pc) override;

View file

@ -6,6 +6,8 @@
#include "Common/time.hpp"
#include "Emu/Cell/lv2/sys_rsx.h"
#include <bitset>
namespace rsx
{
namespace FIFO
@ -38,10 +40,10 @@ namespace rsx
}
}
template <bool full>
template <bool Full>
inline u32 FIFO_control::read_put() const
{
if constexpr (!full)
if constexpr (!Full)
{
return m_ctrl->put & ~3;
}
@ -56,9 +58,9 @@ namespace rsx
}
}
void FIFO_control::set_get(u32 get)
void FIFO_control::set_get(u32 get, bool check_spin)
{
if (m_ctrl->get == get)
if (check_spin && m_ctrl->get == get)
{
if (const u32 addr = m_iotable->get_addr(m_memwatch_addr); addr + 1)
{
@ -72,9 +74,6 @@ namespace rsx
// Update ctrl registers
m_ctrl->get.release(m_internal_get = get);
m_remaining_commands = 0;
// Clear memwatch spinner
m_memwatch_addr = 0;
}
bool FIFO_control::read_unsafe(register_pair& data)
@ -430,9 +429,12 @@ namespace rsx
}
// Check for flow control
if ((cmd & RSX_METHOD_OLD_JUMP_CMD_MASK) == RSX_METHOD_OLD_JUMP_CMD)
if (std::bitset<2> jump_type; jump_type
.set(0, (cmd & RSX_METHOD_OLD_JUMP_CMD_MASK) == RSX_METHOD_OLD_JUMP_CMD)
.set(1, (cmd & RSX_METHOD_NEW_JUMP_CMD_MASK) == RSX_METHOD_NEW_JUMP_CMD)
.any())
{
const u32 offs = cmd & RSX_METHOD_OLD_JUMP_OFFSET_MASK;
const u32 offs = cmd & (jump_type.test(0) ? RSX_METHOD_OLD_JUMP_OFFSET_MASK : RSX_METHOD_NEW_JUMP_OFFSET_MASK);
if (offs == fifo_ctrl->get_pos())
{
//Jump to self. Often preceded by NOP
@ -444,24 +446,9 @@ namespace rsx
performance_counters.state = FIFO_state::spinning;
}
//rsx_log.warning("rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put);
fifo_ctrl->set_get(offs);
return;
}
if ((cmd & RSX_METHOD_NEW_JUMP_CMD_MASK) == RSX_METHOD_NEW_JUMP_CMD)
{
const u32 offs = cmd & RSX_METHOD_NEW_JUMP_OFFSET_MASK;
if (offs == fifo_ctrl->get_pos())
else
{
//Jump to self. Often preceded by NOP
if (performance_counters.state == FIFO_state::running)
{
performance_counters.FIFO_idle_timestamp = rsx::uclock();
sync_point_request.release(true);
}
performance_counters.state = FIFO_state::spinning;
last_known_code_start = offs;
}
//rsx_log.warning("rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put);
@ -481,6 +468,7 @@ namespace rsx
const u32 offs = cmd & RSX_METHOD_CALL_OFFSET_MASK;
fifo_ret_addr = fifo_ctrl->get_pos() + 4;
fifo_ctrl->set_get(offs);
last_known_code_start = offs;
return;
}
if ((cmd & RSX_METHOD_RETURN_MASK) == RSX_METHOD_RETURN_CMD)
@ -493,6 +481,7 @@ namespace rsx
}
fifo_ctrl->set_get(std::exchange(fifo_ret_addr, RSX_CALL_STACK_EMPTY));
last_known_code_start = ctrl->get;
return;
}

View file

@ -134,7 +134,8 @@ namespace rsx
u32 get_current_arg_ptr() const { return m_args_ptr; }
u32 get_remaining_args_count() const { return m_remaining_commands; }
void inc_get(bool wait);
void set_get(u32 get);
void set_get(u32 get, bool check_spin = false);
void abort();
template <bool = true>

View file

@ -12,6 +12,7 @@
#include "Capture/rsx_capture.h"
#include "rsx_methods.h"
#include "gcm_printing.h"
#include "RSXDisAsm.h"
#include "Emu/Cell/lv2/sys_event.h"
#include "Emu/Cell/lv2/sys_time.h"
#include "Emu/Cell/Modules/cellGcmSys.h"
@ -2640,6 +2641,63 @@ namespace rsx
fifo_ctrl->sync_get();
}
std::pair<u32, u32> thread::try_get_pc_of_x_cmds_backwards(u32 count, u32 get) const
{
if (!ctrl)
{
return {0, umax};
}
if (!count)
{
return {0, get};
}
u32 true_get = ctrl->get;
u32 start = last_known_code_start;
RSXDisAsm disasm(cpu_disasm_mode::survey_cmd_size, vm::g_sudo_addr, 0, this);
std::vector<u32> pcs_of_valid_cmds;
pcs_of_valid_cmds.reserve(std::min<u32>((get - start) / 16, 0x4000)); // Rough estimation of final array size
auto probe_code_region = [&](u32 probe_start) -> std::pair<u32, u32>
{
pcs_of_valid_cmds.clear();
pcs_of_valid_cmds.push_back(probe_start);
while (pcs_of_valid_cmds.back() < get)
{
if (u32 advance = disasm.disasm(pcs_of_valid_cmds.back()))
{
pcs_of_valid_cmds.push_back(pcs_of_valid_cmds.back() + advance);
}
else
{
return {0, umax};
}
}
if (pcs_of_valid_cmds.size() == 1u || pcs_of_valid_cmds.back() != get)
{
return {0, umax};
}
u32 found_cmds_count = std::min(count, ::size32(pcs_of_valid_cmds) - 1);
return {found_cmds_count, *(pcs_of_valid_cmds.end() - 1 - found_cmds_count)};
};
auto pair = probe_code_region(start);
if (!pair.first)
{
pair = probe_code_region(true_get);
}
return pair;
}
void thread::recover_fifo(u32 line, u32 col, const char* file, const char* func)
{
const u64 current_time = rsx::uclock();

View file

@ -654,12 +654,16 @@ namespace rsx
rsx_iomap_table iomap_table;
u32 restore_point = 0;
u32 dbg_step_pc = 0;
u32 last_known_code_start = 0;
atomic_t<u32> external_interrupt_lock{ 0 };
atomic_t<bool> external_interrupt_ack{ false };
atomic_t<bool> is_inited{ false };
bool is_fifo_idle() const;
void flush_fifo();
// Returns [count of found commands, PC of their start]
std::pair<u32, u32> try_get_pc_of_x_cmds_backwards(u32 count, u32 get) const;
void recover_fifo(u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),

View file

@ -8,6 +8,7 @@
#include "Emu/CPU/CPUDisAsm.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/RSX/RSXDisAsm.h"
#include "Emu/RSX/RSXThread.h"
#include "Emu/System.h"
#include <QMouseEvent>
@ -164,6 +165,16 @@ void debugger_list::scroll(s32 steps)
steps--;
}
if (m_cpu && m_cpu->id_type() == 0x55 && steps < 0)
{
// If scrolling backwards (upwards), try to obtain the start of commands tail
if (auto [count, res] = static_cast<rsx::thread*>(m_cpu)->try_get_pc_of_x_cmds_backwards(-steps, m_pc); count == 0u - steps)
{
steps = 0;
m_pc = res;
}
}
ShowAddress(m_pc + (steps * 4), false, true);
}