diff --git a/src/xenia/cpu/cpu-private.h b/src/xenia/cpu/cpu-private.h index 3272d2ece..1b49862f6 100644 --- a/src/xenia/cpu/cpu-private.h +++ b/src/xenia/cpu/cpu-private.h @@ -20,6 +20,9 @@ DECLARE_bool(trace_user_calls); DECLARE_bool(trace_kernel_calls); DECLARE_uint64(trace_thread_mask); +DECLARE_uint64(break_on_instruction); +DECLARE_uint64(break_on_memory); + DECLARE_string(load_module_map); DECLARE_string(dump_path); diff --git a/src/xenia/cpu/cpu.cc b/src/xenia/cpu/cpu.cc index 389aeee18..12c8118f6 100644 --- a/src/xenia/cpu/cpu.cc +++ b/src/xenia/cpu/cpu.cc @@ -25,6 +25,13 @@ DEFINE_uint64(trace_thread_mask, -1, "Trace threads with IDs in the mask, or -1 for all."); +// Breakpoints: +DEFINE_uint64(break_on_instruction, 0, + "int3 before the given guest address is executed."); +DEFINE_uint64(break_on_memory, 0, + "int3 on read/write to the given memory address."); + + // Debugging: DEFINE_string(load_module_map, "", "Loads a .map for symbol names and to diff with the generated symbol " diff --git a/src/xenia/cpu/x64/x64_emitter.cc b/src/xenia/cpu/x64/x64_emitter.cc index 44103f66b..54d0f6510 100644 --- a/src/xenia/cpu/x64/x64_emitter.cc +++ b/src/xenia/cpu/x64/x64_emitter.cc @@ -652,7 +652,13 @@ void X64Emitter::GenerateBasicBlock(FunctionBlock* block) { typedef int (*InstrEmitter)(X64Emitter& g, X86Compiler& c, InstrData& i); InstrEmitter emit = (InstrEmitter)i.type->emit; + TraceInstruction(i); + + if (i.address == FLAGS_break_on_instruction) { + c.int3(); + } + if (!i.type->emit || emit(*this, compiler_, i)) { // This printf is handy for sort/uniquify to find instructions. printf("unimplinstr %s\n", i.type->name); @@ -1877,6 +1883,14 @@ GpVar X64Emitter::ReadMemory( uint32_t cia, GpVar& addr, uint32_t size, bool acquire, bool bswap) { X86Compiler& c = compiler_; + if (FLAGS_break_on_memory) { + Label l(c.newLabel()); + c.cmp(addr.r32(), imm(FLAGS_break_on_memory)); + c.jne(l); + c.int3(); + c.bind(l); + } + // Rebase off of memory base pointer. GpVar real_address = TouchMemoryAddress(cia, addr); @@ -1931,6 +1945,14 @@ void X64Emitter::WriteMemory( bool release, bool bswap) { X86Compiler& c = compiler_; + if (FLAGS_break_on_memory) { + Label l(c.newLabel()); + c.cmp(addr.r32(), imm(FLAGS_break_on_memory)); + c.jne(l); + c.int3(); + c.bind(l); + } + // Rebase off of memory base pointer. GpVar real_address = TouchMemoryAddress(cia, addr); @@ -2011,6 +2033,14 @@ XmmVar X64Emitter::ReadMemoryXmm( uint32_t cia, GpVar& addr, uint32_t alignment) { X86Compiler& c = compiler_; + if (FLAGS_break_on_memory) { + Label l(c.newLabel()); + c.cmp(addr.r32(), imm(FLAGS_break_on_memory)); + c.jne(l); + c.int3(); + c.bind(l); + } + // Align memory address. GpVar aligned_addr(c.newGpVar()); c.mov(aligned_addr, addr); @@ -2045,6 +2075,14 @@ void X64Emitter::WriteMemoryXmm( uint32_t cia, GpVar& addr, uint32_t alignment, XmmVar& value) { X86Compiler& c = compiler_; + if (FLAGS_break_on_memory) { + Label l(c.newLabel()); + c.cmp(addr.r32(), imm(FLAGS_break_on_memory)); + c.jne(l); + c.int3(); + c.bind(l); + } + // Align memory address. GpVar aligned_addr(c.newGpVar()); c.mov(aligned_addr, addr);