mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 19:45:20 +00:00
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:
parent
26d8120168
commit
1d51f3af0c
10 changed files with 108 additions and 34 deletions
|
@ -10,6 +10,7 @@ enum class cpu_disasm_mode
|
|||
normal,
|
||||
compiler_elf,
|
||||
list, // RSX exclusive
|
||||
survey_cmd_size, // RSX exclusive
|
||||
};
|
||||
|
||||
class cpu_thread;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue