https://github.com/omjavaid updated https://github.com/llvm/llvm-project/pull/108072
>From 82ee1429a0fcf67aa36bf6ca7debb5518211d16c Mon Sep 17 00:00:00 2001 From: Muhammad Omair Javaid <omair.jav...@linaro.org> Date: Tue, 10 Sep 2024 18:03:29 +0500 Subject: [PATCH 1/7] WoA hardware breakpoint/watchpoint support --- .../Windows/Common/NativeProcessWindows.cpp | 52 ++++++++--- .../Common/NativeRegisterContextWindows.cpp | 3 - .../Common/NativeRegisterContextWindows.h | 6 +- .../NativeRegisterContextWindows_WoW64.cpp | 4 +- .../NativeRegisterContextWindows_arm.cpp | 4 +- .../NativeRegisterContextWindows_arm64.cpp | 86 ++++++++++--------- .../NativeRegisterContextWindows_arm64.h | 32 ++----- .../NativeRegisterContextWindows_i386.cpp | 4 +- .../NativeRegisterContextWindows_x86_64.cpp | 4 +- .../Windows/Common/NativeThreadWindows.cpp | 32 +++++++ 10 files changed, 135 insertions(+), 92 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index 9c330ff1186709..f38f6e32fcd90d 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -491,24 +491,47 @@ NativeProcessWindows::OnDebugException(bool first_chance, return ExceptionResult::MaskException; } case DWORD(STATUS_BREAKPOINT): - case STATUS_WX86_BREAKPOINT: - if (FindSoftwareBreakpoint(record.GetExceptionAddress())) { - LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.", - record.GetExceptionAddress()); - - StopThread(record.GetThreadID(), StopReason::eStopReasonBreakpoint); - - if (NativeThreadWindows *stop_thread = - GetThreadByID(record.GetThreadID())) { - auto ®ister_context = stop_thread->GetRegisterContext(); + case STATUS_WX86_BREAKPOINT: { + bool breakpoint_hit = false; + NativeThreadWindows *stop_thread = GetThreadByID(record.GetThreadID()); + + if (stop_thread) { + uint32_t hw_id = LLDB_INVALID_INDEX32; + auto ®_ctx = stop_thread->GetRegisterContext(); + reg_ctx.GetHardwareBreakHitIndex(hw_id, record.GetExceptionAddress()); + if (hw_id != LLDB_INVALID_INDEX32) { + breakpoint_hit = true; + LLDB_LOG(log, "Hit hardware breakpoint at address {0:x}.", + record.GetExceptionAddress()); + } else if (FindSoftwareBreakpoint(record.GetExceptionAddress())) { + breakpoint_hit = true; + LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.", + record.GetExceptionAddress()); uint32_t breakpoint_size = GetSoftwareBreakpointPCOffset(); // The current PC is AFTER the BP opcode, on all architectures. - uint64_t pc = register_context.GetPC() - breakpoint_size; - register_context.SetPC(pc); + uint64_t pc = reg_ctx.GetPC() - breakpoint_size; + reg_ctx.SetPC(pc); } - SetState(eStateStopped, true); - return ExceptionResult::MaskException; + if (breakpoint_hit) { + StopThread(record.GetThreadID(), StopReason::eStopReasonBreakpoint); + SetState(eStateStopped, true); + return ExceptionResult::MaskException; + } else { + const std::vector<ULONG_PTR> &args = record.GetExceptionArguments(); + if (args.size() >= 2) { + reg_ctx.GetWatchpointHitIndex(hw_id, args[1]); + if (hw_id != LLDB_INVALID_INDEX32) { + addr_t wp_pc = record.GetExceptionAddress(); + std::string desc = + formatv("{0} {1} {2}", args[1], hw_id, wp_pc).str(); + StopThread(record.GetThreadID(), StopReason::eStopReasonWatchpoint, + desc); + SetState(eStateStopped, true); + return ExceptionResult::MaskException; + } + } + } } if (!initial_stop) { @@ -531,6 +554,7 @@ NativeProcessWindows::OnDebugException(bool first_chance, // Hit the initial stop. Continue the application. return ExceptionResult::BreakInDebugger; } + } [[fallthrough]]; default: diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.cpp index 9128363eaa577a..95be1183abb759 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.cpp @@ -18,9 +18,6 @@ using namespace lldb; using namespace lldb_private; -NativeRegisterContextWindows::NativeRegisterContextWindows( - NativeThreadProtocol &thread, RegisterInfoInterface *reg_info_interface_p) - : NativeRegisterContextRegisterInfo(thread, reg_info_interface_p) {} lldb::thread_t NativeRegisterContextWindows::GetThreadHandle() const { auto wthread = static_cast<NativeThreadWindows *>(&m_thread); diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.h index 841b8547f3e904..d00595251f41de 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.h @@ -17,11 +17,9 @@ namespace lldb_private { class NativeThreadWindows; -class NativeRegisterContextWindows : public NativeRegisterContextRegisterInfo { +class NativeRegisterContextWindows + : public virtual NativeRegisterContextRegisterInfo { public: - NativeRegisterContextWindows( - NativeThreadProtocol &native_thread, - RegisterInfoInterface *reg_info_interface_p); static std::unique_ptr<NativeRegisterContextWindows> CreateHostNativeRegisterContextWindows(const ArchSpec &target_arch, diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_WoW64.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_WoW64.cpp index a9642d1c5e48da..069c327ee2f9a6 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_WoW64.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_WoW64.cpp @@ -88,8 +88,8 @@ static Status SetWoW64ThreadContextHelper(lldb::thread_t thread_handle, NativeRegisterContextWindows_WoW64::NativeRegisterContextWindows_WoW64( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextWindows(native_thread, - CreateRegisterInfoInterface(target_arch)) {} + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)) {} bool NativeRegisterContextWindows_WoW64::IsGPR(uint32_t reg_index) const { return (reg_index >= k_first_gpr_i386 && reg_index < k_first_alias_i386); diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm.cpp index 4209fdf3c7109a..fd8a0c05c1b25c 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm.cpp @@ -128,8 +128,8 @@ NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows( NativeRegisterContextWindows_arm::NativeRegisterContextWindows_arm( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextWindows(native_thread, - CreateRegisterInfoInterface(target_arch)) {} + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)) {} bool NativeRegisterContextWindows_arm::IsGPR(uint32_t reg_index) const { return (reg_index >= k_first_gpr_arm && reg_index <= k_last_gpr_arm); diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp index 080a9140e36a64..547ddcc4035d46 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp @@ -10,7 +10,6 @@ #include "NativeRegisterContextWindows_arm64.h" #include "NativeThreadWindows.h" -#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" #include "ProcessWindowsLog.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/HostThread.h" @@ -143,8 +142,14 @@ NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows( NativeRegisterContextWindows_arm64::NativeRegisterContextWindows_arm64( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextWindows(native_thread, - CreateRegisterInfoInterface(target_arch)) {} + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)) { + // Currently, there is no API to query the maximum supported hardware + // breakpoints and watchpoints on Windows. The values set below are based + // on tests conducted on Windows 11 with Snapdragon Elite X hardware. + m_max_hwp_supported = 1; + m_max_hbp_supported = 6; +} bool NativeRegisterContextWindows_arm64::IsGPR(uint32_t reg_index) const { return (reg_index >= k_first_gpr_arm64 && reg_index <= k_last_gpr_arm64); @@ -709,48 +714,49 @@ Status NativeRegisterContextWindows_arm64::WriteAllRegisterValues( return SetThreadContextHelper(GetThreadHandle(), &tls_context); } -Status NativeRegisterContextWindows_arm64::IsWatchpointHit(uint32_t wp_index, - bool &is_hit) { - return Status::FromErrorString("unimplemented"); -} - -Status NativeRegisterContextWindows_arm64::GetWatchpointHitIndex( - uint32_t &wp_index, lldb::addr_t trap_addr) { - return Status::FromErrorString("unimplemented"); -} - -Status NativeRegisterContextWindows_arm64::IsWatchpointVacant(uint32_t wp_index, - bool &is_vacant) { - return Status::FromErrorString("unimplemented"); -} - -Status NativeRegisterContextWindows_arm64::SetHardwareWatchpointWithIndex( - lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { - return Status::FromErrorString("unimplemented"); -} - -bool NativeRegisterContextWindows_arm64::ClearHardwareWatchpoint( - uint32_t wp_index) { - return false; -} +llvm::Error NativeRegisterContextWindows_arm64::ReadHardwareDebugInfo() { + ::CONTEXT tls_context; + Status error = GetThreadContextHelper(GetThreadHandle(), &tls_context, + CONTEXT_DEBUG_REGISTERS); + if (error.Fail()) + return error.ToError(); -Status NativeRegisterContextWindows_arm64::ClearAllHardwareWatchpoints() { - return Status::FromErrorString("unimplemented"); -} + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + m_hwp_regs[i].address = tls_context.Wvr[i]; + m_hwp_regs[i].control = tls_context.Wcr[i]; + } -uint32_t NativeRegisterContextWindows_arm64::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - return LLDB_INVALID_INDEX32; + for (uint32_t i = 0; i < m_max_hbp_supported; i++) { + m_hbp_regs[i].address = tls_context.Bvr[i]; + m_hbp_regs[i].control = tls_context.Bcr[i]; + } + return llvm::Error::success(); } -lldb::addr_t -NativeRegisterContextWindows_arm64::GetWatchpointAddress(uint32_t wp_index) { - return LLDB_INVALID_ADDRESS; -} +llvm::Error +NativeRegisterContextWindows_arm64::WriteHardwareDebugRegs(DREGType hwbType) { + ::CONTEXT tls_context; + Status error = GetThreadContextHelper(GetThreadHandle(), &tls_context, + CONTEXT_DEBUG_REGISTERS); + if (error.Fail()) + return error.ToError(); + + switch (hwbType) { + case eDREGTypeWATCH: + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + tls_context.Wvr[i] = m_hwp_regs[i].address; + tls_context.Wcr[i] = m_hwp_regs[i].control; + } + break; + case eDREGTypeBREAK: + for (uint32_t i = 0; i < m_max_hbp_supported; i++) { + tls_context.Bvr[i] = m_hbp_regs[i].address; + tls_context.Bcr[i] = m_hbp_regs[i].control; + } + break; + } -uint32_t NativeRegisterContextWindows_arm64::NumSupportedHardwareWatchpoints() { - // Not implemented - return 0; + return SetThreadContextHelper(GetThreadHandle(), &tls_context).ToError(); } #endif // defined(__aarch64__) || defined(_M_ARM64) diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.h b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.h index 88afc1e7b18a2f..e73a6af4cbf805 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.h +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.h @@ -10,6 +10,8 @@ #ifndef liblldb_NativeRegisterContextWindows_arm64_h_ #define liblldb_NativeRegisterContextWindows_arm64_h_ +#include "Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" #include "Plugins/Process/Utility/lldb-arm64-register-enums.h" #include "NativeRegisterContextWindows.h" @@ -18,7 +20,9 @@ namespace lldb_private { class NativeThreadWindows; -class NativeRegisterContextWindows_arm64 : public NativeRegisterContextWindows { +class NativeRegisterContextWindows_arm64 + : public NativeRegisterContextWindows, + public NativeRegisterContextDBReg_arm64 { public: NativeRegisterContextWindows_arm64(const ArchSpec &target_arch, NativeThreadProtocol &native_thread); @@ -37,28 +41,6 @@ class NativeRegisterContextWindows_arm64 : public NativeRegisterContextWindows { Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override; - - Status GetWatchpointHitIndex(uint32_t &wp_index, - lldb::addr_t trap_addr) override; - - Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override; - - bool ClearHardwareWatchpoint(uint32_t wp_index) override; - - Status ClearAllHardwareWatchpoints() override; - - Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, - uint32_t watch_flags, - uint32_t wp_index); - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags) override; - - lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; - - uint32_t NumSupportedHardwareWatchpoints() override; - protected: Status GPRRead(const uint32_t reg, RegisterValue ®_value); @@ -72,6 +54,10 @@ class NativeRegisterContextWindows_arm64 : public NativeRegisterContextWindows { bool IsGPR(uint32_t reg_index) const; bool IsFPR(uint32_t reg_index) const; + + llvm::Error ReadHardwareDebugInfo() override; + + llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_i386.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_i386.cpp index 53df9866793946..7c13759df462da 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_i386.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_i386.cpp @@ -92,8 +92,8 @@ NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows( NativeRegisterContextWindows_i386::NativeRegisterContextWindows_i386( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextWindows(native_thread, - CreateRegisterInfoInterface(target_arch)) {} + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)) {} bool NativeRegisterContextWindows_i386::IsGPR(uint32_t reg_index) const { return (reg_index < k_first_alias_i386); diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_x86_64.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_x86_64.cpp index 4c59273b845aaa..c54c31e48e4e5f 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_x86_64.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_x86_64.cpp @@ -110,8 +110,8 @@ NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows( NativeRegisterContextWindows_x86_64::NativeRegisterContextWindows_x86_64( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextWindows(native_thread, - CreateRegisterInfoInterface(target_arch)) {} + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)) {} bool NativeRegisterContextWindows_x86_64::IsGPR(uint32_t reg_index) const { return (reg_index >= k_first_gpr_x86_64 && reg_index < k_first_alias_x86_64); diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp index 8ad59cd1ece887..cade9c09ffb192 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp @@ -178,9 +178,41 @@ Status NativeThreadWindows::RemoveWatchpoint(lldb::addr_t addr) { Status NativeThreadWindows::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) { +#if defined(__aarch64__) || defined(_M_ARM64) + if (m_state == eStateLaunching) + return Status(); + + Status error = RemoveHardwareBreakpoint(addr); + if (error.Fail()) + return error; + + uint32_t bp_index = m_reg_context_up->SetHardwareBreakpoint(addr, size); + + if (bp_index == LLDB_INVALID_INDEX32) + return Status::FromErrorString("Setting hardware breakpoint failed."); + + m_hw_breakpoint_index_map.insert({addr, bp_index}); + + return Status(); +#else return Status::FromErrorString("unimplemented."); +#endif } Status NativeThreadWindows::RemoveHardwareBreakpoint(lldb::addr_t addr) { +#if defined(__aarch64__) || defined(_M_ARM64) + auto bp = m_hw_breakpoint_index_map.find(addr); + if (bp == m_hw_breakpoint_index_map.end()) + return Status(); + + uint32_t bp_index = bp->second; + if (m_reg_context_up->ClearHardwareBreakpoint(bp_index)) { + m_hw_breakpoint_index_map.erase(bp); + return Status(); + } + + return Status::FromErrorString("Clearing hardware breakpoint failed."); +#else return Status::FromErrorString("unimplemented."); +#endif } >From 5d5e56364bf420261b01ac06fd4854378ffc41ea Mon Sep 17 00:00:00 2001 From: Muhammad Omair Javaid <omair.jav...@linaro.org> Date: Wed, 9 Oct 2024 12:29:39 +0500 Subject: [PATCH 2/7] Remove HW breakpoint support --- .../Windows/Common/NativeProcessWindows.cpp | 39 +++++++------------ .../NativeRegisterContextWindows_arm64.cpp | 18 ++------- .../Windows/Common/NativeThreadWindows.cpp | 32 --------------- 3 files changed, 17 insertions(+), 72 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index f38f6e32fcd90d..063872c229b43b 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -491,42 +491,32 @@ NativeProcessWindows::OnDebugException(bool first_chance, return ExceptionResult::MaskException; } case DWORD(STATUS_BREAKPOINT): - case STATUS_WX86_BREAKPOINT: { - bool breakpoint_hit = false; - NativeThreadWindows *stop_thread = GetThreadByID(record.GetThreadID()); + case STATUS_WX86_BREAKPOINT: - if (stop_thread) { - uint32_t hw_id = LLDB_INVALID_INDEX32; + if (NativeThreadWindows *stop_thread = + GetThreadByID(record.GetThreadID())) { auto ®_ctx = stop_thread->GetRegisterContext(); - reg_ctx.GetHardwareBreakHitIndex(hw_id, record.GetExceptionAddress()); - if (hw_id != LLDB_INVALID_INDEX32) { - breakpoint_hit = true; - LLDB_LOG(log, "Hit hardware breakpoint at address {0:x}.", - record.GetExceptionAddress()); - } else if (FindSoftwareBreakpoint(record.GetExceptionAddress())) { - breakpoint_hit = true; + const auto exception_addr = record.GetExceptionAddress(); + const auto thread_id = record.GetThreadID(); + + if (FindSoftwareBreakpoint(exception_addr)) { LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.", - record.GetExceptionAddress()); - uint32_t breakpoint_size = GetSoftwareBreakpointPCOffset(); - // The current PC is AFTER the BP opcode, on all architectures. - uint64_t pc = reg_ctx.GetPC() - breakpoint_size; - reg_ctx.SetPC(pc); - } + exception_addr); - if (breakpoint_hit) { - StopThread(record.GetThreadID(), StopReason::eStopReasonBreakpoint); + reg_ctx.SetPC(reg_ctx.GetPC() - GetSoftwareBreakpointPCOffset()); + StopThread(thread_id, StopReason::eStopReasonBreakpoint); SetState(eStateStopped, true); return ExceptionResult::MaskException; } else { const std::vector<ULONG_PTR> &args = record.GetExceptionArguments(); if (args.size() >= 2) { + uint32_t hw_id = LLDB_INVALID_INDEX32; reg_ctx.GetWatchpointHitIndex(hw_id, args[1]); + if (hw_id != LLDB_INVALID_INDEX32) { - addr_t wp_pc = record.GetExceptionAddress(); std::string desc = - formatv("{0} {1} {2}", args[1], hw_id, wp_pc).str(); - StopThread(record.GetThreadID(), StopReason::eStopReasonWatchpoint, - desc); + formatv("{0} {1} {2}", args[1], hw_id, exception_addr).str(); + StopThread(thread_id, StopReason::eStopReasonWatchpoint, desc); SetState(eStateStopped, true); return ExceptionResult::MaskException; } @@ -554,7 +544,6 @@ NativeProcessWindows::OnDebugException(bool first_chance, // Hit the initial stop. Continue the application. return ExceptionResult::BreakInDebugger; } - } [[fallthrough]]; default: diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp index 547ddcc4035d46..fb2997eb37b429 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp @@ -147,8 +147,8 @@ NativeRegisterContextWindows_arm64::NativeRegisterContextWindows_arm64( // Currently, there is no API to query the maximum supported hardware // breakpoints and watchpoints on Windows. The values set below are based // on tests conducted on Windows 11 with Snapdragon Elite X hardware. - m_max_hwp_supported = 1; - m_max_hbp_supported = 6; + m_max_hwp_supported = 2; + m_max_hbp_supported = 0; } bool NativeRegisterContextWindows_arm64::IsGPR(uint32_t reg_index) const { @@ -726,10 +726,6 @@ llvm::Error NativeRegisterContextWindows_arm64::ReadHardwareDebugInfo() { m_hwp_regs[i].control = tls_context.Wcr[i]; } - for (uint32_t i = 0; i < m_max_hbp_supported; i++) { - m_hbp_regs[i].address = tls_context.Bvr[i]; - m_hbp_regs[i].control = tls_context.Bcr[i]; - } return llvm::Error::success(); } @@ -741,19 +737,11 @@ NativeRegisterContextWindows_arm64::WriteHardwareDebugRegs(DREGType hwbType) { if (error.Fail()) return error.ToError(); - switch (hwbType) { - case eDREGTypeWATCH: + if (hwbType == eDREGTypeWATCH) { for (uint32_t i = 0; i < m_max_hwp_supported; i++) { tls_context.Wvr[i] = m_hwp_regs[i].address; tls_context.Wcr[i] = m_hwp_regs[i].control; } - break; - case eDREGTypeBREAK: - for (uint32_t i = 0; i < m_max_hbp_supported; i++) { - tls_context.Bvr[i] = m_hbp_regs[i].address; - tls_context.Bcr[i] = m_hbp_regs[i].control; - } - break; } return SetThreadContextHelper(GetThreadHandle(), &tls_context).ToError(); diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp index cade9c09ffb192..8ad59cd1ece887 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp @@ -178,41 +178,9 @@ Status NativeThreadWindows::RemoveWatchpoint(lldb::addr_t addr) { Status NativeThreadWindows::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) { -#if defined(__aarch64__) || defined(_M_ARM64) - if (m_state == eStateLaunching) - return Status(); - - Status error = RemoveHardwareBreakpoint(addr); - if (error.Fail()) - return error; - - uint32_t bp_index = m_reg_context_up->SetHardwareBreakpoint(addr, size); - - if (bp_index == LLDB_INVALID_INDEX32) - return Status::FromErrorString("Setting hardware breakpoint failed."); - - m_hw_breakpoint_index_map.insert({addr, bp_index}); - - return Status(); -#else return Status::FromErrorString("unimplemented."); -#endif } Status NativeThreadWindows::RemoveHardwareBreakpoint(lldb::addr_t addr) { -#if defined(__aarch64__) || defined(_M_ARM64) - auto bp = m_hw_breakpoint_index_map.find(addr); - if (bp == m_hw_breakpoint_index_map.end()) - return Status(); - - uint32_t bp_index = bp->second; - if (m_reg_context_up->ClearHardwareBreakpoint(bp_index)) { - m_hw_breakpoint_index_map.erase(bp); - return Status(); - } - - return Status::FromErrorString("Clearing hardware breakpoint failed."); -#else return Status::FromErrorString("unimplemented."); -#endif } >From 6e7e191f3ae50306ea840dfa7aa49af671d2cc25 Mon Sep 17 00:00:00 2001 From: Muhammad Omair Javaid <omair.jav...@linaro.org> Date: Wed, 9 Oct 2024 13:39:17 +0500 Subject: [PATCH 3/7] Run clang-format and fix issues --- .../Process/Windows/Common/NativeRegisterContextWindows.cpp | 1 - .../Process/Windows/Common/NativeRegisterContextWindows.h | 1 - 2 files changed, 2 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.cpp index 95be1183abb759..effe6df36b5765 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.cpp @@ -18,7 +18,6 @@ using namespace lldb; using namespace lldb_private; - lldb::thread_t NativeRegisterContextWindows::GetThreadHandle() const { auto wthread = static_cast<NativeThreadWindows *>(&m_thread); return wthread->GetHostThread().GetNativeThread().GetSystemHandle(); diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.h index d00595251f41de..0f9e37dbd9f527 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.h @@ -20,7 +20,6 @@ class NativeThreadWindows; class NativeRegisterContextWindows : public virtual NativeRegisterContextRegisterInfo { public: - static std::unique_ptr<NativeRegisterContextWindows> CreateHostNativeRegisterContextWindows(const ArchSpec &target_arch, NativeThreadProtocol &native_thread); >From 9b51184329100f324356e30167e67fb650e6accb Mon Sep 17 00:00:00 2001 From: Muhammad Omair Javaid <omair.jav...@linaro.org> Date: Wed, 9 Oct 2024 13:50:05 +0500 Subject: [PATCH 4/7] Fix typo: only one watchpoint available at max --- .../Windows/Common/NativeRegisterContextWindows_arm64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp index fb2997eb37b429..b63a3040870cd9 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp @@ -147,7 +147,7 @@ NativeRegisterContextWindows_arm64::NativeRegisterContextWindows_arm64( // Currently, there is no API to query the maximum supported hardware // breakpoints and watchpoints on Windows. The values set below are based // on tests conducted on Windows 11 with Snapdragon Elite X hardware. - m_max_hwp_supported = 2; + m_max_hwp_supported = 1; m_max_hbp_supported = 0; } >From e3d74ef422f94f27e807b452d7158330922a54da Mon Sep 17 00:00:00 2001 From: Muhammad Omair Javaid <omair.jav...@linaro.org> Date: Mon, 27 Jan 2025 02:00:00 +0500 Subject: [PATCH 5/7] Fix review comments from David --- .../Plugins/Process/Windows/Common/NativeProcessWindows.cpp | 6 +++++- .../Windows/Common/NativeRegisterContextWindows_arm64.cpp | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index 063872c229b43b..9680cb064ab712 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -502,13 +502,17 @@ NativeProcessWindows::OnDebugException(bool first_chance, if (FindSoftwareBreakpoint(exception_addr)) { LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.", exception_addr); - + // The current PC is AFTER the BP opcode, on all architectures. reg_ctx.SetPC(reg_ctx.GetPC() - GetSoftwareBreakpointPCOffset()); StopThread(thread_id, StopReason::eStopReasonBreakpoint); SetState(eStateStopped, true); return ExceptionResult::MaskException; } else { const std::vector<ULONG_PTR> &args = record.GetExceptionArguments(); + // Check that the ExceptionInformation array of EXCEPTION_RECORD + // contains at least two elements: the first is a read-write flag + // indicating the type of data access operation (read or write) while + // the second contains the virtual address of the accessed data. if (args.size() >= 2) { uint32_t hw_id = LLDB_INVALID_INDEX32; reg_ctx.GetWatchpointHitIndex(hw_id, args[1]); diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp index b63a3040870cd9..d065ad6957f7da 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp @@ -148,7 +148,6 @@ NativeRegisterContextWindows_arm64::NativeRegisterContextWindows_arm64( // breakpoints and watchpoints on Windows. The values set below are based // on tests conducted on Windows 11 with Snapdragon Elite X hardware. m_max_hwp_supported = 1; - m_max_hbp_supported = 0; } bool NativeRegisterContextWindows_arm64::IsGPR(uint32_t reg_index) const { >From 93bd8590edb16f66feaa297c5e31ac0a934101f6 Mon Sep 17 00:00:00 2001 From: Muhammad Omair Javaid <omair.jav...@linaro.org> Date: Mon, 27 Jan 2025 02:17:42 +0500 Subject: [PATCH 6/7] Add release note for WoA HW Watch support --- llvm/docs/ReleaseNotes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index 0b4afc77ab9ddb..35aa44f93e45a6 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -135,6 +135,10 @@ Changes to LLDB * When building LLDB with Python support, the minimum version of Python is now 3.8. +* LLDB now supports hardware watchpoints for AArch64 Windows targets. Windows + does not provide API to query the number of supported hardware watchpoints. + Therefore current implementation allows only 1 watchpoint, as tested with + Windows 11 on the Microsoft SQ2 and Snapdragon Elite X platforms. Changes to BOLT --------------------------------- >From d2f686aeac296bea2aeedd6c92d968600e882585 Mon Sep 17 00:00:00 2001 From: Muhammad Omair Javaid <omair.jav...@linaro.org> Date: Thu, 30 Jan 2025 01:29:22 +0500 Subject: [PATCH 7/7] Fix unalinged watchpoints --- .../Windows/Common/NativeProcessWindows.cpp | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index 9680cb064ab712..79dd46ba319d65 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -292,7 +292,8 @@ NativeProcessWindows::GetAuxvData() const { llvm::Expected<llvm::ArrayRef<uint8_t>> NativeProcessWindows::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { - static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000 + static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, + 0xd4}; // brk #0xf000 static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe switch (GetArchitecture().GetMachine()) { @@ -309,9 +310,9 @@ NativeProcessWindows::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { } size_t NativeProcessWindows::GetSoftwareBreakpointPCOffset() { - // Windows always reports an incremented PC after a breakpoint is hit, - // even on ARM. - return cantFail(GetSoftwareBreakpointTrapOpcode(0)).size(); + // Windows always reports an incremented PC after a breakpoint is hit, + // even on ARM. + return cantFail(GetSoftwareBreakpointTrapOpcode(0)).size(); } bool NativeProcessWindows::FindSoftwareBreakpoint(lldb::addr_t addr) { @@ -463,6 +464,7 @@ NativeProcessWindows::OnDebugException(bool first_chance, switch (record.GetExceptionCode()) { case DWORD(STATUS_SINGLE_STEP): case STATUS_WX86_SINGLE_STEP: { +#ifndef __aarch64__ uint32_t wp_id = LLDB_INVALID_INDEX32; if (NativeThreadWindows *thread = GetThreadByID(record.GetThreadID())) { NativeRegisterContextWindows ®_ctx = thread->GetRegisterContext(); @@ -483,6 +485,7 @@ NativeProcessWindows::OnDebugException(bool first_chance, } } if (wp_id == LLDB_INVALID_INDEX32) +#endif StopThread(record.GetThreadID(), StopReason::eStopReasonTrace); SetState(eStateStopped, true); @@ -508,6 +511,9 @@ NativeProcessWindows::OnDebugException(bool first_chance, SetState(eStateStopped, true); return ExceptionResult::MaskException; } else { + // This block of code will only be entered in case of a hardware + // watchpoint or breakpoint hit on AArch64. However, we only handle + // hardware watchpoints below as breakpoints are not yet supported. const std::vector<ULONG_PTR> &args = record.GetExceptionArguments(); // Check that the ExceptionInformation array of EXCEPTION_RECORD // contains at least two elements: the first is a read-write flag @@ -515,11 +521,18 @@ NativeProcessWindows::OnDebugException(bool first_chance, // the second contains the virtual address of the accessed data. if (args.size() >= 2) { uint32_t hw_id = LLDB_INVALID_INDEX32; - reg_ctx.GetWatchpointHitIndex(hw_id, args[1]); + Status error = reg_ctx.GetWatchpointHitIndex(hw_id, args[1]); + if (error.Fail()) + LLDB_LOG(log, + "received error while checking for watchpoint hits, pid = " + "{0}, error = {1}", + thread_id, error); if (hw_id != LLDB_INVALID_INDEX32) { std::string desc = - formatv("{0} {1} {2}", args[1], hw_id, exception_addr).str(); + formatv("{0} {1} {2}", reg_ctx.GetWatchpointAddress(hw_id), + hw_id, exception_addr) + .str(); StopThread(thread_id, StopReason::eStopReasonWatchpoint, desc); SetState(eStateStopped, true); return ExceptionResult::MaskException; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits