mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-17 08:11:51 +00:00
SPU Local Storage capture
This commit is contained in:
parent
73f96f48ee
commit
865464f607
@ -322,18 +322,21 @@ bool spu_thread::write_reg(const u32 addr, const u32 value)
|
||||
void spu_load_exec(const spu_exec_object& elf)
|
||||
{
|
||||
auto ls0 = vm::cast(vm::falloc(RAW_SPU_BASE_ADDR, SPU_LS_SIZE, vm::spu));
|
||||
auto spu = idm::make_ptr<named_thread<spu_thread>>("TEST_SPU", ls0, nullptr, 0, "", 0);
|
||||
|
||||
spu_thread::g_raw_spu_ctr++;
|
||||
spu_thread::g_raw_spu_id[0] = spu->id;
|
||||
|
||||
for (const auto& prog : elf.progs)
|
||||
{
|
||||
if (prog.p_type == 0x1u /* LOAD */ && prog.p_memsz)
|
||||
{
|
||||
std::memcpy(spu->_ptr<void>(prog.p_vaddr), prog.bin.data(), prog.p_filesz);
|
||||
std::memcpy(vm::base(ls0 + prog.p_vaddr), prog.bin.data(), prog.p_filesz);
|
||||
}
|
||||
}
|
||||
|
||||
auto spu = idm::make_ptr<named_thread<spu_thread>>("TEST_SPU", ls0, nullptr, 0, "", 0);
|
||||
|
||||
spu_thread::g_raw_spu_id[0] = spu->id;
|
||||
|
||||
spu->status_npc = {SPU_STATUS_RUNNING, elf.header.e_entry};
|
||||
atomic_storage<u32>::release(spu->pc, elf.header.e_entry);
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/JIT.h"
|
||||
#include "Utilities/asm.h"
|
||||
#include "Utilities/date_time.h"
|
||||
#include "Utilities/sysinfo.h"
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "Emu/Memory/vm_ptr.h"
|
||||
#include "Emu/Memory/vm_reservation.h"
|
||||
|
||||
#include "Loader/ELF.h"
|
||||
#include "Emu/VFS.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/RSX/RSXThread.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
@ -3514,6 +3517,111 @@ void spu_thread::fast_call(u32 ls_addr)
|
||||
gpr[1]._u32[3] = old_stack;
|
||||
}
|
||||
|
||||
bool spu_thread::capture_local_storage() const
|
||||
{
|
||||
struct aligned_delete
|
||||
{
|
||||
void operator()(u8* ptr)
|
||||
{
|
||||
::operator delete(ptr, std::align_val_t{64});
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<u8, aligned_delete> ls_copy(static_cast<u8*>(::operator new(SPU_LS_SIZE, std::align_val_t{64})));
|
||||
const auto ls_ptr = ls_copy.get();
|
||||
std::memcpy(ls_ptr, _ptr<void>(0), SPU_LS_SIZE);
|
||||
|
||||
std::bitset<SPU_LS_SIZE / 512> found;
|
||||
alignas(64) constexpr spu_rdata_t zero{};
|
||||
|
||||
// Scan Local Storage in 512-byte blocks for non-zero blocks
|
||||
for (s32 i = 0; i < SPU_LS_SIZE;)
|
||||
{
|
||||
if (!cmp_rdata(zero, *reinterpret_cast<const spu_rdata_t*>(ls_ptr + i)))
|
||||
{
|
||||
found.set(i / 512);
|
||||
i = ::align(i + 1u, 512);
|
||||
}
|
||||
else
|
||||
{
|
||||
i += sizeof(spu_rdata_t);
|
||||
}
|
||||
}
|
||||
|
||||
spu_exec_object spu_exec;
|
||||
|
||||
// Now save the data in sequential segments
|
||||
for (s32 i = 0, found_first = -1; i <= SPU_LS_SIZE; i += 512)
|
||||
{
|
||||
if (i == SPU_LS_SIZE || !found[i / 512])
|
||||
{
|
||||
if (auto begin = std::exchange(found_first, -1); begin != -1)
|
||||
{
|
||||
// Save data as an executable segment, even the SPU stack
|
||||
auto& prog = spu_exec.progs.emplace_back(SYS_SPU_SEGMENT_TYPE_COPY, 0x7, begin + 0u, i - begin + 0u, 512
|
||||
, std::vector<uchar>(ls_ptr + begin, ls_ptr + i));
|
||||
|
||||
prog.p_paddr = prog.p_vaddr;
|
||||
spu_log.success("Segment: p_type=0x%x, p_vaddr=0x%x, p_filesz=0x%x, p_memsz=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (found_first == -1)
|
||||
{
|
||||
found_first = i;
|
||||
}
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
||||
if (get_type() == spu_type::threaded)
|
||||
{
|
||||
name = *spu_tname.load();
|
||||
|
||||
if (name.empty())
|
||||
{
|
||||
// TODO: Maybe add thread group name here
|
||||
fmt::append(name, "SPU.%u", lv2_id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::append(name, "RawSPU.%u", lv2_id);
|
||||
}
|
||||
|
||||
spu_exec.header.e_entry = pc;
|
||||
|
||||
name = vfs::escape(name, true);
|
||||
std::replace(name.begin(), name.end(), ' ', '_');
|
||||
|
||||
auto get_filename = [&]() -> std::string
|
||||
{
|
||||
return fs::get_cache_dir() + "spu_progs/" + Emu.GetTitleID() + "_" + vfs::escape(name, true) + '_' + date_time::current_time_narrow() + "_capture.elf";
|
||||
};
|
||||
|
||||
auto elf_path = get_filename();
|
||||
fs::file dump_file(elf_path, fs::create + fs::excl + fs::write);
|
||||
|
||||
if (!dump_file)
|
||||
{
|
||||
// Wait 1 second so current_time_narrow() will return a different string
|
||||
std::this_thread::sleep_for(1s);
|
||||
|
||||
if (elf_path = get_filename(); !dump_file.open(elf_path, fs::create + fs::excl + fs::write))
|
||||
{
|
||||
spu_log.error("Failed to create '%s' (error=%s)", elf_path, fs::g_tls_error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
spu_exec.save(dump_file);
|
||||
|
||||
spu_log.success("SPU Local Storage image saved to '%s'", elf_path);
|
||||
return true;
|
||||
}
|
||||
|
||||
spu_function_logger::spu_function_logger(spu_thread& spu, const char* func)
|
||||
: spu(spu)
|
||||
{
|
||||
|
@ -770,6 +770,8 @@ public:
|
||||
|
||||
void fast_call(u32 ls_addr);
|
||||
|
||||
bool capture_local_storage() const;
|
||||
|
||||
// Convert specified SPU LS address to a pointer of specified (possibly converted to BE) type
|
||||
template<typename T>
|
||||
to_be_t<T>* _ptr(u32 lsa) const
|
||||
|
@ -113,7 +113,7 @@ struct elf_prog final : elf_phdr<en_t, sz_t>
|
||||
base::p_vaddr = vaddr;
|
||||
base::p_memsz = memsz;
|
||||
base::p_align = align;
|
||||
base::p_filesz = static_cast<sz_t>(bin.size());
|
||||
base::p_filesz = static_cast<sz_t>(this->bin.size());
|
||||
base::p_paddr = 0;
|
||||
base::p_offset = -1;
|
||||
}
|
||||
|
@ -234,7 +234,9 @@ void debugger_frame::keyPressEvent(QKeyEvent* event)
|
||||
|
||||
const u32 pc = m_debugger_list->m_pc + i * 4;
|
||||
|
||||
if (QApplication::keyboardModifiers() & Qt::ControlModifier)
|
||||
const auto modifiers = QApplication::keyboardModifiers();
|
||||
|
||||
if (modifiers & Qt::ControlModifier)
|
||||
{
|
||||
switch (event->key())
|
||||
{
|
||||
@ -261,7 +263,21 @@ void debugger_frame::keyPressEvent(QKeyEvent* event)
|
||||
dlg->show();
|
||||
return;
|
||||
}
|
||||
case Qt::Key_S:
|
||||
{
|
||||
if (modifiers & Qt::AltModifier)
|
||||
{
|
||||
const auto cpu = this->cpu.lock();
|
||||
|
||||
if (!cpu || cpu->id_type() == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static_cast<spu_thread*>(cpu.get())->capture_local_storage();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case Qt::Key_F10:
|
||||
{
|
||||
DoStep(true);
|
||||
|
Loading…
Reference in New Issue
Block a user