From 720bce25e880c50b371d461fb3eed5cba76faa50 Mon Sep 17 00:00:00 2001 From: Eladash Date: Thu, 19 Mar 2020 06:52:43 +0200 Subject: [PATCH 1/5] Fix a segfault in memory viewer Also a memory leak. --- rpcs3/rpcs3qt/memory_viewer_panel.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/rpcs3/rpcs3qt/memory_viewer_panel.cpp b/rpcs3/rpcs3qt/memory_viewer_panel.cpp index ff41ca24c7cb..76db2fefaf51 100644 --- a/rpcs3/rpcs3qt/memory_viewer_panel.cpp +++ b/rpcs3/rpcs3qt/memory_viewer_panel.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" -#include "Emu/Memory/vm.h" +#include "Utilities/mutex.h" +#include "Emu/Memory/vm_locking.h" #include "memory_viewer_panel.h" @@ -10,6 +11,7 @@ #include #include #include +#include constexpr auto qstr = QString::fromStdString; @@ -273,10 +275,9 @@ void memory_viewer_panel::ShowMemory() if (vm::check_addr(addr)) { - const u8 rmem = vm::read8(addr); + const u8 rmem = *vm::get_super_ptr(addr); t_mem_hex_str += qstr(fmt::format("%02x ", rmem)); - const bool isPrintable = rmem >= 32 && rmem <= 126; - t_mem_ascii_str += qstr(isPrintable ? std::string(1, rmem) : "."); + t_mem_ascii_str += qstr(std::string(1, std::isprint(rmem) ? static_cast(rmem) : '.')); } else { @@ -314,8 +315,15 @@ void memory_viewer_panel::SetPC(const uint pc) void memory_viewer_panel::ShowImage(QWidget* parent, u32 addr, int mode, u32 width, u32 height, bool flipv) { - uchar* originalBuffer = static_cast(vm::base(addr)); - uchar* convertedBuffer = static_cast(std::malloc(width * height * 4)); + std::shared_lock rlock(vm::g_mutex); + + if (!vm::check_addr(addr, width * height * 4)) + { + return; + } + + const auto originalBuffer = vm::get_super_ptr(addr); + const auto convertedBuffer = static_cast(std::malloc(width * height * 4)); switch(mode) { @@ -372,6 +380,8 @@ void memory_viewer_panel::ShowImage(QWidget* parent, u32 addr, int mode, u32 wid break; } + rlock.unlock(); + // Flip vertically if (flipv) { @@ -386,7 +396,7 @@ void memory_viewer_panel::ShowImage(QWidget* parent, u32 addr, int mode, u32 wid } } - QImage image = QImage(convertedBuffer, width, height, QImage::Format_ARGB32); + QImage image = QImage(convertedBuffer, width, height, QImage::Format_ARGB32, [](void* buffer){ std::free(buffer); }, convertedBuffer); if (image.isNull()) return; QLabel* canvas = new QLabel(); From eb73f87927d759677c725fa976f87094a86699ce Mon Sep 17 00:00:00 2001 From: Eladash Date: Thu, 19 Mar 2020 07:11:59 +0200 Subject: [PATCH 2/5] debugger: Force aligned memory view Fixes a corner case viewing unaligned memory at the end of spu memory. Also unaligned view isn't suitable for the debugger, for these purposes the memory viewer should be used instead. --- rpcs3/rpcs3qt/debugger_list.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/rpcs3qt/debugger_list.cpp b/rpcs3/rpcs3qt/debugger_list.cpp index aee3e2b50b77..a7ae9d181108 100644 --- a/rpcs3/rpcs3qt/debugger_list.cpp +++ b/rpcs3/rpcs3qt/debugger_list.cpp @@ -80,7 +80,7 @@ void debugger_list::ShowAddress(u32 addr) { const bool is_spu = cpu->id_type() != 1; const u32 cpu_offset = is_spu ? static_cast(*cpu).offset : 0; - const u32 address_limits = is_spu ? 0x3ffff : ~0; + const u32 address_limits = (is_spu ? 0x3fffc : ~3); m_pc &= address_limits; m_disasm->offset = vm::get_super_ptr(cpu_offset); for (uint i = 0, count = 4; i Date: Thu, 19 Mar 2020 07:17:23 +0200 Subject: [PATCH 3/5] disasm: Improve instructions spacing --- rpcs3/rpcs3qt/debugger_list.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rpcs3/rpcs3qt/debugger_list.cpp b/rpcs3/rpcs3qt/debugger_list.cpp index a7ae9d181108..d14a349c3985 100644 --- a/rpcs3/rpcs3qt/debugger_list.cpp +++ b/rpcs3/rpcs3qt/debugger_list.cpp @@ -73,7 +73,7 @@ void debugger_list::ShowAddress(u32 addr) { for (uint i = 0; i < m_item_count; ++i, m_pc += 4) { - item(i)->setText(qstr(fmt::format("[%08x] illegal address", m_pc))); + item(i)->setText(qstr(fmt::format(" [%08x] illegal address", m_pc))); } } else @@ -87,14 +87,14 @@ void debugger_list::ShowAddress(u32 addr) { if (!vm::check_addr(cpu_offset + m_pc, 4)) { - item(i)->setText((IsBreakpoint(m_pc) ? ">>> " : " ") + qstr(fmt::format("[%08x] illegal address", m_pc))); + item(i)->setText((IsBreakpoint(m_pc) ? ">> " : " ") + qstr(fmt::format("[%08x] illegal address", m_pc))); count = 4; continue; } count = m_disasm->disasm(m_disasm->dump_pc = m_pc); - item(i)->setText((IsBreakpoint(m_pc) ? ">>> " : " ") + qstr(m_disasm->last_opcode)); + item(i)->setText((IsBreakpoint(m_pc) ? ">> " : " ") + qstr(m_disasm->last_opcode)); if (cpu->is_paused() && m_pc == GetPc()) { From e5eafb1ff0b8877122d0f03c31663ba52504e2df Mon Sep 17 00:00:00 2001 From: Eladash Date: Thu, 19 Mar 2020 07:43:33 +0200 Subject: [PATCH 4/5] Fix memory leak in rsx debugger --- rpcs3/rpcs3qt/rsx_debugger.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/rpcs3/rpcs3qt/rsx_debugger.cpp b/rpcs3/rpcs3qt/rsx_debugger.cpp index e2c5d413ab30..a01cf440b118 100644 --- a/rpcs3/rpcs3qt/rsx_debugger.cpp +++ b/rpcs3/rpcs3qt/rsx_debugger.cpp @@ -497,7 +497,7 @@ void rsx_debugger::OnClickDrawCalls() if (width && height && !draw_call.color_buffer[i].empty()) { unsigned char* buffer = convert_to_QImage_buffer(draw_call.state.surface_color(), draw_call.color_buffer[i], width, height); - buffers[i]->showImage(QImage(buffer, static_cast(width), static_cast(height), QImage::Format_RGB32)); + buffers[i]->showImage(QImage(buffer, static_cast(width), static_cast(height), QImage::Format_RGB32, [](void* buffer){ std::free(buffer); }, buffer)); } } @@ -538,7 +538,7 @@ void rsx_debugger::OnClickDrawCalls() } } } - m_buffer_depth->showImage(QImage(buffer, static_cast(width), static_cast(height), QImage::Format_RGB32)); + m_buffer_depth->showImage(QImage(buffer, static_cast(width), static_cast(height), QImage::Format_RGB32, [](void* buffer){ std::free(buffer); }, buffer)); } } @@ -662,13 +662,14 @@ void rsx_debugger::GetBuffers() auto buffers = render->display_buffers; u32 RSXbuffer_addr = rsx::constants::local_mem_base + buffers[bufferId].offset; - if(!vm::check_addr(RSXbuffer_addr)) + const u32 width = buffers[bufferId].width; + const u32 height = buffers[bufferId].height; + + if(!vm::check_addr(RSXbuffer_addr, width * height * 4)) continue; - auto RSXbuffer = vm::get_super_ptr(RSXbuffer_addr); + const auto RSXbuffer = vm::get_super_ptr(RSXbuffer_addr); - u32 width = buffers[bufferId].width; - u32 height = buffers[bufferId].height; u8* buffer = static_cast(std::malloc(width * height * 4)); // ABGR to ARGB and flip vertically @@ -692,7 +693,7 @@ void rsx_debugger::GetBuffers() case 2: pnl = m_buffer_colorC; break; default: pnl = m_buffer_colorD; break; } - pnl->showImage(QImage(buffer, width, height, QImage::Format_RGB32)); + pnl->showImage(QImage(buffer, width, height, QImage::Format_RGB32, [](void* buffer){ std::free(buffer); }, buffer)); } // Draw Texture From 5df7bc7cb4bf40ce455f350098707b60e6f95e87 Mon Sep 17 00:00:00 2001 From: Eladash Date: Thu, 19 Mar 2020 12:29:50 +0200 Subject: [PATCH 5/5] Avoid a segfault when reading ppu stack contents in debuggers TODO: lock vm mutex. --- rpcs3/Emu/Cell/PPUThread.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index e378991d2a50..aaa701b18edc 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -472,8 +472,17 @@ std::string ppu_thread::dump() const fmt::append(ret, "FPSCR = [FL=%u | FG=%u | FE=%u | FU=%u]\n", fpscr.fl, fpscr.fg, fpscr.fe, fpscr.fu); fmt::append(ret, "\nCall stack:\n=========\n0x%08x (0x0) called\n", cia); + //std::shared_lock rlock(vm::g_mutex); // Needs optimizations + // Determine stack range u32 stack_ptr = static_cast(gpr[1]); + + if (!vm::check_addr(stack_ptr, 1, vm::page_writable)) + { + // Normally impossible unless the code does not follow ABI rules + return ret; + } + u32 stack_min = stack_ptr & ~0xfff; u32 stack_max = stack_min + 4096; @@ -487,10 +496,10 @@ std::string ppu_thread::dump() const stack_max += 4096; } - for (u64 sp = vm::read64(stack_ptr); sp >= stack_min && std::max(sp, sp + 0x200) < stack_max; sp = vm::read64(static_cast(sp))) + for (u64 sp = *vm::get_super_ptr(stack_ptr); sp >= stack_min && std::max(sp, sp + 0x200) < stack_max; sp = *vm::get_super_ptr(static_cast(sp))) { // TODO: print also function addresses - fmt::append(ret, "> from 0x%08llx (0x0)\n", vm::read64(static_cast(sp + 16))); + fmt::append(ret, "> from 0x%08llx (0x0)\n", *vm::get_super_ptr(static_cast(sp + 16))); } return ret;