diff options
| author | 2022-06-06 12:56:01 -0400 | |
|---|---|---|
| committer | 2022-06-16 13:18:07 -0400 | |
| commit | 208ed712f42cfd277405a22663197dc1c5e84cfe (patch) | |
| tree | 56c1a3cbddf392d700e817cd4093564e3f096013 /src/core/arm/dynarmic | |
| parent | Merge pull request #8457 from liamwhite/kprocess-suspend (diff) | |
| download | yuzu-208ed712f42cfd277405a22663197dc1c5e84cfe.tar.gz yuzu-208ed712f42cfd277405a22663197dc1c5e84cfe.tar.xz yuzu-208ed712f42cfd277405a22663197dc1c5e84cfe.zip | |
core/debugger: memory breakpoint support
Diffstat (limited to 'src/core/arm/dynarmic')
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.cpp | 69 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.h | 6 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 79 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.h | 6 |
4 files changed, 135 insertions, 25 deletions
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; | |||
| 29 | class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { | 29 | class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { |
| 30 | public: | 30 | public: |
| 31 | explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) | 31 | explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) |
| 32 | : parent{parent_}, memory(parent.system.Memory()) {} | 32 | : parent{parent_}, |
| 33 | memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()} {} | ||
| 33 | 34 | ||
| 34 | u8 MemoryRead8(u32 vaddr) override { | 35 | u8 MemoryRead8(u32 vaddr) override { |
| 36 | CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read); | ||
| 35 | return memory.Read8(vaddr); | 37 | return memory.Read8(vaddr); |
| 36 | } | 38 | } |
| 37 | u16 MemoryRead16(u32 vaddr) override { | 39 | u16 MemoryRead16(u32 vaddr) override { |
| 40 | CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read); | ||
| 38 | return memory.Read16(vaddr); | 41 | return memory.Read16(vaddr); |
| 39 | } | 42 | } |
| 40 | u32 MemoryRead32(u32 vaddr) override { | 43 | u32 MemoryRead32(u32 vaddr) override { |
| 44 | CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read); | ||
| 41 | return memory.Read32(vaddr); | 45 | return memory.Read32(vaddr); |
| 42 | } | 46 | } |
| 43 | u64 MemoryRead64(u32 vaddr) override { | 47 | u64 MemoryRead64(u32 vaddr) override { |
| 48 | CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); | ||
| 44 | return memory.Read64(vaddr); | 49 | return memory.Read64(vaddr); |
| 45 | } | 50 | } |
| 46 | 51 | ||
| 47 | void MemoryWrite8(u32 vaddr, u8 value) override { | 52 | void MemoryWrite8(u32 vaddr, u8 value) override { |
| 48 | memory.Write8(vaddr, value); | 53 | if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { |
| 54 | memory.Write8(vaddr, value); | ||
| 55 | } | ||
| 49 | } | 56 | } |
| 50 | void MemoryWrite16(u32 vaddr, u16 value) override { | 57 | void MemoryWrite16(u32 vaddr, u16 value) override { |
| 51 | memory.Write16(vaddr, value); | 58 | if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) { |
| 59 | memory.Write16(vaddr, value); | ||
| 60 | } | ||
| 52 | } | 61 | } |
| 53 | void MemoryWrite32(u32 vaddr, u32 value) override { | 62 | void MemoryWrite32(u32 vaddr, u32 value) override { |
| 54 | memory.Write32(vaddr, value); | 63 | if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) { |
| 64 | memory.Write32(vaddr, value); | ||
| 65 | } | ||
| 55 | } | 66 | } |
| 56 | void MemoryWrite64(u32 vaddr, u64 value) override { | 67 | void MemoryWrite64(u32 vaddr, u64 value) override { |
| 57 | memory.Write64(vaddr, value); | 68 | if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) { |
| 69 | memory.Write64(vaddr, value); | ||
| 70 | } | ||
| 58 | } | 71 | } |
| 59 | 72 | ||
| 60 | bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override { | 73 | bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override { |
| 61 | return memory.WriteExclusive8(vaddr, value, expected); | 74 | return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) && |
| 75 | memory.WriteExclusive8(vaddr, value, expected); | ||
| 62 | } | 76 | } |
| 63 | bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override { | 77 | bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override { |
| 64 | return memory.WriteExclusive16(vaddr, value, expected); | 78 | return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) && |
| 79 | memory.WriteExclusive16(vaddr, value, expected); | ||
| 65 | } | 80 | } |
| 66 | bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override { | 81 | bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override { |
| 67 | return memory.WriteExclusive32(vaddr, value, expected); | 82 | return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) && |
| 83 | memory.WriteExclusive32(vaddr, value, expected); | ||
| 68 | } | 84 | } |
| 69 | bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override { | 85 | bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override { |
| 70 | return memory.WriteExclusive64(vaddr, value, expected); | 86 | return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) && |
| 87 | memory.WriteExclusive64(vaddr, value, expected); | ||
| 71 | } | 88 | } |
| 72 | 89 | ||
| 73 | void InterpreterFallback(u32 pc, std::size_t num_instructions) override { | 90 | void InterpreterFallback(u32 pc, std::size_t num_instructions) override { |
| @@ -77,8 +94,8 @@ public: | |||
| 77 | } | 94 | } |
| 78 | 95 | ||
| 79 | void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { | 96 | void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { |
| 80 | if (parent.system.DebuggerEnabled()) { | 97 | if (debugger_enabled) { |
| 81 | parent.jit.load()->Regs()[15] = pc; | 98 | parent.SaveContext(parent.breakpoint_context); |
| 82 | parent.jit.load()->HaltExecution(ARM_Interface::breakpoint); | 99 | parent.jit.load()->HaltExecution(ARM_Interface::breakpoint); |
| 83 | return; | 100 | return; |
| 84 | } | 101 | } |
| @@ -117,9 +134,26 @@ public: | |||
| 117 | return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); | 134 | return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); |
| 118 | } | 135 | } |
| 119 | 136 | ||
| 137 | bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) { | ||
| 138 | if (!debugger_enabled) { | ||
| 139 | return true; | ||
| 140 | } | ||
| 141 | |||
| 142 | const auto match{parent.MatchingWatchpoint(addr, size, type)}; | ||
| 143 | if (match) { | ||
| 144 | parent.SaveContext(parent.breakpoint_context); | ||
| 145 | parent.jit.load()->HaltExecution(ARM_Interface::watchpoint); | ||
| 146 | parent.halted_watchpoint = match; | ||
| 147 | return false; | ||
| 148 | } | ||
| 149 | |||
| 150 | return true; | ||
| 151 | } | ||
| 152 | |||
| 120 | ARM_Dynarmic_32& parent; | 153 | ARM_Dynarmic_32& parent; |
| 121 | Core::Memory::Memory& memory; | 154 | Core::Memory::Memory& memory; |
| 122 | std::size_t num_interpreted_instructions{}; | 155 | std::size_t num_interpreted_instructions{}; |
| 156 | bool debugger_enabled{}; | ||
| 123 | static constexpr u64 minimum_run_cycles = 1000U; | 157 | static constexpr u64 minimum_run_cycles = 1000U; |
| 124 | }; | 158 | }; |
| 125 | 159 | ||
| @@ -154,6 +188,11 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* | |||
| 154 | config.code_cache_size = 512_MiB; | 188 | config.code_cache_size = 512_MiB; |
| 155 | config.far_code_offset = 400_MiB; | 189 | config.far_code_offset = 400_MiB; |
| 156 | 190 | ||
| 191 | // Allow memory fault handling to work | ||
| 192 | if (system.DebuggerEnabled()) { | ||
| 193 | config.check_halt_on_memory_access = true; | ||
| 194 | } | ||
| 195 | |||
| 157 | // null_jit | 196 | // null_jit |
| 158 | if (!page_table) { | 197 | if (!page_table) { |
| 159 | // Don't waste too much memory on null_jit | 198 | // Don't waste too much memory on null_jit |
| @@ -248,6 +287,14 @@ u32 ARM_Dynarmic_32::GetSvcNumber() const { | |||
| 248 | return svc_swi; | 287 | return svc_swi; |
| 249 | } | 288 | } |
| 250 | 289 | ||
| 290 | const Kernel::DebugWatchpoint* ARM_Dynarmic_32::HaltedWatchpoint() const { | ||
| 291 | return halted_watchpoint; | ||
| 292 | } | ||
| 293 | |||
| 294 | void ARM_Dynarmic_32::RewindBreakpointInstruction() { | ||
| 295 | LoadContext(breakpoint_context); | ||
| 296 | } | ||
| 297 | |||
| 251 | ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, | 298 | ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, |
| 252 | bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, | 299 | bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, |
| 253 | std::size_t core_index_) | 300 | std::size_t core_index_) |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 5b1d60005..fcbe24f0c 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h | |||
| @@ -72,6 +72,8 @@ protected: | |||
| 72 | Dynarmic::HaltReason RunJit() override; | 72 | Dynarmic::HaltReason RunJit() override; |
| 73 | Dynarmic::HaltReason StepJit() override; | 73 | Dynarmic::HaltReason StepJit() override; |
| 74 | u32 GetSvcNumber() const override; | 74 | u32 GetSvcNumber() const override; |
| 75 | const Kernel::DebugWatchpoint* HaltedWatchpoint() const override; | ||
| 76 | void RewindBreakpointInstruction() override; | ||
| 75 | 77 | ||
| 76 | private: | 78 | private: |
| 77 | std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; | 79 | std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; |
| @@ -98,6 +100,10 @@ private: | |||
| 98 | 100 | ||
| 99 | // SVC callback | 101 | // SVC callback |
| 100 | u32 svc_swi{}; | 102 | u32 svc_swi{}; |
| 103 | |||
| 104 | // Watchpoint info | ||
| 105 | const Kernel::DebugWatchpoint* halted_watchpoint; | ||
| 106 | ThreadContext32 breakpoint_context; | ||
| 101 | }; | 107 | }; |
| 102 | 108 | ||
| 103 | } // namespace Core | 109 | } // namespace Core |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index d4c67eafd..4370ca294 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -29,55 +29,76 @@ using namespace Common::Literals; | |||
| 29 | class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { | 29 | class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { |
| 30 | public: | 30 | public: |
| 31 | explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) | 31 | explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) |
| 32 | : parent{parent_}, memory(parent.system.Memory()) {} | 32 | : parent{parent_}, |
| 33 | memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()} {} | ||
| 33 | 34 | ||
| 34 | u8 MemoryRead8(u64 vaddr) override { | 35 | u8 MemoryRead8(u64 vaddr) override { |
| 36 | CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read); | ||
| 35 | return memory.Read8(vaddr); | 37 | return memory.Read8(vaddr); |
| 36 | } | 38 | } |
| 37 | u16 MemoryRead16(u64 vaddr) override { | 39 | u16 MemoryRead16(u64 vaddr) override { |
| 40 | CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read); | ||
| 38 | return memory.Read16(vaddr); | 41 | return memory.Read16(vaddr); |
| 39 | } | 42 | } |
| 40 | u32 MemoryRead32(u64 vaddr) override { | 43 | u32 MemoryRead32(u64 vaddr) override { |
| 44 | CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read); | ||
| 41 | return memory.Read32(vaddr); | 45 | return memory.Read32(vaddr); |
| 42 | } | 46 | } |
| 43 | u64 MemoryRead64(u64 vaddr) override { | 47 | u64 MemoryRead64(u64 vaddr) override { |
| 48 | CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); | ||
| 44 | return memory.Read64(vaddr); | 49 | return memory.Read64(vaddr); |
| 45 | } | 50 | } |
| 46 | Vector MemoryRead128(u64 vaddr) override { | 51 | Vector MemoryRead128(u64 vaddr) override { |
| 52 | CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read); | ||
| 47 | return {memory.Read64(vaddr), memory.Read64(vaddr + 8)}; | 53 | return {memory.Read64(vaddr), memory.Read64(vaddr + 8)}; |
| 48 | } | 54 | } |
| 49 | 55 | ||
| 50 | void MemoryWrite8(u64 vaddr, u8 value) override { | 56 | void MemoryWrite8(u64 vaddr, u8 value) override { |
| 51 | memory.Write8(vaddr, value); | 57 | if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { |
| 58 | memory.Write8(vaddr, value); | ||
| 59 | } | ||
| 52 | } | 60 | } |
| 53 | void MemoryWrite16(u64 vaddr, u16 value) override { | 61 | void MemoryWrite16(u64 vaddr, u16 value) override { |
| 54 | memory.Write16(vaddr, value); | 62 | if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) { |
| 63 | memory.Write16(vaddr, value); | ||
| 64 | } | ||
| 55 | } | 65 | } |
| 56 | void MemoryWrite32(u64 vaddr, u32 value) override { | 66 | void MemoryWrite32(u64 vaddr, u32 value) override { |
| 57 | memory.Write32(vaddr, value); | 67 | if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) { |
| 68 | memory.Write32(vaddr, value); | ||
| 69 | } | ||
| 58 | } | 70 | } |
| 59 | void MemoryWrite64(u64 vaddr, u64 value) override { | 71 | void MemoryWrite64(u64 vaddr, u64 value) override { |
| 60 | memory.Write64(vaddr, value); | 72 | if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) { |
| 73 | memory.Write64(vaddr, value); | ||
| 74 | } | ||
| 61 | } | 75 | } |
| 62 | void MemoryWrite128(u64 vaddr, Vector value) override { | 76 | void MemoryWrite128(u64 vaddr, Vector value) override { |
| 63 | memory.Write64(vaddr, value[0]); | 77 | if (CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write)) { |
| 64 | memory.Write64(vaddr + 8, value[1]); | 78 | memory.Write64(vaddr, value[0]); |
| 79 | memory.Write64(vaddr + 8, value[1]); | ||
| 80 | } | ||
| 65 | } | 81 | } |
| 66 | 82 | ||
| 67 | bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override { | 83 | bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override { |
| 68 | return memory.WriteExclusive8(vaddr, value, expected); | 84 | return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) && |
| 85 | memory.WriteExclusive8(vaddr, value, expected); | ||
| 69 | } | 86 | } |
| 70 | bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override { | 87 | bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override { |
| 71 | return memory.WriteExclusive16(vaddr, value, expected); | 88 | return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) && |
| 89 | memory.WriteExclusive16(vaddr, value, expected); | ||
| 72 | } | 90 | } |
| 73 | bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override { | 91 | bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override { |
| 74 | return memory.WriteExclusive32(vaddr, value, expected); | 92 | return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) && |
| 93 | memory.WriteExclusive32(vaddr, value, expected); | ||
| 75 | } | 94 | } |
| 76 | bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override { | 95 | bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override { |
| 77 | return memory.WriteExclusive64(vaddr, value, expected); | 96 | return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) && |
| 97 | memory.WriteExclusive64(vaddr, value, expected); | ||
| 78 | } | 98 | } |
| 79 | bool MemoryWriteExclusive128(u64 vaddr, Vector value, Vector expected) override { | 99 | bool MemoryWriteExclusive128(u64 vaddr, Vector value, Vector expected) override { |
| 80 | return memory.WriteExclusive128(vaddr, value, expected); | 100 | return CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write) && |
| 101 | memory.WriteExclusive128(vaddr, value, expected); | ||
| 81 | } | 102 | } |
| 82 | 103 | ||
| 83 | void InterpreterFallback(u64 pc, std::size_t num_instructions) override { | 104 | void InterpreterFallback(u64 pc, std::size_t num_instructions) override { |
| @@ -118,8 +139,8 @@ public: | |||
| 118 | case Dynarmic::A64::Exception::Yield: | 139 | case Dynarmic::A64::Exception::Yield: |
| 119 | return; | 140 | return; |
| 120 | default: | 141 | default: |
| 121 | if (parent.system.DebuggerEnabled()) { | 142 | if (debugger_enabled) { |
| 122 | parent.jit.load()->SetPC(pc); | 143 | parent.SaveContext(parent.breakpoint_context); |
| 123 | parent.jit.load()->HaltExecution(ARM_Interface::breakpoint); | 144 | parent.jit.load()->HaltExecution(ARM_Interface::breakpoint); |
| 124 | return; | 145 | return; |
| 125 | } | 146 | } |
| @@ -160,10 +181,27 @@ public: | |||
| 160 | return parent.system.CoreTiming().GetClockTicks(); | 181 | return parent.system.CoreTiming().GetClockTicks(); |
| 161 | } | 182 | } |
| 162 | 183 | ||
| 184 | bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) { | ||
| 185 | if (!debugger_enabled) { | ||
| 186 | return true; | ||
| 187 | } | ||
| 188 | |||
| 189 | const auto match{parent.MatchingWatchpoint(addr, size, type)}; | ||
| 190 | if (match) { | ||
| 191 | parent.SaveContext(parent.breakpoint_context); | ||
| 192 | parent.jit.load()->HaltExecution(ARM_Interface::watchpoint); | ||
| 193 | parent.halted_watchpoint = match; | ||
| 194 | return false; | ||
| 195 | } | ||
| 196 | |||
| 197 | return true; | ||
| 198 | } | ||
| 199 | |||
| 163 | ARM_Dynarmic_64& parent; | 200 | ARM_Dynarmic_64& parent; |
| 164 | Core::Memory::Memory& memory; | 201 | Core::Memory::Memory& memory; |
| 165 | u64 tpidrro_el0 = 0; | 202 | u64 tpidrro_el0 = 0; |
| 166 | u64 tpidr_el0 = 0; | 203 | u64 tpidr_el0 = 0; |
| 204 | bool debugger_enabled{}; | ||
| 167 | static constexpr u64 minimum_run_cycles = 1000U; | 205 | static constexpr u64 minimum_run_cycles = 1000U; |
| 168 | }; | 206 | }; |
| 169 | 207 | ||
| @@ -214,6 +252,11 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* | |||
| 214 | config.code_cache_size = 512_MiB; | 252 | config.code_cache_size = 512_MiB; |
| 215 | config.far_code_offset = 400_MiB; | 253 | config.far_code_offset = 400_MiB; |
| 216 | 254 | ||
| 255 | // Allow memory fault handling to work | ||
| 256 | if (system.DebuggerEnabled()) { | ||
| 257 | config.check_halt_on_memory_access = true; | ||
| 258 | } | ||
| 259 | |||
| 217 | // null_jit | 260 | // null_jit |
| 218 | if (!page_table) { | 261 | if (!page_table) { |
| 219 | // Don't waste too much memory on null_jit | 262 | // Don't waste too much memory on null_jit |
| @@ -308,6 +351,14 @@ u32 ARM_Dynarmic_64::GetSvcNumber() const { | |||
| 308 | return svc_swi; | 351 | return svc_swi; |
| 309 | } | 352 | } |
| 310 | 353 | ||
| 354 | const Kernel::DebugWatchpoint* ARM_Dynarmic_64::HaltedWatchpoint() const { | ||
| 355 | return halted_watchpoint; | ||
| 356 | } | ||
| 357 | |||
| 358 | void ARM_Dynarmic_64::RewindBreakpointInstruction() { | ||
| 359 | LoadContext(breakpoint_context); | ||
| 360 | } | ||
| 361 | |||
| 311 | ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, | 362 | ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, |
| 312 | bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, | 363 | bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, |
| 313 | std::size_t core_index_) | 364 | std::size_t core_index_) |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index abfbc3c3f..71dbaac5e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h | |||
| @@ -66,6 +66,8 @@ protected: | |||
| 66 | Dynarmic::HaltReason RunJit() override; | 66 | Dynarmic::HaltReason RunJit() override; |
| 67 | Dynarmic::HaltReason StepJit() override; | 67 | Dynarmic::HaltReason StepJit() override; |
| 68 | u32 GetSvcNumber() const override; | 68 | u32 GetSvcNumber() const override; |
| 69 | const Kernel::DebugWatchpoint* HaltedWatchpoint() const override; | ||
| 70 | void RewindBreakpointInstruction() override; | ||
| 69 | 71 | ||
| 70 | private: | 72 | private: |
| 71 | std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, | 73 | std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, |
| @@ -91,6 +93,10 @@ private: | |||
| 91 | 93 | ||
| 92 | // SVC callback | 94 | // SVC callback |
| 93 | u32 svc_swi{}; | 95 | u32 svc_swi{}; |
| 96 | |||
| 97 | // Breakpoint info | ||
| 98 | const Kernel::DebugWatchpoint* halted_watchpoint; | ||
| 99 | ThreadContext64 breakpoint_context; | ||
| 94 | }; | 100 | }; |
| 95 | 101 | ||
| 96 | } // namespace Core | 102 | } // namespace Core |