From 90ad129b83f059816799f97c85be4069132082ef Mon Sep 17 00:00:00 2001 From: Eladash Date: Thu, 31 Aug 2023 11:35:23 +0300 Subject: [PATCH] Debugger: Fix GOTO and intruction stepping --- rpcs3/Emu/RSX/RSXDisAsm.cpp | 16 ++++++-- rpcs3/Emu/RSX/RSXThread.cpp | 70 +++++++++++++++++++++++---------- rpcs3/Emu/RSX/RSXThread.h | 2 +- rpcs3/rpcs3qt/debugger_list.cpp | 42 ++++++++++++++++++-- 4 files changed, 101 insertions(+), 29 deletions(-) diff --git a/rpcs3/Emu/RSX/RSXDisAsm.cpp b/rpcs3/Emu/RSX/RSXDisAsm.cpp index 7abcc179fe..81ba45c586 100644 --- a/rpcs3/Emu/RSX/RSXDisAsm.cpp +++ b/rpcs3/Emu/RSX/RSXDisAsm.cpp @@ -43,6 +43,11 @@ u32 RSXDisAsm::disasm(u32 pc) if (m_op & RSX_METHOD_NON_METHOD_CMD_MASK) { + if (m_mode == cpu_disasm_mode::survey_cmd_size) + { + return 4; + } + if ((m_op & RSX_METHOD_OLD_JUMP_CMD_MASK) == RSX_METHOD_OLD_JUMP_CMD) { u32 jumpAddr = m_op & RSX_METHOD_OLD_JUMP_OFFSET_MASK; @@ -86,10 +91,13 @@ u32 RSXDisAsm::disasm(u32 pc) } } - if (i == 1) - Write("nop", 0); - else - Write(fmt::format("nop x%u", i), 0); + if (m_mode != cpu_disasm_mode::survey_cmd_size) + { + if (i == 1) + Write("nop", 0); + else + Write(fmt::format("nop x%u", i), 0); + } return i * 4; } diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 8b1490b7fa..8be464eb13 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -3106,9 +3106,9 @@ namespace rsx fifo_ctrl->invalidate_cache(); } - std::pair thread::try_get_pc_of_x_cmds_backwards(u32 count, u32 get) const + std::pair thread::try_get_pc_of_x_cmds_backwards(s32 count, u32 get) const { - if (!ctrl) + if (!ctrl || state & cpu_flag::exit) { return {0, umax}; } @@ -3124,31 +3124,61 @@ namespace rsx RSXDisAsm disasm(cpu_disasm_mode::survey_cmd_size, vm::g_sudo_addr, 0, this); std::vector pcs_of_valid_cmds; - pcs_of_valid_cmds.reserve(std::min((get - start) / 16, 0x4000)); // Rough estimation of final array size + + if (get > start) + { + pcs_of_valid_cmds.reserve(std::min((get - start) / 16, 0x4000)); // Rough estimation of final array size + } auto probe_code_region = [&](u32 probe_start) -> std::pair { - 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, get}; - } - } - - if (pcs_of_valid_cmds.size() == 1u || pcs_of_valid_cmds.back() != get) + if (probe_start > get) { return {0, get}; } - u32 found_cmds_count = std::min(count, ::size32(pcs_of_valid_cmds) - 1); + pcs_of_valid_cmds.clear(); + pcs_of_valid_cmds.push_back(probe_start); + + usz index_of_get = umax; + usz until = umax; + + while (pcs_of_valid_cmds.size() < until) + { + if (u32 advance = disasm.disasm(pcs_of_valid_cmds.back())) + { + pcs_of_valid_cmds.push_back(utils::add_saturate(pcs_of_valid_cmds.back(), advance)); + } + else + { + break; + } + + if (index_of_get == umax && pcs_of_valid_cmds.back() >= get) + { + index_of_get = pcs_of_valid_cmds.size() - 1; + until = index_of_get + 1; + + if (count < 0 && pcs_of_valid_cmds.back() == get) + { + until -= count; + } + } + } + + if (index_of_get == umax || pcs_of_valid_cmds[index_of_get] != get) + { + return {0, get}; + } + + if (count < 0) + { + const u32 found_cmds_count = std::min(-count, ::size32(pcs_of_valid_cmds) - 1 - index_of_get); + + return {found_cmds_count, pcs_of_valid_cmds[index_of_get + found_cmds_count]}; + } + + const 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)}; }; diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 4f378939fd..a1be7e35ec 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -219,7 +219,7 @@ namespace rsx void flush_fifo(); // Returns [count of found commands, PC of their start] - std::pair try_get_pc_of_x_cmds_backwards(u32 count, u32 get) const; + std::pair try_get_pc_of_x_cmds_backwards(s32 count, u32 get) const; void recover_fifo(u32 line = __builtin_LINE(), u32 col = __builtin_COLUMN(), diff --git a/rpcs3/rpcs3qt/debugger_list.cpp b/rpcs3/rpcs3qt/debugger_list.cpp index 011c59146e..d7ce622abe 100644 --- a/rpcs3/rpcs3qt/debugger_list.cpp +++ b/rpcs3/rpcs3qt/debugger_list.cpp @@ -71,8 +71,12 @@ void debugger_list::UpdateCPUData(cpu_thread* cpu, CPUDisAsm* disasm) u32 debugger_list::GetStartAddress(u32 address) { const u32 steps = m_item_count / 3; + const u32 inst_count_jump_on_step = std::min(steps, 4); - u32 result = address; + const bool is_spu = m_cpu && m_cpu->id_type() == 2; + const u32 address_mask = (is_spu ? 0x3fffc : ~3); + + u32 result = address & address_mask; if (m_cpu && m_cpu->id_type() == 0x55) { @@ -83,13 +87,43 @@ u32 debugger_list::GetStartAddress(u32 address) } else { - result = address - (steps * 4); + result = (address - (steps * 4)) & address_mask; } - if (address > m_pc || m_start_addr > address) + u32 upper_bound = (m_start_addr + (steps * 4)) & address_mask; + + if (m_cpu && m_cpu->id_type() == 0x55) + { + if (auto [count, res] = static_cast(m_cpu)->try_get_pc_of_x_cmds_backwards(0 - steps, m_start_addr); count == steps) + { + upper_bound = res; + } + } + + bool goto_addr = false; + + if (upper_bound > m_start_addr) + { + goto_addr = address < m_start_addr || address >= upper_bound; + } + else + { + // Overflowing bounds case + goto_addr = address < m_start_addr && address >= upper_bound; + } + + if (goto_addr) { m_pc = address; - m_start_addr = result; + + if (address > upper_bound && address - upper_bound < inst_count_jump_on_step * 4) + { + m_start_addr = result + inst_count_jump_on_step * 4; + } + else + { + m_start_addr = result; + } } return m_start_addr;