mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-28 13:28:01 +03:00
Add memory breakpoints
Some checks are pending
Some checks are pending
RPCS3 needs to be compiled with -DHAS_MEMORY_BREAKPOINTS=ON for it to be available
This commit is contained in:
parent
cb659474d9
commit
66952fe301
17 changed files with 416 additions and 74 deletions
|
@ -30,6 +30,7 @@ option(USE_SYSTEM_FFMPEG "Prefer system ffmpeg instead of the prebuild one" OFF)
|
||||||
option(USE_SYSTEM_OPENAL "Prefer system OpenAL instead of the prebuild one" ON)
|
option(USE_SYSTEM_OPENAL "Prefer system OpenAL instead of the prebuild one" ON)
|
||||||
option(USE_SYSTEM_CURL "Prefer system Curl instead of the prebuild one" ON)
|
option(USE_SYSTEM_CURL "Prefer system Curl instead of the prebuild one" ON)
|
||||||
option(USE_SYSTEM_OPENCV "Prefer system OpenCV instead of the builtin one" ON)
|
option(USE_SYSTEM_OPENCV "Prefer system OpenCV instead of the builtin one" ON)
|
||||||
|
option(HAS_MEMORY_BREAKPOINTS "Add support for memory breakpoints to the interpreter" OFF)
|
||||||
option(USE_LTO "Use LTO for building" ON)
|
option(USE_LTO "Use LTO for building" ON)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/buildfiles/cmake")
|
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/buildfiles/cmake")
|
||||||
|
|
|
@ -28,6 +28,10 @@ if(USE_ASAN)
|
||||||
set_source_files_properties(../../Utilities/Thread.cpp PROPERTIES COMPILE_DEFINITIONS USE_ASAN)
|
set_source_files_properties(../../Utilities/Thread.cpp PROPERTIES COMPILE_DEFINITIONS USE_ASAN)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(HAS_MEMORY_BREAKPOINTS)
|
||||||
|
target_compile_definitions(rpcs3_emu PRIVATE RPCS3_HAS_MEMORY_BREAKPOINTS)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_libraries(rpcs3_emu
|
target_link_libraries(rpcs3_emu
|
||||||
PRIVATE
|
PRIVATE
|
||||||
3rdparty::zlib 3rdparty::yaml-cpp 3rdparty::zstd
|
3rdparty::zlib 3rdparty::yaml-cpp 3rdparty::zstd
|
||||||
|
|
|
@ -26,6 +26,29 @@
|
||||||
#pragma GCC diagnostic ignored "-Wuninitialized"
|
#pragma GCC diagnostic ignored "-Wuninitialized"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
void ppubreak(ppu_thread& ppu)
|
||||||
|
{
|
||||||
|
if (!g_breakpoint_handler.IsBreakOnBPM())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!ppu.state.test_and_set(cpu_flag::dbg_pause))
|
||||||
|
{
|
||||||
|
ppu.check_state();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PPU_WRITE_8(addr, value) vm::write8(addr, value, &ppu);
|
||||||
|
#define PPU_WRITE_16(addr, value) vm::write16(addr, value, &ppu);
|
||||||
|
#define PPU_WRITE_32(addr, value) vm::write32(addr, value, &ppu);
|
||||||
|
#define PPU_WRITE_64(addr, value) vm::write64(addr, value, &ppu);
|
||||||
|
#else
|
||||||
|
#define PPU_WRITE_8(addr, value) vm::write8(addr, value);
|
||||||
|
#define PPU_WRITE_16(addr, value) vm::write16(addr, value);
|
||||||
|
#define PPU_WRITE_32(addr, value) vm::write32(addr, value);
|
||||||
|
#define PPU_WRITE_64(addr, value) vm::write64(addr, value);
|
||||||
|
#endif
|
||||||
|
|
||||||
extern bool is_debugger_present();
|
extern bool is_debugger_present();
|
||||||
|
|
||||||
extern const ppu_decoder<ppu_itype> g_ppu_itype;
|
extern const ppu_decoder<ppu_itype> g_ppu_itype;
|
||||||
|
@ -428,6 +451,14 @@ auto ppu_feed_data(ppu_thread& ppu, u64 addr)
|
||||||
|
|
||||||
auto value = vm::_ref<T>(vm::cast(addr));
|
auto value = vm::_ref<T>(vm::cast(addr));
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
if (g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_read))
|
||||||
|
{
|
||||||
|
debugbp_log.success("BPMR: breakpoint reading 0x%x at 0x%x", value, addr);
|
||||||
|
ppubreak(ppu);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if constexpr (!((Flags == use_feed_data) || ...))
|
if constexpr (!((Flags == use_feed_data) || ...))
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
|
@ -4274,7 +4305,7 @@ auto STVEBX()
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
||||||
const u8 eb = addr & 0xf;
|
const u8 eb = addr & 0xf;
|
||||||
vm::write8(vm::cast(addr), ppu.vr[op.vs]._u8[15 - eb]);
|
PPU_WRITE_8(vm::cast(addr), ppu.vr[op.vs]._u8[15 - eb]);
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
}
|
}
|
||||||
|
@ -4381,7 +4412,7 @@ auto STDX()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
||||||
vm::write64(vm::cast(addr), ppu.gpr[op.rs]);
|
PPU_WRITE_64(vm::cast(addr), ppu.gpr[op.rs]);
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
}
|
}
|
||||||
|
@ -4407,7 +4438,7 @@ auto STWX()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
||||||
vm::write32(vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs]));
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs]));
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
}
|
}
|
||||||
|
@ -4421,7 +4452,7 @@ auto STVEHX()
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~1ULL;
|
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~1ULL;
|
||||||
const u8 eb = (addr & 0xf) >> 1;
|
const u8 eb = (addr & 0xf) >> 1;
|
||||||
vm::write16(vm::cast(addr), ppu.vr[op.vs]._u16[7 - eb]);
|
PPU_WRITE_16(vm::cast(addr), ppu.vr[op.vs]._u16[7 - eb]);
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
}
|
}
|
||||||
|
@ -4434,7 +4465,7 @@ auto STDUX()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
||||||
vm::write64(vm::cast(addr), ppu.gpr[op.rs]);
|
PPU_WRITE_64(vm::cast(addr), ppu.gpr[op.rs]);
|
||||||
ppu.gpr[op.ra] = addr;
|
ppu.gpr[op.ra] = addr;
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
|
@ -4448,7 +4479,7 @@ auto STWUX()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
||||||
vm::write32(vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs]));
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs]));
|
||||||
ppu.gpr[op.ra] = addr;
|
ppu.gpr[op.ra] = addr;
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
|
@ -4463,7 +4494,7 @@ auto STVEWX()
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~3ULL;
|
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~3ULL;
|
||||||
const u8 eb = (addr & 0xf) >> 2;
|
const u8 eb = (addr & 0xf) >> 2;
|
||||||
vm::write32(vm::cast(addr), ppu.vr[op.vs]._u32[3 - eb]);
|
PPU_WRITE_32(vm::cast(addr), ppu.vr[op.vs]._u32[3 - eb]);
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
}
|
}
|
||||||
|
@ -4527,7 +4558,7 @@ auto STBX()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
||||||
vm::write8(vm::cast(addr), static_cast<u8>(ppu.gpr[op.rs]));
|
PPU_WRITE_8(vm::cast(addr), static_cast<u8>(ppu.gpr[op.rs]));
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
}
|
}
|
||||||
|
@ -4639,7 +4670,7 @@ auto STBUX()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
||||||
vm::write8(vm::cast(addr), static_cast<u8>(ppu.gpr[op.rs]));
|
PPU_WRITE_8(vm::cast(addr), static_cast<u8>(ppu.gpr[op.rs]));
|
||||||
ppu.gpr[op.ra] = addr;
|
ppu.gpr[op.ra] = addr;
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
|
@ -4883,7 +4914,7 @@ auto STHX()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
||||||
vm::write16(vm::cast(addr), static_cast<u16>(ppu.gpr[op.rs]));
|
PPU_WRITE_16(vm::cast(addr), static_cast<u16>(ppu.gpr[op.rs]));
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
}
|
}
|
||||||
|
@ -4922,7 +4953,7 @@ auto STHUX()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
||||||
vm::write16(vm::cast(addr), static_cast<u16>(ppu.gpr[op.rs]));
|
PPU_WRITE_16(vm::cast(addr), static_cast<u16>(ppu.gpr[op.rs]));
|
||||||
ppu.gpr[op.ra] = addr;
|
ppu.gpr[op.ra] = addr;
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
|
@ -5346,7 +5377,7 @@ auto STSWX()
|
||||||
u32 count = ppu.xer.cnt & 0x7F;
|
u32 count = ppu.xer.cnt & 0x7F;
|
||||||
for (; count >= 4; count -= 4, addr += 4, op.rs = (op.rs + 1) & 31)
|
for (; count >= 4; count -= 4, addr += 4, op.rs = (op.rs + 1) & 31)
|
||||||
{
|
{
|
||||||
vm::write32(vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs]));
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs]));
|
||||||
}
|
}
|
||||||
if (count)
|
if (count)
|
||||||
{
|
{
|
||||||
|
@ -5354,7 +5385,7 @@ auto STSWX()
|
||||||
for (u32 byte = 0; byte < count; byte++)
|
for (u32 byte = 0; byte < count; byte++)
|
||||||
{
|
{
|
||||||
u8 byte_value = static_cast<u8>(value >> ((3 ^ byte) * 8));
|
u8 byte_value = static_cast<u8>(value >> ((3 ^ byte) * 8));
|
||||||
vm::write8(vm::cast(addr + byte), byte_value);
|
PPU_WRITE_8(vm::cast(addr + byte), byte_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -5434,7 +5465,7 @@ auto STSWI()
|
||||||
{
|
{
|
||||||
if (N > 3)
|
if (N > 3)
|
||||||
{
|
{
|
||||||
vm::write32(vm::cast(addr), static_cast<u32>(ppu.gpr[reg]));
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(ppu.gpr[reg]));
|
||||||
addr += 4;
|
addr += 4;
|
||||||
N -= 4;
|
N -= 4;
|
||||||
}
|
}
|
||||||
|
@ -5444,7 +5475,7 @@ auto STSWI()
|
||||||
while (N > 0)
|
while (N > 0)
|
||||||
{
|
{
|
||||||
N = N - 1;
|
N = N - 1;
|
||||||
vm::write8(vm::cast(addr), (0xFF000000 & buf) >> 24);
|
PPU_WRITE_8(vm::cast(addr), (0xFF000000 & buf) >> 24);
|
||||||
buf <<= 8;
|
buf <<= 8;
|
||||||
addr++;
|
addr++;
|
||||||
}
|
}
|
||||||
|
@ -5678,7 +5709,7 @@ auto STFIWX()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
||||||
vm::write32(vm::cast(addr), static_cast<u32>(std::bit_cast<u64>(ppu.fpr[op.frs])));
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(std::bit_cast<u64>(ppu.fpr[op.frs])));
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
}
|
}
|
||||||
|
@ -5793,7 +5824,7 @@ auto STW()
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
||||||
const u32 value = static_cast<u32>(ppu.gpr[op.rs]);
|
const u32 value = static_cast<u32>(ppu.gpr[op.rs]);
|
||||||
vm::write32(vm::cast(addr), value);
|
PPU_WRITE_32(vm::cast(addr), value);
|
||||||
|
|
||||||
//Insomniac engine v3 & v4 (newer R&C, Fuse, Resitance 3)
|
//Insomniac engine v3 & v4 (newer R&C, Fuse, Resitance 3)
|
||||||
if (value == 0xAAAAAAAA) [[unlikely]]
|
if (value == 0xAAAAAAAA) [[unlikely]]
|
||||||
|
@ -5813,7 +5844,7 @@ auto STWU()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
||||||
vm::write32(vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs]));
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs]));
|
||||||
ppu.gpr[op.ra] = addr;
|
ppu.gpr[op.ra] = addr;
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
|
@ -5827,7 +5858,7 @@ auto STB()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
||||||
vm::write8(vm::cast(addr), static_cast<u8>(ppu.gpr[op.rs]));
|
PPU_WRITE_8(vm::cast(addr), static_cast<u8>(ppu.gpr[op.rs]));
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
}
|
}
|
||||||
|
@ -5840,7 +5871,7 @@ auto STBU()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
||||||
vm::write8(vm::cast(addr), static_cast<u8>(ppu.gpr[op.rs]));
|
PPU_WRITE_8(vm::cast(addr), static_cast<u8>(ppu.gpr[op.rs]));
|
||||||
ppu.gpr[op.ra] = addr;
|
ppu.gpr[op.ra] = addr;
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
|
@ -5908,7 +5939,7 @@ auto STH()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
||||||
vm::write16(vm::cast(addr), static_cast<u16>(ppu.gpr[op.rs]));
|
PPU_WRITE_16(vm::cast(addr), static_cast<u16>(ppu.gpr[op.rs]));
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
}
|
}
|
||||||
|
@ -5921,7 +5952,7 @@ auto STHU()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
||||||
vm::write16(vm::cast(addr), static_cast<u16>(ppu.gpr[op.rs]));
|
PPU_WRITE_16(vm::cast(addr), static_cast<u16>(ppu.gpr[op.rs]));
|
||||||
ppu.gpr[op.ra] = addr;
|
ppu.gpr[op.ra] = addr;
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
|
@ -5953,7 +5984,7 @@ auto STMW()
|
||||||
u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
||||||
for (u32 i = op.rs; i<32; ++i, addr += 4)
|
for (u32 i = op.rs; i<32; ++i, addr += 4)
|
||||||
{
|
{
|
||||||
vm::write32(vm::cast(addr), static_cast<u32>(ppu.gpr[i]));
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(ppu.gpr[i]));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
|
@ -6115,7 +6146,7 @@ auto STD()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.gpr[op.ra] : 0);
|
const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.gpr[op.ra] : 0);
|
||||||
vm::write64(vm::cast(addr), ppu.gpr[op.rs]);
|
PPU_WRITE_64(vm::cast(addr), ppu.gpr[op.rs]);
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
}
|
}
|
||||||
|
@ -6128,7 +6159,7 @@ auto STDU()
|
||||||
|
|
||||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||||
const u64 addr = ppu.gpr[op.ra] + (op.simm16 & ~3);
|
const u64 addr = ppu.gpr[op.ra] + (op.simm16 & ~3);
|
||||||
vm::write64(vm::cast(addr), ppu.gpr[op.rs]);
|
PPU_WRITE_64(vm::cast(addr), ppu.gpr[op.rs]);
|
||||||
ppu.gpr[op.ra] = addr;
|
ppu.gpr[op.ra] = addr;
|
||||||
};
|
};
|
||||||
RETURN_(ppu, op);
|
RETURN_(ppu, op);
|
||||||
|
|
|
@ -8,6 +8,17 @@
|
||||||
|
|
||||||
#include "util/to_endian.hpp"
|
#include "util/to_endian.hpp"
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
#include "rpcs3qt/breakpoint_handler.h"
|
||||||
|
#include "util/logs.hpp"
|
||||||
|
|
||||||
|
LOG_CHANNEL(debugbp_log, "DebugBP");
|
||||||
|
|
||||||
|
class ppu_thread;
|
||||||
|
|
||||||
|
void ppubreak(ppu_thread& ppu);
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace utils
|
namespace utils
|
||||||
{
|
{
|
||||||
class shm;
|
class shm;
|
||||||
|
@ -242,9 +253,21 @@ namespace vm
|
||||||
return g_base_addr[addr];
|
return g_base_addr[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
inline void write8(u32 addr, u8 value, ppu_thread* ppu = nullptr)
|
||||||
|
#else
|
||||||
inline void write8(u32 addr, u8 value)
|
inline void write8(u32 addr, u8 value)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
g_base_addr[addr] = value;
|
g_base_addr[addr] = value;
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
if (ppu && g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_write))
|
||||||
|
{
|
||||||
|
debugbp_log.success("BPMW: breakpoint writing(8) 0x%x at 0x%x", value, addr);
|
||||||
|
ppubreak(*ppu);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read or write virtual memory in a safe manner, returns false on failure
|
// Read or write virtual memory in a safe manner, returns false on failure
|
||||||
|
@ -276,9 +299,21 @@ namespace vm
|
||||||
return _ref<u16>(addr);
|
return _ref<u16>(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
inline void write16(u32 addr, be_t<u16> value, ppu_thread* ppu = nullptr)
|
||||||
|
#else
|
||||||
inline void write16(u32 addr, be_t<u16> value)
|
inline void write16(u32 addr, be_t<u16> value)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
_ref<u16>(addr) = value;
|
_ref<u16>(addr) = value;
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
if (ppu && g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_write))
|
||||||
|
{
|
||||||
|
debugbp_log.success("BPMW: breakpoint writing(16) 0x%x at 0x%x", value, addr);
|
||||||
|
ppubreak(*ppu);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const be_t<u32>& read32(u32 addr)
|
inline const be_t<u32>& read32(u32 addr)
|
||||||
|
@ -286,9 +321,21 @@ namespace vm
|
||||||
return _ref<u32>(addr);
|
return _ref<u32>(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
inline void write32(u32 addr, be_t<u32> value, ppu_thread* ppu = nullptr)
|
||||||
|
#else
|
||||||
inline void write32(u32 addr, be_t<u32> value)
|
inline void write32(u32 addr, be_t<u32> value)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
_ref<u32>(addr) = value;
|
_ref<u32>(addr) = value;
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
if (ppu && g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_write))
|
||||||
|
{
|
||||||
|
debugbp_log.success("BPMW: breakpoint writing(32) 0x%x at 0x%x", value, addr);
|
||||||
|
ppubreak(*ppu);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const be_t<u64>& read64(u32 addr)
|
inline const be_t<u64>& read64(u32 addr)
|
||||||
|
@ -296,9 +343,21 @@ namespace vm
|
||||||
return _ref<u64>(addr);
|
return _ref<u64>(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
inline void write64(u32 addr, be_t<u64> value, ppu_thread* ppu = nullptr)
|
||||||
|
#else
|
||||||
inline void write64(u32 addr, be_t<u64> value)
|
inline void write64(u32 addr, be_t<u64> value)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
_ref<u64>(addr) = value;
|
_ref<u64>(addr) = value;
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
if (ppu && g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_write))
|
||||||
|
{
|
||||||
|
debugbp_log.success("BPMW: breakpoint writing(64) 0x%x at 0x%x", value, addr);
|
||||||
|
ppubreak(*ppu);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
|
@ -232,6 +232,9 @@
|
||||||
<ClCompile Include="QTGeneratedFiles\Debug\moc_custom_dialog.cpp">
|
<ClCompile Include="QTGeneratedFiles\Debug\moc_custom_dialog.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="QTGeneratedFiles\Debug\moc_debugger_add_bp_window.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="QTGeneratedFiles\Debug\moc_debugger_frame.cpp">
|
<ClCompile Include="QTGeneratedFiles\Debug\moc_debugger_frame.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -511,6 +514,9 @@
|
||||||
<ClCompile Include="QTGeneratedFiles\Release\moc_custom_dialog.cpp">
|
<ClCompile Include="QTGeneratedFiles\Release\moc_custom_dialog.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="QTGeneratedFiles\Release\moc_debugger_add_bp_window.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="QTGeneratedFiles\Release\moc_debugger_frame.cpp">
|
<ClCompile Include="QTGeneratedFiles\Release\moc_debugger_frame.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -846,6 +852,7 @@
|
||||||
<ClCompile Include="headless_application.cpp" />
|
<ClCompile Include="headless_application.cpp" />
|
||||||
<ClCompile Include="rpcs3qt\auto_pause_settings_dialog.cpp" />
|
<ClCompile Include="rpcs3qt\auto_pause_settings_dialog.cpp" />
|
||||||
<ClCompile Include="rpcs3qt\cg_disasm_window.cpp" />
|
<ClCompile Include="rpcs3qt\cg_disasm_window.cpp" />
|
||||||
|
<ClCompile Include="rpcs3qt\debugger_add_bp_window.cpp" />
|
||||||
<ClCompile Include="rpcs3qt\debugger_frame.cpp" />
|
<ClCompile Include="rpcs3qt\debugger_frame.cpp" />
|
||||||
<ClCompile Include="rpcs3qt\emu_settings.cpp" />
|
<ClCompile Include="rpcs3qt\emu_settings.cpp" />
|
||||||
<ClCompile Include="rpcs3qt\game_list_frame.cpp" />
|
<ClCompile Include="rpcs3qt\game_list_frame.cpp" />
|
||||||
|
@ -961,6 +968,16 @@
|
||||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="rpcs3qt\debugger_add_bp_window.h">
|
||||||
|
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing debugger_add_bp_window.h...</Message>
|
||||||
|
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||||
|
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"</Command>
|
||||||
|
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing debugger_add_bp_window.h...</Message>
|
||||||
|
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||||
|
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"</Command>
|
||||||
|
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||||
|
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||||
|
</CustomBuild>
|
||||||
<CustomBuild Include="rpcs3qt\debugger_frame.h">
|
<CustomBuild Include="rpcs3qt\debugger_frame.h">
|
||||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing debugger_frame.h...</Message>
|
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing debugger_frame.h...</Message>
|
||||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||||
|
|
|
@ -213,6 +213,12 @@
|
||||||
<ClCompile Include="QTGeneratedFiles\Release\moc_cg_disasm_window.cpp">
|
<ClCompile Include="QTGeneratedFiles\Release\moc_cg_disasm_window.cpp">
|
||||||
<Filter>Generated Files\Release</Filter>
|
<Filter>Generated Files\Release</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="QTGeneratedFiles\Debug\moc_debugger_add_bp_window.cpp">
|
||||||
|
<Filter>Generated Files\Debug</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="QTGeneratedFiles\Release\moc_debugger_add_bp_window.cpp">
|
||||||
|
<Filter>Generated Files\Release</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="QTGeneratedFiles\Debug\moc_debugger_frame.cpp">
|
<ClCompile Include="QTGeneratedFiles\Debug\moc_debugger_frame.cpp">
|
||||||
<Filter>Generated Files\Debug</Filter>
|
<Filter>Generated Files\Debug</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -396,6 +402,9 @@
|
||||||
<ClCompile Include="rpcs3qt\cg_disasm_window.cpp">
|
<ClCompile Include="rpcs3qt\cg_disasm_window.cpp">
|
||||||
<Filter>Gui\dev tools</Filter>
|
<Filter>Gui\dev tools</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="rpcs3qt\debugger_add_bp_window.cpp">
|
||||||
|
<Filter>Gui\debugger</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="rpcs3qt\debugger_frame.cpp">
|
<ClCompile Include="rpcs3qt\debugger_frame.cpp">
|
||||||
<Filter>Gui\debugger</Filter>
|
<Filter>Gui\debugger</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
@ -13,6 +13,7 @@ add_library(rpcs3_ui STATIC
|
||||||
curl_handle.cpp
|
curl_handle.cpp
|
||||||
custom_dialog.cpp
|
custom_dialog.cpp
|
||||||
custom_table_widget_item.cpp
|
custom_table_widget_item.cpp
|
||||||
|
debugger_add_bp_window.cpp
|
||||||
debugger_frame.cpp
|
debugger_frame.cpp
|
||||||
debugger_list.cpp
|
debugger_list.cpp
|
||||||
downloader.cpp
|
downloader.cpp
|
||||||
|
@ -129,6 +130,10 @@ add_library(rpcs3_ui STATIC
|
||||||
"../resources.qrc"
|
"../resources.qrc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(HAS_MEMORY_BREAKPOINTS)
|
||||||
|
target_compile_definitions(rpcs3_ui PRIVATE RPCS3_HAS_MEMORY_BREAKPOINTS)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_sources(rpcs3_ui PUBLIC "../windows.qrc")
|
target_sources(rpcs3_ui PUBLIC "../windows.qrc")
|
||||||
target_compile_definitions(rpcs3_ui PRIVATE UNICODE _UNICODE)
|
target_compile_definitions(rpcs3_ui PRIVATE UNICODE _UNICODE)
|
||||||
|
|
|
@ -2,29 +2,53 @@
|
||||||
|
|
||||||
extern bool ppu_breakpoint(u32 loc, bool is_adding);
|
extern bool ppu_breakpoint(u32 loc, bool is_adding);
|
||||||
|
|
||||||
bool breakpoint_handler::HasBreakpoint(u32 loc) const
|
bool breakpoint_handler::IsBreakOnBPM() const
|
||||||
{
|
{
|
||||||
return m_breakpoints.contains(loc);
|
return m_break_on_bpm;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool breakpoint_handler::AddBreakpoint(u32 loc)
|
void breakpoint_handler::SetBreakOnBPM(bool break_on_bpm)
|
||||||
{
|
{
|
||||||
if (!ppu_breakpoint(loc, true))
|
m_break_on_bpm = break_on_bpm;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool breakpoint_handler::HasBreakpoint(u32 loc, bs_t<breakpoint_types> type)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(mutex_breakpoints);
|
||||||
|
|
||||||
|
return m_breakpoints.contains(loc) && ((m_breakpoints.at(loc) & type) == type);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool breakpoint_handler::AddBreakpoint(u32 loc, bs_t<breakpoint_types> type)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(mutex_breakpoints);
|
||||||
|
|
||||||
|
if ((type & breakpoint_types::bp_exec) && !ppu_breakpoint(loc, true))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure(m_breakpoints.insert(loc).second);
|
return m_breakpoints.insert({loc, type}).second;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool breakpoint_handler::RemoveBreakpoint(u32 loc)
|
bool breakpoint_handler::RemoveBreakpoint(u32 loc)
|
||||||
{
|
{
|
||||||
|
std::lock_guard lock(mutex_breakpoints);
|
||||||
|
|
||||||
|
bs_t<breakpoint_types> bp_type{};
|
||||||
|
if (m_breakpoints.contains(loc))
|
||||||
|
{
|
||||||
|
bp_type = m_breakpoints.at(loc);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_breakpoints.erase(loc) == 0)
|
if (m_breakpoints.erase(loc) == 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bp_type & breakpoint_types::bp_exec)
|
||||||
|
{
|
||||||
ensure(ppu_breakpoint(loc, false));
|
ensure(ppu_breakpoint(loc, false));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "util/types.hpp"
|
#include "util/types.hpp"
|
||||||
#include <set>
|
#include "Utilities/bit_set.h"
|
||||||
|
#include <map>
|
||||||
|
#include "Utilities/mutex.h"
|
||||||
|
|
||||||
enum class breakpoint_types
|
enum class breakpoint_types
|
||||||
{
|
{
|
||||||
bp_read = 0x1,
|
bp_read = 0x1,
|
||||||
bp_write = 0x2,
|
bp_write = 0x2,
|
||||||
bp_exec = 0x4,
|
bp_exec = 0x4,
|
||||||
|
__bitset_enum_max
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -20,16 +23,19 @@ public:
|
||||||
breakpoint_handler() = default;
|
breakpoint_handler() = default;
|
||||||
~breakpoint_handler() = default;
|
~breakpoint_handler() = default;
|
||||||
|
|
||||||
|
bool IsBreakOnBPM() const;
|
||||||
|
void SetBreakOnBPM(bool break_on_bpm);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true iff breakpoint exists at loc.
|
* Returns true iff breakpoint exists at loc.
|
||||||
* TODO: Add arg for flags, gameid, and maybe even thread if it should be thread local breakpoint.... breakpoint struct is probably what'll happen
|
* TODO: Add arg for flags, gameid, and maybe even thread if it should be thread local breakpoint.... breakpoint struct is probably what'll happen
|
||||||
*/
|
*/
|
||||||
bool HasBreakpoint(u32 loc) const;
|
bool HasBreakpoint(u32 loc, bs_t<breakpoint_types> type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if added successfully. TODO: flags
|
* Returns true if added successfully. TODO: flags
|
||||||
*/
|
*/
|
||||||
bool AddBreakpoint(u32 loc);
|
bool AddBreakpoint(u32 loc, bs_t<breakpoint_types> type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if removed breakpoint at loc successfully.
|
* Returns true if removed breakpoint at loc successfully.
|
||||||
|
@ -39,5 +45,9 @@ public:
|
||||||
private:
|
private:
|
||||||
// TODO : generalize to hold multiple games and handle flags.Probably do : std::map<std::string (gameid), std::set<breakpoint>>.
|
// TODO : generalize to hold multiple games and handle flags.Probably do : std::map<std::string (gameid), std::set<breakpoint>>.
|
||||||
// Although, externally, they'll only be accessed by loc (I think) so a map of maps may also do?
|
// Although, externally, they'll only be accessed by loc (I think) so a map of maps may also do?
|
||||||
std::set<u32> m_breakpoints; //! Holds all breakpoints.
|
shared_mutex mutex_breakpoints;
|
||||||
|
std::map<u32, bs_t<breakpoint_types>> m_breakpoints; //! Holds all breakpoints.
|
||||||
|
bool m_break_on_bpm = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern breakpoint_handler g_breakpoint_handler;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "Emu/CPU/CPUDisAsm.h"
|
#include "Emu/CPU/CPUDisAsm.h"
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "Emu/Cell/SPUThread.h"
|
#include "Emu/Cell/SPUThread.h"
|
||||||
|
#include "rpcs3qt/debugger_add_bp_window.h"
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
@ -72,19 +73,35 @@ void breakpoint_list::RemoveBreakpoint(u32 addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool breakpoint_list::AddBreakpoint(u32 pc)
|
bool breakpoint_list::AddBreakpoint(u32 pc, bs_t<breakpoint_types> type)
|
||||||
{
|
{
|
||||||
if (!m_ppu_breakpoint_handler->AddBreakpoint(pc))
|
if (!m_ppu_breakpoint_handler->AddBreakpoint(pc, type))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_disasm->disasm(pc);
|
QString breakpoint_item_text;
|
||||||
|
|
||||||
QString text = QString::fromStdString(m_disasm->last_opcode);
|
if (type == breakpoint_types::bp_exec)
|
||||||
text.remove(10, 13);
|
{
|
||||||
|
m_disasm->disasm(m_disasm->dump_pc = pc);
|
||||||
|
breakpoint_item_text = QString::fromStdString(m_disasm->last_opcode);
|
||||||
|
breakpoint_item_text.remove(10, 13);
|
||||||
|
}
|
||||||
|
else if (type == breakpoint_types::bp_read)
|
||||||
|
{
|
||||||
|
breakpoint_item_text = QString("BPMR: 0x%1").arg(pc, 8, 16, QChar('0'));
|
||||||
|
}
|
||||||
|
else if (type == breakpoint_types::bp_write)
|
||||||
|
{
|
||||||
|
breakpoint_item_text = QString("BPMW: 0x%1").arg(pc, 8, 16, QChar('0'));
|
||||||
|
}
|
||||||
|
else if (type == (breakpoint_types::bp_read + breakpoint_types::bp_write))
|
||||||
|
{
|
||||||
|
breakpoint_item_text = QString("BPMRW: 0x%1").arg(pc, 8, 16, QChar('0'));
|
||||||
|
}
|
||||||
|
|
||||||
QListWidgetItem* breakpoint_item = new QListWidgetItem(text);
|
QListWidgetItem* breakpoint_item = new QListWidgetItem(breakpoint_item_text);
|
||||||
breakpoint_item->setForeground(m_text_color_bp);
|
breakpoint_item->setForeground(m_text_color_bp);
|
||||||
breakpoint_item->setBackground(m_color_bp);
|
breakpoint_item->setBackground(m_color_bp);
|
||||||
breakpoint_item->setData(Qt::UserRole, pc);
|
breakpoint_item->setData(Qt::UserRole, pc);
|
||||||
|
@ -168,7 +185,7 @@ void breakpoint_list::HandleBreakpointRequest(u32 loc, bool only_add)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ppu_breakpoint_handler->HasBreakpoint(loc))
|
if (m_ppu_breakpoint_handler->HasBreakpoint(loc, breakpoint_types::bp_exec))
|
||||||
{
|
{
|
||||||
if (!only_add)
|
if (!only_add)
|
||||||
{
|
{
|
||||||
|
@ -177,7 +194,7 @@ void breakpoint_list::HandleBreakpointRequest(u32 loc, bool only_add)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!AddBreakpoint(loc))
|
if (!AddBreakpoint(loc, breakpoint_types::bp_exec))
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Unknown error while setting breakpoint!"), tr("Failed to set breakpoints."));
|
QMessageBox::warning(this, tr("Unknown error while setting breakpoint!"), tr("Failed to set breakpoints."));
|
||||||
return;
|
return;
|
||||||
|
@ -196,11 +213,6 @@ void breakpoint_list::OnBreakpointListDoubleClicked()
|
||||||
|
|
||||||
void breakpoint_list::OnBreakpointListRightClicked(const QPoint& pos)
|
void breakpoint_list::OnBreakpointListRightClicked(const QPoint& pos)
|
||||||
{
|
{
|
||||||
if (!itemAt(pos))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_context_menu = new QMenu();
|
m_context_menu = new QMenu();
|
||||||
|
|
||||||
if (selectedItems().count() == 1)
|
if (selectedItems().count() == 1)
|
||||||
|
@ -215,7 +227,28 @@ void breakpoint_list::OnBreakpointListRightClicked(const QPoint &pos)
|
||||||
m_context_menu->addSeparator();
|
m_context_menu->addSeparator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selectedItems().count() >= 1)
|
||||||
|
{
|
||||||
m_context_menu->addAction(m_delete_action);
|
m_context_menu->addAction(m_delete_action);
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction* m_addbp = new QAction(tr("Add Breakpoint"), this);
|
||||||
|
connect(m_addbp, &QAction::triggered, this, [this]
|
||||||
|
{
|
||||||
|
debugger_add_bp_window dlg(this, this);
|
||||||
|
dlg.exec();
|
||||||
|
});
|
||||||
|
m_context_menu->addAction(m_addbp);
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
QAction* m_tglbpmbreak = new QAction(m_ppu_breakpoint_handler->IsBreakOnBPM() ? tr("Disable BPM") : tr("Enable BPM"), this);
|
||||||
|
connect(m_tglbpmbreak, &QAction::triggered, [this]
|
||||||
|
{
|
||||||
|
m_ppu_breakpoint_handler->SetBreakOnBPM(!m_ppu_breakpoint_handler->IsBreakOnBPM());
|
||||||
|
});
|
||||||
|
m_context_menu->addAction(m_tglbpmbreak);
|
||||||
|
#endif
|
||||||
|
|
||||||
m_context_menu->exec(viewport()->mapToGlobal(pos));
|
m_context_menu->exec(viewport()->mapToGlobal(pos));
|
||||||
m_context_menu->deleteLater();
|
m_context_menu->deleteLater();
|
||||||
m_context_menu = nullptr;
|
m_context_menu = nullptr;
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
|
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
|
|
||||||
|
#include "breakpoint_handler.h"
|
||||||
|
|
||||||
class CPUDisAsm;
|
class CPUDisAsm;
|
||||||
class cpu_thread;
|
class cpu_thread;
|
||||||
class breakpoint_handler;
|
|
||||||
|
|
||||||
class breakpoint_list : public QListWidget
|
class breakpoint_list : public QListWidget
|
||||||
{
|
{
|
||||||
|
@ -16,8 +17,8 @@ public:
|
||||||
breakpoint_list(QWidget* parent, breakpoint_handler* handler);
|
breakpoint_list(QWidget* parent, breakpoint_handler* handler);
|
||||||
void UpdateCPUData(std::shared_ptr<CPUDisAsm> disasm);
|
void UpdateCPUData(std::shared_ptr<CPUDisAsm> disasm);
|
||||||
void ClearBreakpoints();
|
void ClearBreakpoints();
|
||||||
bool AddBreakpoint(u32 pc);
|
|
||||||
void RemoveBreakpoint(u32 addr);
|
void RemoveBreakpoint(u32 addr);
|
||||||
|
bool AddBreakpoint(u32 pc, bs_t<breakpoint_types> type);
|
||||||
|
|
||||||
QColor m_text_color_bp;
|
QColor m_text_color_bp;
|
||||||
QColor m_color_bp;
|
QColor m_color_bp;
|
||||||
|
@ -36,7 +37,7 @@ private Q_SLOTS:
|
||||||
void OnBreakpointListDelete();
|
void OnBreakpointListDelete();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
breakpoint_handler* m_ppu_breakpoint_handler;
|
breakpoint_handler* m_ppu_breakpoint_handler = nullptr;
|
||||||
QMenu* m_context_menu = nullptr;
|
QMenu* m_context_menu = nullptr;
|
||||||
QAction* m_delete_action;
|
QAction* m_delete_action;
|
||||||
std::shared_ptr<CPUDisAsm> m_disasm = nullptr;
|
std::shared_ptr<CPUDisAsm> m_disasm = nullptr;
|
||||||
|
|
116
rpcs3/rpcs3qt/debugger_add_bp_window.cpp
Normal file
116
rpcs3/rpcs3qt/debugger_add_bp_window.cpp
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
#include "debugger_add_bp_window.h"
|
||||||
|
#include "Utilities/StrFmt.h"
|
||||||
|
#include "Utilities/StrUtil.h"
|
||||||
|
#include "breakpoint_handler.h"
|
||||||
|
#include "util/types.hpp"
|
||||||
|
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
debugger_add_bp_window::debugger_add_bp_window(breakpoint_list* bp_list, QWidget* parent)
|
||||||
|
: QDialog(parent)
|
||||||
|
{
|
||||||
|
ensure(bp_list);
|
||||||
|
|
||||||
|
setWindowTitle(tr("Add a breakpoint"));
|
||||||
|
setModal(true);
|
||||||
|
|
||||||
|
QVBoxLayout* vbox_panel = new QVBoxLayout();
|
||||||
|
|
||||||
|
QHBoxLayout* hbox_top = new QHBoxLayout();
|
||||||
|
QLabel* l_address = new QLabel(tr("Address"));
|
||||||
|
QLineEdit* t_address = new QLineEdit();
|
||||||
|
t_address->setPlaceholderText(tr("Address here"));
|
||||||
|
t_address->setFocus();
|
||||||
|
|
||||||
|
hbox_top->addWidget(l_address);
|
||||||
|
hbox_top->addWidget(t_address);
|
||||||
|
vbox_panel->addLayout(hbox_top);
|
||||||
|
|
||||||
|
QHBoxLayout* hbox_bot = new QHBoxLayout();
|
||||||
|
QComboBox* co_bptype = new QComboBox(this);
|
||||||
|
QStringList qstr_breakpoint_types;
|
||||||
|
|
||||||
|
qstr_breakpoint_types
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
<< tr("Memory Read")
|
||||||
|
<< tr("Memory Write")
|
||||||
|
<< tr("Memory Read&Write")
|
||||||
|
#endif
|
||||||
|
<< tr("Execution");
|
||||||
|
|
||||||
|
co_bptype->addItems(qstr_breakpoint_types);
|
||||||
|
|
||||||
|
hbox_bot->addWidget(co_bptype);
|
||||||
|
vbox_panel->addLayout(hbox_bot);
|
||||||
|
|
||||||
|
QHBoxLayout* hbox_buttons = new QHBoxLayout();
|
||||||
|
QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
|
button_box->button(QDialogButtonBox::Ok)->setText(tr("Add"));
|
||||||
|
|
||||||
|
hbox_buttons->addWidget(button_box);
|
||||||
|
vbox_panel->addLayout(hbox_buttons);
|
||||||
|
|
||||||
|
setLayout(vbox_panel);
|
||||||
|
|
||||||
|
connect(button_box, &QDialogButtonBox::accepted, this, [=, this]
|
||||||
|
{
|
||||||
|
const std::string str_address = t_address->text().toStdString();
|
||||||
|
|
||||||
|
if (str_address.empty())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Add BP error"), tr("Address is empty!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We always want hex
|
||||||
|
const std::string parsed_string = (!str_address.starts_with("0x") && !str_address.starts_with("0X")) ? fmt::format("0x%s", str_address) : str_address;
|
||||||
|
u64 parsed_address = 0;
|
||||||
|
|
||||||
|
// We don't accept 0
|
||||||
|
if (!try_to_uint64(&parsed_address, parsed_string, 1, 0xFF'FF'FF'FF))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Add BP error"), tr("Address is invalid!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u32 address = static_cast<u32>(parsed_address);
|
||||||
|
bs_t<breakpoint_types> bp_t{};
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
switch (co_bptype->currentIndex())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
bp_t = breakpoint_types::bp_read;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
bp_t = breakpoint_types::bp_write;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
bp_t = breakpoint_types::bp_read + breakpoint_types::bp_write;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
bp_t = breakpoint_types::bp_exec;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
bp_t = breakpoint_types::bp_exec;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (bp_t)
|
||||||
|
bp_list->AddBreakpoint(address, bp_t);
|
||||||
|
|
||||||
|
QDialog::accept();
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
|
||||||
|
move(QCursor::pos());
|
||||||
|
}
|
13
rpcs3/rpcs3qt/debugger_add_bp_window.h
Normal file
13
rpcs3/rpcs3qt/debugger_add_bp_window.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "breakpoint_list.h"
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
class debugger_add_bp_window : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit debugger_add_bp_window(breakpoint_list* bp_list, QWidget* parent = nullptr);
|
||||||
|
};
|
|
@ -34,6 +34,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
#include "rpcs3qt/debugger_add_bp_window.h"
|
||||||
#include "util/asm.hpp"
|
#include "util/asm.hpp"
|
||||||
|
|
||||||
constexpr auto qstr = QString::fromStdString;
|
constexpr auto qstr = QString::fromStdString;
|
||||||
|
@ -43,6 +44,9 @@ constexpr auto s_pause_flags = cpu_flag::dbg_pause + cpu_flag::dbg_global_pause;
|
||||||
extern atomic_t<bool> g_debugger_pause_all_threads_on_bp;
|
extern atomic_t<bool> g_debugger_pause_all_threads_on_bp;
|
||||||
|
|
||||||
extern const ppu_decoder<ppu_itype> g_ppu_itype;
|
extern const ppu_decoder<ppu_itype> g_ppu_itype;
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
breakpoint_handler g_breakpoint_handler = breakpoint_handler();
|
||||||
|
#endif
|
||||||
|
|
||||||
extern bool is_using_interpreter(thread_class t_class);
|
extern bool is_using_interpreter(thread_class t_class);
|
||||||
|
|
||||||
|
@ -66,7 +70,12 @@ debugger_frame::debugger_frame(std::shared_ptr<gui_settings> gui_settings, QWidg
|
||||||
QHBoxLayout* hbox_b_main = new QHBoxLayout();
|
QHBoxLayout* hbox_b_main = new QHBoxLayout();
|
||||||
hbox_b_main->setContentsMargins(0, 0, 0, 0);
|
hbox_b_main->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
||||||
|
m_ppu_breakpoint_handler = &g_breakpoint_handler;
|
||||||
|
#else
|
||||||
m_ppu_breakpoint_handler = new breakpoint_handler();
|
m_ppu_breakpoint_handler = new breakpoint_handler();
|
||||||
|
#endif
|
||||||
|
|
||||||
m_breakpoint_list = new breakpoint_list(this, m_ppu_breakpoint_handler);
|
m_breakpoint_list = new breakpoint_list(this, m_ppu_breakpoint_handler);
|
||||||
|
|
||||||
m_debugger_list = new debugger_list(this, m_gui_settings, m_ppu_breakpoint_handler);
|
m_debugger_list = new debugger_list(this, m_gui_settings, m_ppu_breakpoint_handler);
|
||||||
|
@ -90,6 +99,7 @@ debugger_frame::debugger_frame(std::shared_ptr<gui_settings> gui_settings, QWidg
|
||||||
m_go_to_pc = new QPushButton(tr("Go To PC"), this);
|
m_go_to_pc = new QPushButton(tr("Go To PC"), this);
|
||||||
m_btn_step = new QPushButton(tr("Step"), this);
|
m_btn_step = new QPushButton(tr("Step"), this);
|
||||||
m_btn_step_over = new QPushButton(tr("Step Over"), this);
|
m_btn_step_over = new QPushButton(tr("Step Over"), this);
|
||||||
|
m_btn_add_bp = new QPushButton(tr("Add BP"), this);
|
||||||
m_btn_run = new QPushButton(RunString, this);
|
m_btn_run = new QPushButton(RunString, this);
|
||||||
|
|
||||||
EnableButtons(false);
|
EnableButtons(false);
|
||||||
|
@ -100,6 +110,7 @@ debugger_frame::debugger_frame(std::shared_ptr<gui_settings> gui_settings, QWidg
|
||||||
hbox_b_main->addWidget(m_go_to_pc);
|
hbox_b_main->addWidget(m_go_to_pc);
|
||||||
hbox_b_main->addWidget(m_btn_step);
|
hbox_b_main->addWidget(m_btn_step);
|
||||||
hbox_b_main->addWidget(m_btn_step_over);
|
hbox_b_main->addWidget(m_btn_step_over);
|
||||||
|
hbox_b_main->addWidget(m_btn_add_bp);
|
||||||
hbox_b_main->addWidget(m_btn_run);
|
hbox_b_main->addWidget(m_btn_run);
|
||||||
hbox_b_main->addWidget(m_choice_units);
|
hbox_b_main->addWidget(m_choice_units);
|
||||||
hbox_b_main->addStretch();
|
hbox_b_main->addStretch();
|
||||||
|
@ -152,6 +163,12 @@ debugger_frame::debugger_frame(std::shared_ptr<gui_settings> gui_settings, QWidg
|
||||||
connect(m_btn_step, &QAbstractButton::clicked, this, &debugger_frame::DoStep);
|
connect(m_btn_step, &QAbstractButton::clicked, this, &debugger_frame::DoStep);
|
||||||
connect(m_btn_step_over, &QAbstractButton::clicked, [this]() { DoStep(true); });
|
connect(m_btn_step_over, &QAbstractButton::clicked, [this]() { DoStep(true); });
|
||||||
|
|
||||||
|
connect(m_btn_add_bp, &QAbstractButton::clicked, this, [this]
|
||||||
|
{
|
||||||
|
debugger_add_bp_window dlg(m_breakpoint_list, this);
|
||||||
|
dlg.exec();
|
||||||
|
});
|
||||||
|
|
||||||
connect(m_btn_run, &QAbstractButton::clicked, this, &debugger_frame::RunBtnPress);
|
connect(m_btn_run, &QAbstractButton::clicked, this, &debugger_frame::RunBtnPress);
|
||||||
|
|
||||||
connect(m_choice_units->lineEdit(), &QLineEdit::editingFinished, [&]
|
connect(m_choice_units->lineEdit(), &QLineEdit::editingFinished, [&]
|
||||||
|
@ -1588,7 +1605,7 @@ void debugger_frame::DoStep(bool step_over)
|
||||||
|
|
||||||
// Set breakpoint on next instruction
|
// Set breakpoint on next instruction
|
||||||
const u32 next_instruction_pc = current_instruction_pc + 4;
|
const u32 next_instruction_pc = current_instruction_pc + 4;
|
||||||
m_ppu_breakpoint_handler->AddBreakpoint(next_instruction_pc);
|
m_ppu_breakpoint_handler->AddBreakpoint(next_instruction_pc, breakpoint_types::bp_exec);
|
||||||
|
|
||||||
// Undefine previous step over breakpoint if it hasn't been already
|
// Undefine previous step over breakpoint if it hasn't been already
|
||||||
// This can happen when the user steps over a branch that doesn't return to itself
|
// This can happen when the user steps over a branch that doesn't return to itself
|
||||||
|
@ -1680,6 +1697,7 @@ void debugger_frame::EnableButtons(bool enable)
|
||||||
|
|
||||||
m_go_to_addr->setEnabled(enable);
|
m_go_to_addr->setEnabled(enable);
|
||||||
m_go_to_pc->setEnabled(enable);
|
m_go_to_pc->setEnabled(enable);
|
||||||
|
m_btn_add_bp->setEnabled(enable);
|
||||||
m_btn_step->setEnabled(step);
|
m_btn_step->setEnabled(step);
|
||||||
m_btn_step_over->setEnabled(step);
|
m_btn_step_over->setEnabled(step);
|
||||||
m_btn_run->setEnabled(enable);
|
m_btn_run->setEnabled(enable);
|
||||||
|
|
|
@ -46,20 +46,21 @@ class debugger_frame : public custom_dock_widget
|
||||||
const QString RunString = tr("Run");
|
const QString RunString = tr("Run");
|
||||||
const QString PauseString = tr("Pause");
|
const QString PauseString = tr("Pause");
|
||||||
|
|
||||||
debugger_list* m_debugger_list;
|
debugger_list* m_debugger_list = nullptr;
|
||||||
QSplitter* m_right_splitter;
|
QSplitter* m_right_splitter = nullptr;
|
||||||
QFont m_mono;
|
QFont m_mono;
|
||||||
QPlainTextEdit* m_misc_state;
|
QPlainTextEdit* m_misc_state = nullptr;
|
||||||
QPlainTextEdit* m_regs;
|
QPlainTextEdit* m_regs = nullptr;
|
||||||
QPushButton* m_go_to_addr;
|
QPushButton* m_go_to_addr = nullptr;
|
||||||
QPushButton* m_go_to_pc;
|
QPushButton* m_go_to_pc = nullptr;
|
||||||
QPushButton* m_btn_step;
|
QPushButton* m_btn_step = nullptr;
|
||||||
QPushButton* m_btn_step_over;
|
QPushButton* m_btn_step_over = nullptr;
|
||||||
QPushButton* m_btn_run;
|
QPushButton* m_btn_add_bp = nullptr;
|
||||||
|
QPushButton* m_btn_run = nullptr;
|
||||||
|
|
||||||
QComboBox* m_choice_units;
|
QComboBox* m_choice_units = nullptr;
|
||||||
QTimer* m_update;
|
QTimer* m_update = nullptr;
|
||||||
QSplitter* m_splitter;
|
QSplitter* m_splitter = nullptr;
|
||||||
|
|
||||||
u64 m_threads_created = -1;
|
u64 m_threads_created = -1;
|
||||||
u64 m_threads_deleted = -1;
|
u64 m_threads_deleted = -1;
|
||||||
|
@ -83,9 +84,9 @@ class debugger_frame : public custom_dock_widget
|
||||||
u32 m_spu_disasm_pc = 0;
|
u32 m_spu_disasm_pc = 0;
|
||||||
bool m_is_spu_disasm_mode = false;
|
bool m_is_spu_disasm_mode = false;
|
||||||
|
|
||||||
breakpoint_list* m_breakpoint_list;
|
breakpoint_list* m_breakpoint_list = nullptr;
|
||||||
breakpoint_handler* m_ppu_breakpoint_handler;
|
breakpoint_handler* m_ppu_breakpoint_handler = nullptr;
|
||||||
call_stack_list* m_call_stack_list;
|
call_stack_list* m_call_stack_list = nullptr;
|
||||||
instruction_editor_dialog* m_inst_editor = nullptr;
|
instruction_editor_dialog* m_inst_editor = nullptr;
|
||||||
register_editor_dialog* m_reg_editor = nullptr;
|
register_editor_dialog* m_reg_editor = nullptr;
|
||||||
QDialog* m_goto_dialog = nullptr;
|
QDialog* m_goto_dialog = nullptr;
|
||||||
|
|
|
@ -157,7 +157,7 @@ void debugger_list::ShowAddress(u32 addr, bool select_addr, bool direct)
|
||||||
{
|
{
|
||||||
case thread_class::ppu:
|
case thread_class::ppu:
|
||||||
{
|
{
|
||||||
return m_ppu_breakpoint_handler->HasBreakpoint(pc);
|
return m_ppu_breakpoint_handler->HasBreakpoint(pc, breakpoint_types::bp_exec);
|
||||||
}
|
}
|
||||||
case thread_class::spu:
|
case thread_class::spu:
|
||||||
{
|
{
|
||||||
|
|
|
@ -56,7 +56,7 @@ private:
|
||||||
|
|
||||||
std::shared_ptr<gui_settings> m_gui_settings;
|
std::shared_ptr<gui_settings> m_gui_settings;
|
||||||
|
|
||||||
breakpoint_handler* m_ppu_breakpoint_handler;
|
breakpoint_handler* m_ppu_breakpoint_handler = nullptr;
|
||||||
cpu_thread* m_cpu = nullptr;
|
cpu_thread* m_cpu = nullptr;
|
||||||
std::shared_ptr<CPUDisAsm> m_disasm;
|
std::shared_ptr<CPUDisAsm> m_disasm;
|
||||||
QDialog* m_cmd_detail = nullptr;
|
QDialog* m_cmd_detail = nullptr;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue