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/hle/kernel | |
| 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/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/k_process.cpp | 46 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_process.h | 30 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_scheduler.cpp | 1 |
3 files changed, 77 insertions, 0 deletions
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index cd863e715..6a73f6783 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -584,6 +584,52 @@ ResultCode KProcess::DeleteThreadLocalRegion(VAddr addr) { | |||
| 584 | return ResultSuccess; | 584 | return ResultSuccess; |
| 585 | } | 585 | } |
| 586 | 586 | ||
| 587 | bool KProcess::InsertWatchpoint(Core::System& system, VAddr addr, u64 size, | ||
| 588 | DebugWatchpointType type) { | ||
| 589 | const auto watch{std::find_if(watchpoints.begin(), watchpoints.end(), [&](const auto& wp) { | ||
| 590 | return wp.type == DebugWatchpointType::None; | ||
| 591 | })}; | ||
| 592 | |||
| 593 | if (watch == watchpoints.end()) { | ||
| 594 | return false; | ||
| 595 | } | ||
| 596 | |||
| 597 | watch->start_address = addr; | ||
| 598 | watch->end_address = addr + size; | ||
| 599 | watch->type = type; | ||
| 600 | |||
| 601 | for (VAddr page = Common::AlignDown(addr, PageSize); page < addr + size; page += PageSize) { | ||
| 602 | debug_page_refcounts[page]++; | ||
| 603 | system.Memory().MarkRegionDebug(page, PageSize, true); | ||
| 604 | } | ||
| 605 | |||
| 606 | return true; | ||
| 607 | } | ||
| 608 | |||
| 609 | bool KProcess::RemoveWatchpoint(Core::System& system, VAddr addr, u64 size, | ||
| 610 | DebugWatchpointType type) { | ||
| 611 | const auto watch{std::find_if(watchpoints.begin(), watchpoints.end(), [&](const auto& wp) { | ||
| 612 | return wp.start_address == addr && wp.end_address == addr + size && wp.type == type; | ||
| 613 | })}; | ||
| 614 | |||
| 615 | if (watch == watchpoints.end()) { | ||
| 616 | return false; | ||
| 617 | } | ||
| 618 | |||
| 619 | watch->start_address = 0; | ||
| 620 | watch->end_address = 0; | ||
| 621 | watch->type = DebugWatchpointType::None; | ||
| 622 | |||
| 623 | for (VAddr page = Common::AlignDown(addr, PageSize); page < addr + size; page += PageSize) { | ||
| 624 | debug_page_refcounts[page]--; | ||
| 625 | if (!debug_page_refcounts[page]) { | ||
| 626 | system.Memory().MarkRegionDebug(page, PageSize, false); | ||
| 627 | } | ||
| 628 | } | ||
| 629 | |||
| 630 | return true; | ||
| 631 | } | ||
| 632 | |||
| 587 | void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) { | 633 | void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) { |
| 588 | const auto ReprotectSegment = [&](const CodeSet::Segment& segment, | 634 | const auto ReprotectSegment = [&](const CodeSet::Segment& segment, |
| 589 | Svc::MemoryPermission permission) { | 635 | Svc::MemoryPermission permission) { |
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index e562a79b8..c2086e5ba 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <cstddef> | 8 | #include <cstddef> |
| 9 | #include <list> | 9 | #include <list> |
| 10 | #include <map> | ||
| 10 | #include <string> | 11 | #include <string> |
| 11 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 12 | #include "core/hle/kernel/k_address_arbiter.h" | 13 | #include "core/hle/kernel/k_address_arbiter.h" |
| @@ -68,6 +69,20 @@ enum class ProcessActivity : u32 { | |||
| 68 | Paused, | 69 | Paused, |
| 69 | }; | 70 | }; |
| 70 | 71 | ||
| 72 | enum class DebugWatchpointType : u8 { | ||
| 73 | None = 0, | ||
| 74 | Read = 1 << 0, | ||
| 75 | Write = 1 << 1, | ||
| 76 | ReadOrWrite = Read | Write, | ||
| 77 | }; | ||
| 78 | DECLARE_ENUM_FLAG_OPERATORS(DebugWatchpointType); | ||
| 79 | |||
| 80 | struct DebugWatchpoint { | ||
| 81 | VAddr start_address; | ||
| 82 | VAddr end_address; | ||
| 83 | DebugWatchpointType type; | ||
| 84 | }; | ||
| 85 | |||
| 71 | class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> { | 86 | class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> { |
| 72 | KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject); | 87 | KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject); |
| 73 | 88 | ||
| @@ -374,6 +389,19 @@ public: | |||
| 374 | // Frees a used TLS slot identified by the given address | 389 | // Frees a used TLS slot identified by the given address |
| 375 | ResultCode DeleteThreadLocalRegion(VAddr addr); | 390 | ResultCode DeleteThreadLocalRegion(VAddr addr); |
| 376 | 391 | ||
| 392 | /////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 393 | // Debug watchpoint management | ||
| 394 | |||
| 395 | // Attempts to insert a watchpoint into a free slot. Returns false if none are available. | ||
| 396 | bool InsertWatchpoint(Core::System& system, VAddr addr, u64 size, DebugWatchpointType type); | ||
| 397 | |||
| 398 | // Attempts to remove the watchpoint specified by the given parameters. | ||
| 399 | bool RemoveWatchpoint(Core::System& system, VAddr addr, u64 size, DebugWatchpointType type); | ||
| 400 | |||
| 401 | const std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>& GetWatchpoints() const { | ||
| 402 | return watchpoints; | ||
| 403 | } | ||
| 404 | |||
| 377 | private: | 405 | private: |
| 378 | void PinThread(s32 core_id, KThread* thread) { | 406 | void PinThread(s32 core_id, KThread* thread) { |
| 379 | ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES)); | 407 | ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES)); |
| @@ -478,6 +506,8 @@ private: | |||
| 478 | std::array<KThread*, Core::Hardware::NUM_CPU_CORES> running_threads{}; | 506 | std::array<KThread*, Core::Hardware::NUM_CPU_CORES> running_threads{}; |
| 479 | std::array<u64, Core::Hardware::NUM_CPU_CORES> running_thread_idle_counts{}; | 507 | std::array<u64, Core::Hardware::NUM_CPU_CORES> running_thread_idle_counts{}; |
| 480 | std::array<KThread*, Core::Hardware::NUM_CPU_CORES> pinned_threads{}; | 508 | std::array<KThread*, Core::Hardware::NUM_CPU_CORES> pinned_threads{}; |
| 509 | std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS> watchpoints{}; | ||
| 510 | std::map<VAddr, u64> debug_page_refcounts; | ||
| 481 | 511 | ||
| 482 | KThread* exception_thread{}; | 512 | KThread* exception_thread{}; |
| 483 | 513 | ||
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 2d4e8637b..edd0e4eae 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp | |||
| @@ -710,6 +710,7 @@ void KScheduler::Reload(KThread* thread) { | |||
| 710 | Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); | 710 | Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); |
| 711 | cpu_core.LoadContext(thread->GetContext32()); | 711 | cpu_core.LoadContext(thread->GetContext32()); |
| 712 | cpu_core.LoadContext(thread->GetContext64()); | 712 | cpu_core.LoadContext(thread->GetContext64()); |
| 713 | cpu_core.LoadWatchpointArray(thread->GetOwnerProcess()->GetWatchpoints()); | ||
| 713 | cpu_core.SetTlsAddress(thread->GetTLSAddress()); | 714 | cpu_core.SetTlsAddress(thread->GetTLSAddress()); |
| 714 | cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); | 715 | cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); |
| 715 | cpu_core.ClearExclusiveState(); | 716 | cpu_core.ClearExclusiveState(); |