diff options
| author | 2022-06-01 20:46:10 -0400 | |
|---|---|---|
| committer | 2022-06-01 20:46:10 -0400 | |
| commit | 858f8ac6d9f39a1be95dc2f5e83c752b725136ad (patch) | |
| tree | 26d5733fe69193e76402bad78b1a3a8b791b6095 | |
| parent | Merge pull request #8400 from Docteh/fullscreen_glitch (diff) | |
| parent | core/debugger: Improved stepping mechanism and misc fixes (diff) | |
| download | yuzu-858f8ac6d9f39a1be95dc2f5e83c752b725136ad.tar.gz yuzu-858f8ac6d9f39a1be95dc2f5e83c752b725136ad.tar.xz yuzu-858f8ac6d9f39a1be95dc2f5e83c752b725136ad.zip | |
Merge pull request #8402 from liamwhite/better-step
core/debugger: Improved stepping mechanism and misc fixes
Diffstat (limited to '')
| -rw-r--r-- | CMakeLists.txt | 5 | ||||
| -rw-r--r-- | src/core/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/core/arm/arm_interface.cpp | 45 | ||||
| -rw-r--r-- | src/core/arm/arm_interface.h | 14 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.cpp | 45 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.h | 9 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 45 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.h | 9 | ||||
| -rw-r--r-- | src/core/debugger/debugger.cpp | 61 | ||||
| -rw-r--r-- | src/core/debugger/debugger.h | 5 | ||||
| -rw-r--r-- | src/core/debugger/debugger_interface.h | 9 | ||||
| -rw-r--r-- | src/core/debugger/gdbstub.cpp | 99 | ||||
| -rw-r--r-- | src/core/debugger/gdbstub.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.h | 15 | ||||
| -rw-r--r-- | src/video_core/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/yuzu/CMakeLists.txt | 4 |
16 files changed, 252 insertions, 122 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e3de90ff..be70c04ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -222,6 +222,11 @@ else() | |||
| 222 | list(APPEND CONAN_REQUIRED_LIBS "boost/1.79.0") | 222 | list(APPEND CONAN_REQUIRED_LIBS "boost/1.79.0") |
| 223 | endif() | 223 | endif() |
| 224 | 224 | ||
| 225 | # boost:asio has functions that require AcceptEx et al | ||
| 226 | if (MINGW) | ||
| 227 | find_library(MSWSOCK_LIBRARY mswsock REQUIRED) | ||
| 228 | endif() | ||
| 229 | |||
| 225 | # Attempt to locate any packages that are required and report the missing ones in CONAN_REQUIRED_LIBS | 230 | # Attempt to locate any packages that are required and report the missing ones in CONAN_REQUIRED_LIBS |
| 226 | yuzu_find_packages() | 231 | yuzu_find_packages() |
| 227 | 232 | ||
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 948cc318a..2bd720f08 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -768,6 +768,9 @@ create_target_directory_groups(core) | |||
| 768 | 768 | ||
| 769 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) | 769 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) |
| 770 | target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus) | 770 | target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus) |
| 771 | if (MINGW) | ||
| 772 | target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY}) | ||
| 773 | endif() | ||
| 771 | 774 | ||
| 772 | if (ENABLE_WEB_SERVICE) | 775 | if (ENABLE_WEB_SERVICE) |
| 773 | target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) | 776 | target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE) |
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 1310f72bf..9b5a5ca57 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "core/core.h" | 11 | #include "core/core.h" |
| 12 | #include "core/debugger/debugger.h" | 12 | #include "core/debugger/debugger.h" |
| 13 | #include "core/hle/kernel/k_process.h" | 13 | #include "core/hle/kernel/k_process.h" |
| 14 | #include "core/hle/kernel/svc.h" | ||
| 14 | #include "core/loader/loader.h" | 15 | #include "core/loader/loader.h" |
| 15 | #include "core/memory.h" | 16 | #include "core/memory.h" |
| 16 | 17 | ||
| @@ -89,8 +90,48 @@ void ARM_Interface::LogBacktrace() const { | |||
| 89 | } | 90 | } |
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | bool ARM_Interface::ShouldStep() const { | 93 | void ARM_Interface::Run() { |
| 93 | return system.DebuggerEnabled() && system.GetDebugger().IsStepping(); | 94 | using Kernel::StepState; |
| 95 | using Kernel::SuspendType; | ||
| 96 | |||
| 97 | while (true) { | ||
| 98 | Kernel::KThread* current_thread{system.Kernel().CurrentScheduler()->GetCurrentThread()}; | ||
| 99 | Dynarmic::HaltReason hr{}; | ||
| 100 | |||
| 101 | // Notify the debugger and go to sleep if a step was performed | ||
| 102 | // and this thread has been scheduled again. | ||
| 103 | if (current_thread->GetStepState() == StepState::StepPerformed) { | ||
| 104 | system.GetDebugger().NotifyThreadStopped(current_thread); | ||
| 105 | current_thread->RequestSuspend(SuspendType::Debug); | ||
| 106 | break; | ||
| 107 | } | ||
| 108 | |||
| 109 | // Otherwise, run the thread. | ||
| 110 | if (current_thread->GetStepState() == StepState::StepPending) { | ||
| 111 | hr = StepJit(); | ||
| 112 | |||
| 113 | if (Has(hr, step_thread)) { | ||
| 114 | current_thread->SetStepState(StepState::StepPerformed); | ||
| 115 | } | ||
| 116 | } else { | ||
| 117 | hr = RunJit(); | ||
| 118 | } | ||
| 119 | |||
| 120 | // Notify the debugger and go to sleep if a breakpoint was hit. | ||
| 121 | if (Has(hr, breakpoint)) { | ||
| 122 | system.GetDebugger().NotifyThreadStopped(current_thread); | ||
| 123 | current_thread->RequestSuspend(Kernel::SuspendType::Debug); | ||
| 124 | break; | ||
| 125 | } | ||
| 126 | |||
| 127 | // Handle syscalls and scheduling (this may change the current thread) | ||
| 128 | if (Has(hr, svc_call)) { | ||
| 129 | Kernel::Svc::Call(system, GetSvcNumber()); | ||
| 130 | } | ||
| 131 | if (Has(hr, break_loop) || !uses_wall_clock) { | ||
| 132 | break; | ||
| 133 | } | ||
| 134 | } | ||
| 94 | } | 135 | } |
| 95 | 136 | ||
| 96 | } // namespace Core | 137 | } // namespace Core |
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 7842c626b..66f6107e9 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -6,6 +6,9 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | |||
| 10 | #include <dynarmic/interface/halt_reason.h> | ||
| 11 | |||
| 9 | #include "common/common_funcs.h" | 12 | #include "common/common_funcs.h" |
| 10 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 11 | #include "core/hardware_properties.h" | 14 | #include "core/hardware_properties.h" |
| @@ -64,7 +67,7 @@ public: | |||
| 64 | static_assert(sizeof(ThreadContext64) == 0x320); | 67 | static_assert(sizeof(ThreadContext64) == 0x320); |
| 65 | 68 | ||
| 66 | /// Runs the CPU until an event happens | 69 | /// Runs the CPU until an event happens |
| 67 | virtual void Run() = 0; | 70 | void Run(); |
| 68 | 71 | ||
| 69 | /// Clear all instruction cache | 72 | /// Clear all instruction cache |
| 70 | virtual void ClearInstructionCache() = 0; | 73 | virtual void ClearInstructionCache() = 0; |
| @@ -191,7 +194,10 @@ public: | |||
| 191 | 194 | ||
| 192 | void LogBacktrace() const; | 195 | void LogBacktrace() const; |
| 193 | 196 | ||
| 194 | bool ShouldStep() const; | 197 | static constexpr Dynarmic::HaltReason step_thread = Dynarmic::HaltReason::Step; |
| 198 | static constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2; | ||
| 199 | static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3; | ||
| 200 | static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4; | ||
| 195 | 201 | ||
| 196 | protected: | 202 | protected: |
| 197 | /// System context that this ARM interface is running under. | 203 | /// System context that this ARM interface is running under. |
| @@ -200,6 +206,10 @@ protected: | |||
| 200 | bool uses_wall_clock; | 206 | bool uses_wall_clock; |
| 201 | 207 | ||
| 202 | static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out); | 208 | static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out); |
| 209 | |||
| 210 | virtual Dynarmic::HaltReason RunJit() = 0; | ||
| 211 | virtual Dynarmic::HaltReason StepJit() = 0; | ||
| 212 | virtual u32 GetSvcNumber() const = 0; | ||
| 203 | }; | 213 | }; |
| 204 | 214 | ||
| 205 | } // namespace Core | 215 | } // namespace Core |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 894c1c527..7c82d0b96 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -26,10 +26,6 @@ namespace Core { | |||
| 26 | 26 | ||
| 27 | using namespace Common::Literals; | 27 | using namespace Common::Literals; |
| 28 | 28 | ||
| 29 | constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2; | ||
| 30 | constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3; | ||
| 31 | constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4; | ||
| 32 | |||
| 33 | class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { | 29 | class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { |
| 34 | public: | 30 | public: |
| 35 | explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) | 31 | explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) |
| @@ -82,8 +78,8 @@ public: | |||
| 82 | 78 | ||
| 83 | void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { | 79 | void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { |
| 84 | if (parent.system.DebuggerEnabled()) { | 80 | if (parent.system.DebuggerEnabled()) { |
| 85 | parent.breakpoint_pc = pc; | 81 | parent.jit.load()->Regs()[15] = pc; |
| 86 | parent.jit.load()->HaltExecution(breakpoint); | 82 | parent.jit.load()->HaltExecution(ARM_Interface::breakpoint); |
| 87 | return; | 83 | return; |
| 88 | } | 84 | } |
| 89 | 85 | ||
| @@ -95,7 +91,7 @@ public: | |||
| 95 | 91 | ||
| 96 | void CallSVC(u32 swi) override { | 92 | void CallSVC(u32 swi) override { |
| 97 | parent.svc_swi = swi; | 93 | parent.svc_swi = swi; |
| 98 | parent.jit.load()->HaltExecution(svc_call); | 94 | parent.jit.load()->HaltExecution(ARM_Interface::svc_call); |
| 99 | } | 95 | } |
| 100 | 96 | ||
| 101 | void AddTicks(u64 ticks) override { | 97 | void AddTicks(u64 ticks) override { |
| @@ -240,35 +236,16 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* | |||
| 240 | return std::make_unique<Dynarmic::A32::Jit>(config); | 236 | return std::make_unique<Dynarmic::A32::Jit>(config); |
| 241 | } | 237 | } |
| 242 | 238 | ||
| 243 | void ARM_Dynarmic_32::Run() { | 239 | Dynarmic::HaltReason ARM_Dynarmic_32::RunJit() { |
| 244 | while (true) { | 240 | return jit.load()->Run(); |
| 245 | const auto hr = ShouldStep() ? jit.load()->Step() : jit.load()->Run(); | 241 | } |
| 246 | if (Has(hr, svc_call)) { | ||
| 247 | Kernel::Svc::Call(system, svc_swi); | ||
| 248 | } | ||
| 249 | |||
| 250 | // Check to see if breakpoint is triggered. | ||
| 251 | // Recheck step condition in case stop is no longer desired. | ||
| 252 | Kernel::KThread* current_thread = system.Kernel().GetCurrentEmuThread(); | ||
| 253 | if (Has(hr, breakpoint)) { | ||
| 254 | jit.load()->Regs()[15] = breakpoint_pc; | ||
| 255 | 242 | ||
| 256 | if (system.GetDebugger().NotifyThreadStopped(current_thread)) { | 243 | Dynarmic::HaltReason ARM_Dynarmic_32::StepJit() { |
| 257 | current_thread->RequestSuspend(Kernel::SuspendType::Debug); | 244 | return jit.load()->Step(); |
| 258 | } | 245 | } |
| 259 | break; | ||
| 260 | } | ||
| 261 | if (ShouldStep()) { | ||
| 262 | // When stepping, this should be the only thread running. | ||
| 263 | ASSERT(system.GetDebugger().NotifyThreadStopped(current_thread)); | ||
| 264 | current_thread->RequestSuspend(Kernel::SuspendType::Debug); | ||
| 265 | break; | ||
| 266 | } | ||
| 267 | 246 | ||
| 268 | if (Has(hr, break_loop) || !uses_wall_clock) { | 247 | u32 ARM_Dynarmic_32::GetSvcNumber() const { |
| 269 | break; | 248 | return svc_swi; |
| 270 | } | ||
| 271 | } | ||
| 272 | } | 249 | } |
| 273 | 250 | ||
| 274 | ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, | 251 | ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 0557d5940..5b1d60005 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h | |||
| @@ -41,7 +41,6 @@ public: | |||
| 41 | void SetVectorReg(int index, u128 value) override; | 41 | void SetVectorReg(int index, u128 value) override; |
| 42 | u32 GetPSTATE() const override; | 42 | u32 GetPSTATE() const override; |
| 43 | void SetPSTATE(u32 pstate) override; | 43 | void SetPSTATE(u32 pstate) override; |
| 44 | void Run() override; | ||
| 45 | VAddr GetTlsAddress() const override; | 44 | VAddr GetTlsAddress() const override; |
| 46 | void SetTlsAddress(VAddr address) override; | 45 | void SetTlsAddress(VAddr address) override; |
| 47 | void SetTPIDR_EL0(u64 value) override; | 46 | void SetTPIDR_EL0(u64 value) override; |
| @@ -69,6 +68,11 @@ public: | |||
| 69 | 68 | ||
| 70 | std::vector<BacktraceEntry> GetBacktrace() const override; | 69 | std::vector<BacktraceEntry> GetBacktrace() const override; |
| 71 | 70 | ||
| 71 | protected: | ||
| 72 | Dynarmic::HaltReason RunJit() override; | ||
| 73 | Dynarmic::HaltReason StepJit() override; | ||
| 74 | u32 GetSvcNumber() const override; | ||
| 75 | |||
| 72 | private: | 76 | private: |
| 73 | std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; | 77 | std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; |
| 74 | 78 | ||
| @@ -94,9 +98,6 @@ private: | |||
| 94 | 98 | ||
| 95 | // SVC callback | 99 | // SVC callback |
| 96 | u32 svc_swi{}; | 100 | u32 svc_swi{}; |
| 97 | |||
| 98 | // Debug restart address | ||
| 99 | u32 breakpoint_pc{}; | ||
| 100 | }; | 101 | }; |
| 101 | 102 | ||
| 102 | } // namespace Core | 103 | } // namespace Core |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 1f596cfef..d4c67eafd 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -26,10 +26,6 @@ namespace Core { | |||
| 26 | using Vector = Dynarmic::A64::Vector; | 26 | using Vector = Dynarmic::A64::Vector; |
| 27 | using namespace Common::Literals; | 27 | using namespace Common::Literals; |
| 28 | 28 | ||
| 29 | constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2; | ||
| 30 | constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3; | ||
| 31 | constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4; | ||
| 32 | |||
| 33 | class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { | 29 | class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { |
| 34 | public: | 30 | public: |
| 35 | explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) | 31 | explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) |
| @@ -123,8 +119,8 @@ public: | |||
| 123 | return; | 119 | return; |
| 124 | default: | 120 | default: |
| 125 | if (parent.system.DebuggerEnabled()) { | 121 | if (parent.system.DebuggerEnabled()) { |
| 126 | parent.breakpoint_pc = pc; | 122 | parent.jit.load()->SetPC(pc); |
| 127 | parent.jit.load()->HaltExecution(breakpoint); | 123 | parent.jit.load()->HaltExecution(ARM_Interface::breakpoint); |
| 128 | return; | 124 | return; |
| 129 | } | 125 | } |
| 130 | 126 | ||
| @@ -136,7 +132,7 @@ public: | |||
| 136 | 132 | ||
| 137 | void CallSVC(u32 swi) override { | 133 | void CallSVC(u32 swi) override { |
| 138 | parent.svc_swi = swi; | 134 | parent.svc_swi = swi; |
| 139 | parent.jit.load()->HaltExecution(svc_call); | 135 | parent.jit.load()->HaltExecution(ARM_Interface::svc_call); |
| 140 | } | 136 | } |
| 141 | 137 | ||
| 142 | void AddTicks(u64 ticks) override { | 138 | void AddTicks(u64 ticks) override { |
| @@ -300,35 +296,16 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* | |||
| 300 | return std::make_shared<Dynarmic::A64::Jit>(config); | 296 | return std::make_shared<Dynarmic::A64::Jit>(config); |
| 301 | } | 297 | } |
| 302 | 298 | ||
| 303 | void ARM_Dynarmic_64::Run() { | 299 | Dynarmic::HaltReason ARM_Dynarmic_64::RunJit() { |
| 304 | while (true) { | 300 | return jit.load()->Run(); |
| 305 | const auto hr = jit.load()->Run(); | 301 | } |
| 306 | if (Has(hr, svc_call)) { | ||
| 307 | Kernel::Svc::Call(system, svc_swi); | ||
| 308 | } | ||
| 309 | |||
| 310 | // Check to see if breakpoint is triggered. | ||
| 311 | // Recheck step condition in case stop is no longer desired. | ||
| 312 | Kernel::KThread* current_thread = system.Kernel().GetCurrentEmuThread(); | ||
| 313 | if (Has(hr, breakpoint)) { | ||
| 314 | jit.load()->SetPC(breakpoint_pc); | ||
| 315 | 302 | ||
| 316 | if (system.GetDebugger().NotifyThreadStopped(current_thread)) { | 303 | Dynarmic::HaltReason ARM_Dynarmic_64::StepJit() { |
| 317 | current_thread->RequestSuspend(Kernel::SuspendType::Debug); | 304 | return jit.load()->Step(); |
| 318 | } | 305 | } |
| 319 | break; | ||
| 320 | } | ||
| 321 | if (ShouldStep()) { | ||
| 322 | // When stepping, this should be the only thread running. | ||
| 323 | ASSERT(system.GetDebugger().NotifyThreadStopped(current_thread)); | ||
| 324 | current_thread->RequestSuspend(Kernel::SuspendType::Debug); | ||
| 325 | break; | ||
| 326 | } | ||
| 327 | 306 | ||
| 328 | if (Has(hr, break_loop) || !uses_wall_clock) { | 307 | u32 ARM_Dynarmic_64::GetSvcNumber() const { |
| 329 | break; | 308 | return svc_swi; |
| 330 | } | ||
| 331 | } | ||
| 332 | } | 309 | } |
| 333 | 310 | ||
| 334 | ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, | 311 | ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index aa7054e0c..abfbc3c3f 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h | |||
| @@ -39,7 +39,6 @@ public: | |||
| 39 | void SetVectorReg(int index, u128 value) override; | 39 | void SetVectorReg(int index, u128 value) override; |
| 40 | u32 GetPSTATE() const override; | 40 | u32 GetPSTATE() const override; |
| 41 | void SetPSTATE(u32 pstate) override; | 41 | void SetPSTATE(u32 pstate) override; |
| 42 | void Run() override; | ||
| 43 | VAddr GetTlsAddress() const override; | 42 | VAddr GetTlsAddress() const override; |
| 44 | void SetTlsAddress(VAddr address) override; | 43 | void SetTlsAddress(VAddr address) override; |
| 45 | void SetTPIDR_EL0(u64 value) override; | 44 | void SetTPIDR_EL0(u64 value) override; |
| @@ -63,6 +62,11 @@ public: | |||
| 63 | 62 | ||
| 64 | std::vector<BacktraceEntry> GetBacktrace() const override; | 63 | std::vector<BacktraceEntry> GetBacktrace() const override; |
| 65 | 64 | ||
| 65 | protected: | ||
| 66 | Dynarmic::HaltReason RunJit() override; | ||
| 67 | Dynarmic::HaltReason StepJit() override; | ||
| 68 | u32 GetSvcNumber() const override; | ||
| 69 | |||
| 66 | private: | 70 | private: |
| 67 | std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, | 71 | std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, |
| 68 | std::size_t address_space_bits) const; | 72 | std::size_t address_space_bits) const; |
| @@ -87,9 +91,6 @@ private: | |||
| 87 | 91 | ||
| 88 | // SVC callback | 92 | // SVC callback |
| 89 | u32 svc_swi{}; | 93 | u32 svc_swi{}; |
| 90 | |||
| 91 | // Debug restart address | ||
| 92 | u64 breakpoint_pc{}; | ||
| 93 | }; | 94 | }; |
| 94 | 95 | ||
| 95 | } // namespace Core | 96 | } // namespace Core |
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index dd3e330e6..68ab33e46 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <algorithm> | ||
| 4 | #include <mutex> | 5 | #include <mutex> |
| 5 | #include <thread> | 6 | #include <thread> |
| 6 | 7 | ||
| @@ -84,31 +85,31 @@ public: | |||
| 84 | return active_thread; | 85 | return active_thread; |
| 85 | } | 86 | } |
| 86 | 87 | ||
| 87 | bool IsStepping() const { | ||
| 88 | return stepping; | ||
| 89 | } | ||
| 90 | |||
| 91 | private: | 88 | private: |
| 92 | void InitializeServer(u16 port) { | 89 | void InitializeServer(u16 port) { |
| 93 | using boost::asio::ip::tcp; | 90 | using boost::asio::ip::tcp; |
| 94 | 91 | ||
| 95 | LOG_INFO(Debug_GDBStub, "Starting server on port {}...", port); | 92 | LOG_INFO(Debug_GDBStub, "Starting server on port {}...", port); |
| 96 | 93 | ||
| 97 | // Initialize the listening socket and accept a new client. | ||
| 98 | tcp::endpoint endpoint{boost::asio::ip::address_v4::loopback(), port}; | ||
| 99 | tcp::acceptor acceptor{io_context, endpoint}; | ||
| 100 | client_socket = acceptor.accept(); | ||
| 101 | |||
| 102 | // Run the connection thread. | 94 | // Run the connection thread. |
| 103 | connection_thread = std::jthread([&](std::stop_token stop_token) { | 95 | connection_thread = std::jthread([&, port](std::stop_token stop_token) { |
| 104 | try { | 96 | try { |
| 97 | // Initialize the listening socket and accept a new client. | ||
| 98 | tcp::endpoint endpoint{boost::asio::ip::address_v4::loopback(), port}; | ||
| 99 | tcp::acceptor acceptor{io_context, endpoint}; | ||
| 100 | |||
| 101 | acceptor.async_accept(client_socket, [](const auto&) {}); | ||
| 102 | io_context.run_one(); | ||
| 103 | io_context.restart(); | ||
| 104 | |||
| 105 | if (stop_token.stop_requested()) { | ||
| 106 | return; | ||
| 107 | } | ||
| 108 | |||
| 105 | ThreadLoop(stop_token); | 109 | ThreadLoop(stop_token); |
| 106 | } catch (const std::exception& ex) { | 110 | } catch (const std::exception& ex) { |
| 107 | LOG_CRITICAL(Debug_GDBStub, "Stopping server: {}", ex.what()); | 111 | LOG_CRITICAL(Debug_GDBStub, "Stopping server: {}", ex.what()); |
| 108 | } | 112 | } |
| 109 | |||
| 110 | client_socket.shutdown(client_socket.shutdown_both); | ||
| 111 | client_socket.close(); | ||
| 112 | }); | 113 | }); |
| 113 | } | 114 | } |
| 114 | 115 | ||
| @@ -129,8 +130,7 @@ private: | |||
| 129 | AllCoreStop(); | 130 | AllCoreStop(); |
| 130 | 131 | ||
| 131 | // Set the active thread. | 132 | // Set the active thread. |
| 132 | active_thread = ThreadList()[0]; | 133 | UpdateActiveThread(); |
| 133 | active_thread->Resume(Kernel::SuspendType::Debug); | ||
| 134 | 134 | ||
| 135 | // Set up the frontend. | 135 | // Set up the frontend. |
| 136 | frontend->Connected(); | 136 | frontend->Connected(); |
| @@ -142,7 +142,7 @@ private: | |||
| 142 | 142 | ||
| 143 | void PipeData(std::span<const u8> data) { | 143 | void PipeData(std::span<const u8> data) { |
| 144 | AllCoreStop(); | 144 | AllCoreStop(); |
| 145 | active_thread->Resume(Kernel::SuspendType::Debug); | 145 | UpdateActiveThread(); |
| 146 | frontend->Stopped(active_thread); | 146 | frontend->Stopped(active_thread); |
| 147 | } | 147 | } |
| 148 | 148 | ||
| @@ -156,18 +156,22 @@ private: | |||
| 156 | stopped = true; | 156 | stopped = true; |
| 157 | } | 157 | } |
| 158 | AllCoreStop(); | 158 | AllCoreStop(); |
| 159 | active_thread = ThreadList()[0]; | 159 | UpdateActiveThread(); |
| 160 | active_thread->Resume(Kernel::SuspendType::Debug); | ||
| 161 | frontend->Stopped(active_thread); | 160 | frontend->Stopped(active_thread); |
| 162 | break; | 161 | break; |
| 163 | } | 162 | } |
| 164 | case DebuggerAction::Continue: | 163 | case DebuggerAction::Continue: |
| 165 | stepping = false; | 164 | active_thread->SetStepState(Kernel::StepState::NotStepping); |
| 166 | ResumeInactiveThreads(); | 165 | ResumeInactiveThreads(); |
| 167 | AllCoreResume(); | 166 | AllCoreResume(); |
| 168 | break; | 167 | break; |
| 169 | case DebuggerAction::StepThread: | 168 | case DebuggerAction::StepThreadUnlocked: |
| 170 | stepping = true; | 169 | active_thread->SetStepState(Kernel::StepState::StepPending); |
| 170 | ResumeInactiveThreads(); | ||
| 171 | AllCoreResume(); | ||
| 172 | break; | ||
| 173 | case DebuggerAction::StepThreadLocked: | ||
| 174 | active_thread->SetStepState(Kernel::StepState::StepPending); | ||
| 171 | SuspendInactiveThreads(); | 175 | SuspendInactiveThreads(); |
| 172 | AllCoreResume(); | 176 | AllCoreResume(); |
| 173 | break; | 177 | break; |
| @@ -212,10 +216,20 @@ private: | |||
| 212 | for (auto* thread : ThreadList()) { | 216 | for (auto* thread : ThreadList()) { |
| 213 | if (thread != active_thread) { | 217 | if (thread != active_thread) { |
| 214 | thread->Resume(Kernel::SuspendType::Debug); | 218 | thread->Resume(Kernel::SuspendType::Debug); |
| 219 | thread->SetStepState(Kernel::StepState::NotStepping); | ||
| 215 | } | 220 | } |
| 216 | } | 221 | } |
| 217 | } | 222 | } |
| 218 | 223 | ||
| 224 | void UpdateActiveThread() { | ||
| 225 | const auto& threads{ThreadList()}; | ||
| 226 | if (std::find(threads.begin(), threads.end(), active_thread) == threads.end()) { | ||
| 227 | active_thread = threads[0]; | ||
| 228 | } | ||
| 229 | active_thread->Resume(Kernel::SuspendType::Debug); | ||
| 230 | active_thread->SetStepState(Kernel::StepState::NotStepping); | ||
| 231 | } | ||
| 232 | |||
| 219 | const std::vector<Kernel::KThread*>& ThreadList() { | 233 | const std::vector<Kernel::KThread*>& ThreadList() { |
| 220 | return system.GlobalSchedulerContext().GetThreadList(); | 234 | return system.GlobalSchedulerContext().GetThreadList(); |
| 221 | } | 235 | } |
| @@ -233,7 +247,6 @@ private: | |||
| 233 | 247 | ||
| 234 | Kernel::KThread* active_thread; | 248 | Kernel::KThread* active_thread; |
| 235 | bool stopped; | 249 | bool stopped; |
| 236 | bool stepping; | ||
| 237 | 250 | ||
| 238 | std::array<u8, 4096> client_data; | 251 | std::array<u8, 4096> client_data; |
| 239 | }; | 252 | }; |
| @@ -252,8 +265,4 @@ bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) { | |||
| 252 | return impl && impl->NotifyThreadStopped(thread); | 265 | return impl && impl->NotifyThreadStopped(thread); |
| 253 | } | 266 | } |
| 254 | 267 | ||
| 255 | bool Debugger::IsStepping() const { | ||
| 256 | return impl && impl->IsStepping(); | ||
| 257 | } | ||
| 258 | |||
| 259 | } // namespace Core | 268 | } // namespace Core |
diff --git a/src/core/debugger/debugger.h b/src/core/debugger/debugger.h index 7acd11815..ea36c6ab2 100644 --- a/src/core/debugger/debugger.h +++ b/src/core/debugger/debugger.h | |||
| @@ -35,11 +35,6 @@ public: | |||
| 35 | */ | 35 | */ |
| 36 | bool NotifyThreadStopped(Kernel::KThread* thread); | 36 | bool NotifyThreadStopped(Kernel::KThread* thread); |
| 37 | 37 | ||
| 38 | /** | ||
| 39 | * Returns whether a step is in progress. | ||
| 40 | */ | ||
| 41 | bool IsStepping() const; | ||
| 42 | |||
| 43 | private: | 38 | private: |
| 44 | std::unique_ptr<DebuggerImpl> impl; | 39 | std::unique_ptr<DebuggerImpl> impl; |
| 45 | }; | 40 | }; |
diff --git a/src/core/debugger/debugger_interface.h b/src/core/debugger/debugger_interface.h index e6d4c0190..35ba0bc61 100644 --- a/src/core/debugger/debugger_interface.h +++ b/src/core/debugger/debugger_interface.h | |||
| @@ -16,10 +16,11 @@ class KThread; | |||
| 16 | namespace Core { | 16 | namespace Core { |
| 17 | 17 | ||
| 18 | enum class DebuggerAction { | 18 | enum class DebuggerAction { |
| 19 | Interrupt, // Stop emulation as soon as possible. | 19 | Interrupt, ///< Stop emulation as soon as possible. |
| 20 | Continue, // Resume emulation. | 20 | Continue, ///< Resume emulation. |
| 21 | StepThread, // Step the currently-active thread. | 21 | StepThreadLocked, ///< Step the currently-active thread without resuming others. |
| 22 | ShutdownEmulation, // Shut down the emulator. | 22 | StepThreadUnlocked, ///< Step the currently-active thread and resume others. |
| 23 | ShutdownEmulation, ///< Shut down the emulator. | ||
| 23 | }; | 24 | }; |
| 24 | 25 | ||
| 25 | class DebuggerBackend { | 26 | class DebuggerBackend { |
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index ee7598165..0c36069a6 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp | |||
| @@ -6,8 +6,7 @@ | |||
| 6 | #include <optional> | 6 | #include <optional> |
| 7 | #include <thread> | 7 | #include <thread> |
| 8 | 8 | ||
| 9 | #include <boost/asio.hpp> | 9 | #include <boost/algorithm/string.hpp> |
| 10 | #include <boost/process/async_pipe.hpp> | ||
| 11 | 10 | ||
| 12 | #include "common/hex_util.h" | 11 | #include "common/hex_util.h" |
| 13 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| @@ -114,6 +113,11 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | |||
| 114 | return; | 113 | return; |
| 115 | } | 114 | } |
| 116 | 115 | ||
| 116 | if (packet.starts_with("vCont")) { | ||
| 117 | HandleVCont(packet.substr(5), actions); | ||
| 118 | return; | ||
| 119 | } | ||
| 120 | |||
| 117 | std::string_view command{packet.substr(1, packet.size())}; | 121 | std::string_view command{packet.substr(1, packet.size())}; |
| 118 | 122 | ||
| 119 | switch (packet[0]) { | 123 | switch (packet[0]) { |
| @@ -122,6 +126,8 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | |||
| 122 | s64 thread_id{strtoll(command.data() + 1, nullptr, 16)}; | 126 | s64 thread_id{strtoll(command.data() + 1, nullptr, 16)}; |
| 123 | if (thread_id >= 1) { | 127 | if (thread_id >= 1) { |
| 124 | thread = GetThreadByID(thread_id); | 128 | thread = GetThreadByID(thread_id); |
| 129 | } else { | ||
| 130 | thread = backend.GetActiveThread(); | ||
| 125 | } | 131 | } |
| 126 | 132 | ||
| 127 | if (thread) { | 133 | if (thread) { |
| @@ -141,6 +147,7 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | |||
| 141 | } | 147 | } |
| 142 | break; | 148 | break; |
| 143 | } | 149 | } |
| 150 | case 'Q': | ||
| 144 | case 'q': | 151 | case 'q': |
| 145 | HandleQuery(command); | 152 | HandleQuery(command); |
| 146 | break; | 153 | break; |
| @@ -204,7 +211,7 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | |||
| 204 | break; | 211 | break; |
| 205 | } | 212 | } |
| 206 | case 's': | 213 | case 's': |
| 207 | actions.push_back(DebuggerAction::StepThread); | 214 | actions.push_back(DebuggerAction::StepThreadLocked); |
| 208 | break; | 215 | break; |
| 209 | case 'C': | 216 | case 'C': |
| 210 | case 'c': | 217 | case 'c': |
| @@ -248,12 +255,47 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | |||
| 248 | } | 255 | } |
| 249 | } | 256 | } |
| 250 | 257 | ||
| 258 | static std::string_view GetThreadWaitReason(const Kernel::KThread* thread) { | ||
| 259 | switch (thread->GetWaitReasonForDebugging()) { | ||
| 260 | case Kernel::ThreadWaitReasonForDebugging::Sleep: | ||
| 261 | return "Sleep"; | ||
| 262 | case Kernel::ThreadWaitReasonForDebugging::IPC: | ||
| 263 | return "IPC"; | ||
| 264 | case Kernel::ThreadWaitReasonForDebugging::Synchronization: | ||
| 265 | return "Synchronization"; | ||
| 266 | case Kernel::ThreadWaitReasonForDebugging::ConditionVar: | ||
| 267 | return "ConditionVar"; | ||
| 268 | case Kernel::ThreadWaitReasonForDebugging::Arbitration: | ||
| 269 | return "Arbitration"; | ||
| 270 | case Kernel::ThreadWaitReasonForDebugging::Suspended: | ||
| 271 | return "Suspended"; | ||
| 272 | default: | ||
| 273 | return "Unknown"; | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | static std::string GetThreadState(const Kernel::KThread* thread) { | ||
| 278 | switch (thread->GetState()) { | ||
| 279 | case Kernel::ThreadState::Initialized: | ||
| 280 | return "Initialized"; | ||
| 281 | case Kernel::ThreadState::Waiting: | ||
| 282 | return fmt::format("Waiting ({})", GetThreadWaitReason(thread)); | ||
| 283 | case Kernel::ThreadState::Runnable: | ||
| 284 | return "Runnable"; | ||
| 285 | case Kernel::ThreadState::Terminated: | ||
| 286 | return "Terminated"; | ||
| 287 | default: | ||
| 288 | return "Unknown"; | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 251 | void GDBStub::HandleQuery(std::string_view command) { | 292 | void GDBStub::HandleQuery(std::string_view command) { |
| 252 | if (command.starts_with("TStatus")) { | 293 | if (command.starts_with("TStatus")) { |
| 253 | // no tracepoint support | 294 | // no tracepoint support |
| 254 | SendReply("T0"); | 295 | SendReply("T0"); |
| 255 | } else if (command.starts_with("Supported")) { | 296 | } else if (command.starts_with("Supported")) { |
| 256 | SendReply("PacketSize=4000;qXfer:features:read+;qXfer:threads:read+;qXfer:libraries:read+"); | 297 | SendReply("PacketSize=4000;qXfer:features:read+;qXfer:threads:read+;qXfer:libraries:read+;" |
| 298 | "vContSupported+;QStartNoAckMode+"); | ||
| 257 | } else if (command.starts_with("Xfer:features:read:target.xml:")) { | 299 | } else if (command.starts_with("Xfer:features:read:target.xml:")) { |
| 258 | const auto offset{command.substr(30)}; | 300 | const auto offset{command.substr(30)}; |
| 259 | const auto amount{command.substr(command.find(',') + 1)}; | 301 | const auto amount{command.substr(command.find(',') + 1)}; |
| @@ -297,18 +339,57 @@ void GDBStub::HandleQuery(std::string_view command) { | |||
| 297 | 339 | ||
| 298 | const auto& threads = system.GlobalSchedulerContext().GetThreadList(); | 340 | const auto& threads = system.GlobalSchedulerContext().GetThreadList(); |
| 299 | for (const auto& thread : threads) { | 341 | for (const auto& thread : threads) { |
| 300 | buffer += | 342 | buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="Thread {:d}">{}</thread>)", |
| 301 | fmt::format(R"(<thread id="{:x}" core="{:d}" name="Thread {:d}"/>)", | 343 | thread->GetThreadID(), thread->GetActiveCore(), |
| 302 | thread->GetThreadID(), thread->GetActiveCore(), thread->GetThreadID()); | 344 | thread->GetThreadID(), GetThreadState(thread)); |
| 303 | } | 345 | } |
| 304 | 346 | ||
| 305 | buffer += "</threads>"; | 347 | buffer += "</threads>"; |
| 306 | SendReply(buffer); | 348 | SendReply(buffer); |
| 349 | } else if (command.starts_with("Attached")) { | ||
| 350 | SendReply("0"); | ||
| 351 | } else if (command.starts_with("StartNoAckMode")) { | ||
| 352 | no_ack = true; | ||
| 353 | SendReply(GDB_STUB_REPLY_OK); | ||
| 307 | } else { | 354 | } else { |
| 308 | SendReply(GDB_STUB_REPLY_EMPTY); | 355 | SendReply(GDB_STUB_REPLY_EMPTY); |
| 309 | } | 356 | } |
| 310 | } | 357 | } |
| 311 | 358 | ||
| 359 | void GDBStub::HandleVCont(std::string_view command, std::vector<DebuggerAction>& actions) { | ||
| 360 | if (command == "?") { | ||
| 361 | // Continuing and stepping are supported | ||
| 362 | // (signal is ignored, but required for GDB to use vCont) | ||
| 363 | SendReply("vCont;c;C;s;S"); | ||
| 364 | return; | ||
| 365 | } | ||
| 366 | |||
| 367 | Kernel::KThread* stepped_thread{nullptr}; | ||
| 368 | bool lock_execution{true}; | ||
| 369 | |||
| 370 | std::vector<std::string> entries; | ||
| 371 | boost::split(entries, command.substr(1), boost::is_any_of(";")); | ||
| 372 | for (const auto& thread_action : entries) { | ||
| 373 | std::vector<std::string> parts; | ||
| 374 | boost::split(parts, thread_action, boost::is_any_of(":")); | ||
| 375 | |||
| 376 | if (parts.size() == 1 && (parts[0] == "c" || parts[0].starts_with("C"))) { | ||
| 377 | lock_execution = false; | ||
| 378 | } | ||
| 379 | if (parts.size() == 2 && (parts[0] == "s" || parts[0].starts_with("S"))) { | ||
| 380 | stepped_thread = GetThreadByID(strtoll(parts[1].data(), nullptr, 16)); | ||
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 | if (stepped_thread) { | ||
| 385 | backend.SetActiveThread(stepped_thread); | ||
| 386 | actions.push_back(lock_execution ? DebuggerAction::StepThreadLocked | ||
| 387 | : DebuggerAction::StepThreadUnlocked); | ||
| 388 | } else { | ||
| 389 | actions.push_back(DebuggerAction::Continue); | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 312 | Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { | 393 | Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { |
| 313 | const auto& threads{system.GlobalSchedulerContext().GetThreadList()}; | 394 | const auto& threads{system.GlobalSchedulerContext().GetThreadList()}; |
| 314 | for (auto* thread : threads) { | 395 | for (auto* thread : threads) { |
| @@ -374,6 +455,10 @@ void GDBStub::SendReply(std::string_view data) { | |||
| 374 | } | 455 | } |
| 375 | 456 | ||
| 376 | void GDBStub::SendStatus(char status) { | 457 | void GDBStub::SendStatus(char status) { |
| 458 | if (no_ack) { | ||
| 459 | return; | ||
| 460 | } | ||
| 461 | |||
| 377 | std::array<u8, 1> buf = {static_cast<u8>(status)}; | 462 | std::array<u8, 1> buf = {static_cast<u8>(status)}; |
| 378 | LOG_TRACE(Debug_GDBStub, "Writing status: {}", status); | 463 | LOG_TRACE(Debug_GDBStub, "Writing status: {}", status); |
| 379 | backend.WriteToClient(buf); | 464 | backend.WriteToClient(buf); |
diff --git a/src/core/debugger/gdbstub.h b/src/core/debugger/gdbstub.h index e58d60719..aa1f7de6c 100644 --- a/src/core/debugger/gdbstub.h +++ b/src/core/debugger/gdbstub.h | |||
| @@ -28,6 +28,7 @@ public: | |||
| 28 | private: | 28 | private: |
| 29 | void ProcessData(std::vector<DebuggerAction>& actions); | 29 | void ProcessData(std::vector<DebuggerAction>& actions); |
| 30 | void ExecuteCommand(std::string_view packet, std::vector<DebuggerAction>& actions); | 30 | void ExecuteCommand(std::string_view packet, std::vector<DebuggerAction>& actions); |
| 31 | void HandleVCont(std::string_view command, std::vector<DebuggerAction>& actions); | ||
| 31 | void HandleQuery(std::string_view command); | 32 | void HandleQuery(std::string_view command); |
| 32 | std::vector<char>::const_iterator CommandEnd() const; | 33 | std::vector<char>::const_iterator CommandEnd() const; |
| 33 | std::optional<std::string> DetachCommand(); | 34 | std::optional<std::string> DetachCommand(); |
| @@ -42,6 +43,7 @@ private: | |||
| 42 | std::unique_ptr<GDBStubArch> arch; | 43 | std::unique_ptr<GDBStubArch> arch; |
| 43 | std::vector<char> current_command; | 44 | std::vector<char> current_command; |
| 44 | std::map<VAddr, u32> replaced_instructions; | 45 | std::map<VAddr, u32> replaced_instructions; |
| 46 | bool no_ack{}; | ||
| 45 | }; | 47 | }; |
| 46 | 48 | ||
| 47 | } // namespace Core | 49 | } // namespace Core |
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index b55a922ab..60ae0da78 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -100,6 +100,12 @@ enum class ThreadWaitReasonForDebugging : u32 { | |||
| 100 | Suspended, ///< Thread is waiting due to process suspension | 100 | Suspended, ///< Thread is waiting due to process suspension |
| 101 | }; | 101 | }; |
| 102 | 102 | ||
| 103 | enum class StepState : u32 { | ||
| 104 | NotStepping, ///< Thread is not currently stepping | ||
| 105 | StepPending, ///< Thread will step when next scheduled | ||
| 106 | StepPerformed, ///< Thread has stepped, waiting to be scheduled again | ||
| 107 | }; | ||
| 108 | |||
| 103 | [[nodiscard]] KThread* GetCurrentThreadPointer(KernelCore& kernel); | 109 | [[nodiscard]] KThread* GetCurrentThreadPointer(KernelCore& kernel); |
| 104 | [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); | 110 | [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); |
| 105 | [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); | 111 | [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); |
| @@ -267,6 +273,14 @@ public: | |||
| 267 | 273 | ||
| 268 | void SetState(ThreadState state); | 274 | void SetState(ThreadState state); |
| 269 | 275 | ||
| 276 | [[nodiscard]] StepState GetStepState() const { | ||
| 277 | return step_state; | ||
| 278 | } | ||
| 279 | |||
| 280 | void SetStepState(StepState state) { | ||
| 281 | step_state = state; | ||
| 282 | } | ||
| 283 | |||
| 270 | [[nodiscard]] s64 GetLastScheduledTick() const { | 284 | [[nodiscard]] s64 GetLastScheduledTick() const { |
| 271 | return last_scheduled_tick; | 285 | return last_scheduled_tick; |
| 272 | } | 286 | } |
| @@ -769,6 +783,7 @@ private: | |||
| 769 | std::shared_ptr<Common::Fiber> host_context{}; | 783 | std::shared_ptr<Common::Fiber> host_context{}; |
| 770 | bool is_single_core{}; | 784 | bool is_single_core{}; |
| 771 | ThreadType thread_type{}; | 785 | ThreadType thread_type{}; |
| 786 | StepState step_state{}; | ||
| 772 | std::mutex dummy_wait_lock; | 787 | std::mutex dummy_wait_lock; |
| 773 | std::condition_variable dummy_wait_cv; | 788 | std::condition_variable dummy_wait_cv; |
| 774 | 789 | ||
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 6a6325e38..256695804 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -277,3 +277,7 @@ else() | |||
| 277 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> | 277 | $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> |
| 278 | ) | 278 | ) |
| 279 | endif() | 279 | endif() |
| 280 | |||
| 281 | if (ARCHITECTURE_x86_64) | ||
| 282 | target_link_libraries(video_core PRIVATE dynarmic) | ||
| 283 | endif() | ||
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 404acdd05..07df9675d 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -319,3 +319,7 @@ endif() | |||
| 319 | if (NOT APPLE) | 319 | if (NOT APPLE) |
| 320 | target_compile_definitions(yuzu PRIVATE HAS_OPENGL) | 320 | target_compile_definitions(yuzu PRIVATE HAS_OPENGL) |
| 321 | endif() | 321 | endif() |
| 322 | |||
| 323 | if (ARCHITECTURE_x86_64) | ||
| 324 | target_link_libraries(yuzu PRIVATE dynarmic) | ||
| 325 | endif() | ||