From 208ed712f42cfd277405a22663197dc1c5e84cfe Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 6 Jun 2022 12:56:01 -0400 Subject: core/debugger: memory breakpoint support --- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 69 ++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 11 deletions(-) (limited to 'src/core/arm/dynarmic/arm_dynarmic_32.cpp') diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 7c82d0b96..8c90c8be0 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -29,45 +29,62 @@ using namespace Common::Literals; class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { public: explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) - : parent{parent_}, memory(parent.system.Memory()) {} + : parent{parent_}, + memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()} {} u8 MemoryRead8(u32 vaddr) override { + CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read); return memory.Read8(vaddr); } u16 MemoryRead16(u32 vaddr) override { + CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read); return memory.Read16(vaddr); } u32 MemoryRead32(u32 vaddr) override { + CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read); return memory.Read32(vaddr); } u64 MemoryRead64(u32 vaddr) override { + CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); return memory.Read64(vaddr); } void MemoryWrite8(u32 vaddr, u8 value) override { - memory.Write8(vaddr, value); + if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { + memory.Write8(vaddr, value); + } } void MemoryWrite16(u32 vaddr, u16 value) override { - memory.Write16(vaddr, value); + if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) { + memory.Write16(vaddr, value); + } } void MemoryWrite32(u32 vaddr, u32 value) override { - memory.Write32(vaddr, value); + if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) { + memory.Write32(vaddr, value); + } } void MemoryWrite64(u32 vaddr, u64 value) override { - memory.Write64(vaddr, value); + if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) { + memory.Write64(vaddr, value); + } } bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override { - return memory.WriteExclusive8(vaddr, value, expected); + return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) && + memory.WriteExclusive8(vaddr, value, expected); } bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override { - return memory.WriteExclusive16(vaddr, value, expected); + return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) && + memory.WriteExclusive16(vaddr, value, expected); } bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override { - return memory.WriteExclusive32(vaddr, value, expected); + return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) && + memory.WriteExclusive32(vaddr, value, expected); } bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override { - return memory.WriteExclusive64(vaddr, value, expected); + return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) && + memory.WriteExclusive64(vaddr, value, expected); } void InterpreterFallback(u32 pc, std::size_t num_instructions) override { @@ -77,8 +94,8 @@ public: } void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { - if (parent.system.DebuggerEnabled()) { - parent.jit.load()->Regs()[15] = pc; + if (debugger_enabled) { + parent.SaveContext(parent.breakpoint_context); parent.jit.load()->HaltExecution(ARM_Interface::breakpoint); return; } @@ -117,9 +134,26 @@ public: return std::max(parent.system.CoreTiming().GetDowncount(), 0); } + bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) { + if (!debugger_enabled) { + return true; + } + + const auto match{parent.MatchingWatchpoint(addr, size, type)}; + if (match) { + parent.SaveContext(parent.breakpoint_context); + parent.jit.load()->HaltExecution(ARM_Interface::watchpoint); + parent.halted_watchpoint = match; + return false; + } + + return true; + } + ARM_Dynarmic_32& parent; Core::Memory::Memory& memory; std::size_t num_interpreted_instructions{}; + bool debugger_enabled{}; static constexpr u64 minimum_run_cycles = 1000U; }; @@ -154,6 +188,11 @@ std::shared_ptr ARM_Dynarmic_32::MakeJit(Common::PageTable* config.code_cache_size = 512_MiB; config.far_code_offset = 400_MiB; + // Allow memory fault handling to work + if (system.DebuggerEnabled()) { + config.check_halt_on_memory_access = true; + } + // null_jit if (!page_table) { // Don't waste too much memory on null_jit @@ -248,6 +287,14 @@ u32 ARM_Dynarmic_32::GetSvcNumber() const { return svc_swi; } +const Kernel::DebugWatchpoint* ARM_Dynarmic_32::HaltedWatchpoint() const { + return halted_watchpoint; +} + +void ARM_Dynarmic_32::RewindBreakpointInstruction() { + LoadContext(breakpoint_context); +} + ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_) -- cgit v1.2.3