From 69ef9c8a6a4dffa9dfe21e57461befa06b5e6b7d Mon Sep 17 00:00:00 2001 From: Eladash <18193363+elad335@users.noreply.github.com> Date: Sat, 2 Dec 2023 19:04:44 +0200 Subject: [PATCH] PPU/sys_dbg: Implement self-modifying code --- rpcs3/Emu/Cell/PPUThread.cpp | 9 +++- rpcs3/Emu/Cell/lv2/sys_dbg.cpp | 76 +++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index b364de5cac..c8284f0310 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -413,9 +413,14 @@ const auto ppu_recompiler_fallback_ghc = &ppu_recompiler_fallback; #endif // Get pointer to executable cache +static ppu_intrp_func_t* ppu_ptr(u32 addr) +{ + return reinterpret_cast(vm::g_exec_addr + u64{addr} * 2); +} + static ppu_intrp_func_t& ppu_ref(u32 addr) { - return *reinterpret_cast(vm::g_exec_addr + u64{addr} * 2); + return *ppu_ptr(addr); } // Get interpreter cache value @@ -710,7 +715,7 @@ extern void ppu_register_range(u32 addr, u32 size) addr &= -0x10000; // Register executable range at - utils::memory_commit(&ppu_ref(addr), u64{size} * 2, utils::protection::rw); + utils::memory_commit(ppu_ptr(addr), u64{size} * 2, utils::protection::rw); ensure(vm::page_protect(addr, size, 0, vm::page_executable)); if (g_cfg.core.ppu_debug) diff --git a/rpcs3/Emu/Cell/lv2/sys_dbg.cpp b/rpcs3/Emu/Cell/lv2/sys_dbg.cpp index 8375a06c9f..27fa51b148 100644 --- a/rpcs3/Emu/Cell/lv2/sys_dbg.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_dbg.cpp @@ -2,7 +2,14 @@ #include "sys_dbg.h" #include "Emu/Cell/ErrorCodes.h" + +#include "Emu/Cell/PPUInterpreter.h" #include "Emu/Cell/Modules/sys_lv2dbg.h" +#include "Emu/Memory/vm_locking.h" + +#include "util/asm.hpp" + +void ppu_register_function_at(u32 addr, u32 size, ppu_intrp_func_t ptr = nullptr); LOG_CHANNEL(sys_dbg); @@ -21,13 +28,21 @@ error_code sys_dbg_read_process_memory(s32 pid, u32 address, u32 size, vm::ptr(data.get_ptr()); + + if ((address >> 28) == 0xDu) + { + // Stack pages (4k pages is the exception here) + std::memmove(vm::base(address), data_ptr, size); + return CELL_OK; + } + + const u32 end = address + size; + + for (u32 i = address, exec_update_size = 0; i < end;) + { + const u32 op_size = std::min(utils::align(i + 1, 0x10000), end) - i; + + const bool is_exec = vm::check_addr(i, vm::page_executable | vm::page_readable); + + if (is_exec) + { + exec_update_size += op_size; + i += op_size; + } + + if (!is_exec || i >= end) + { + // Commit executable data update + // The read memory is also super ptr so memmove can work correctly on all implementations + const u32 before_addr = i - exec_update_size; + std::memmove(vm::get_super_ptr(before_addr), vm::get_super_ptr(data.addr() + (before_addr - address)), exec_update_size); + ppu_register_function_at(before_addr, exec_update_size); + exec_update_size = 0; + + if (i >= end) + { + break; + } + } + + if (!is_exec) + { + std::memmove(vm::base(i), data_ptr + (i - address), op_size); + i += op_size; + } + } return CELL_OK; }