mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-06 18:40:36 +00:00
PPU/sys_dbg: Implement self-modifying code
This commit is contained in:
parent
8ef844ca53
commit
69ef9c8a6a
@ -413,9 +413,14 @@ const auto ppu_recompiler_fallback_ghc = &ppu_recompiler_fallback;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Get pointer to executable cache
|
// Get pointer to executable cache
|
||||||
|
static ppu_intrp_func_t* ppu_ptr(u32 addr)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<ppu_intrp_func_t*>(vm::g_exec_addr + u64{addr} * 2);
|
||||||
|
}
|
||||||
|
|
||||||
static ppu_intrp_func_t& ppu_ref(u32 addr)
|
static ppu_intrp_func_t& ppu_ref(u32 addr)
|
||||||
{
|
{
|
||||||
return *reinterpret_cast<ppu_intrp_func_t*>(vm::g_exec_addr + u64{addr} * 2);
|
return *ppu_ptr(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get interpreter cache value
|
// Get interpreter cache value
|
||||||
@ -710,7 +715,7 @@ extern void ppu_register_range(u32 addr, u32 size)
|
|||||||
addr &= -0x10000;
|
addr &= -0x10000;
|
||||||
|
|
||||||
// Register executable range at
|
// 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));
|
ensure(vm::page_protect(addr, size, 0, vm::page_executable));
|
||||||
|
|
||||||
if (g_cfg.core.ppu_debug)
|
if (g_cfg.core.ppu_debug)
|
||||||
|
@ -2,7 +2,14 @@
|
|||||||
#include "sys_dbg.h"
|
#include "sys_dbg.h"
|
||||||
|
|
||||||
#include "Emu/Cell/ErrorCodes.h"
|
#include "Emu/Cell/ErrorCodes.h"
|
||||||
|
|
||||||
|
#include "Emu/Cell/PPUInterpreter.h"
|
||||||
#include "Emu/Cell/Modules/sys_lv2dbg.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);
|
LOG_CHANNEL(sys_dbg);
|
||||||
|
|
||||||
@ -21,13 +28,21 @@ error_code sys_dbg_read_process_memory(s32 pid, u32 address, u32 size, vm::ptr<v
|
|||||||
return CELL_LV2DBG_ERROR_DEINVALIDARGUMENTS;
|
return CELL_LV2DBG_ERROR_DEINVALIDARGUMENTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vm::writer_lock lock;
|
||||||
|
|
||||||
// Check if data destination is writable
|
// Check if data destination is writable
|
||||||
if (!vm::check_addr(data.addr(), vm::page_writable, size))
|
if (!vm::check_addr(data.addr(), vm::page_writable, size))
|
||||||
{
|
{
|
||||||
return CELL_EFAULT;
|
return CELL_EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(data.get_ptr(), vm::get_super_ptr(address), size);
|
// Check if the source is readable
|
||||||
|
if (!vm::check_addr(address, vm::page_readable, size))
|
||||||
|
{
|
||||||
|
return CELL_EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memmove(data.get_ptr(), vm::base(address), size);
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
@ -53,7 +68,64 @@ error_code sys_dbg_write_process_memory(s32 pid, u32 address, u32 size, vm::cptr
|
|||||||
return CELL_EFAULT;
|
return CELL_EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(vm::get_super_ptr(address), data.get_ptr(), size);
|
// Check destination (can be read-only actually)
|
||||||
|
if (!vm::check_addr(address, vm::page_readable, size))
|
||||||
|
{
|
||||||
|
return CELL_EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm::writer_lock lock;
|
||||||
|
|
||||||
|
// Again
|
||||||
|
if (!vm::check_addr(data.addr(), vm::page_readable, size) || !vm::check_addr(address, vm::page_readable, size))
|
||||||
|
{
|
||||||
|
return CELL_EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8* data_ptr = static_cast<const u8*>(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<u32>(utils::align<u32>(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;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user