diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index 9c330ff118670..79dd46ba319d6 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> 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); @@ -492,23 +495,50 @@ NativeProcessWindows::OnDebugException(bool first_chance, } 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 ®_ctx = stop_thread->GetRegisterContext(); + const auto exception_addr = record.GetExceptionAddress(); + const auto thread_id = record.GetThreadID(); - if (NativeThreadWindows *stop_thread = - GetThreadByID(record.GetThreadID())) { - auto ®ister_context = stop_thread->GetRegisterContext(); - uint32_t breakpoint_size = GetSoftwareBreakpointPCOffset(); + 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. - uint64_t pc = register_context.GetPC() - breakpoint_size; - register_context.SetPC(pc); + reg_ctx.SetPC(reg_ctx.GetPC() - GetSoftwareBreakpointPCOffset()); + StopThread(thread_id, StopReason::eStopReasonBreakpoint); + 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 &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; + 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}", reg_ctx.GetWatchpointAddress(hw_id), + hw_id, exception_addr) + .str(); + StopThread(thread_id, StopReason::eStopReasonWatchpoint, desc); + SetState(eStateStopped, true); + return ExceptionResult::MaskException; + } + } } - - SetState(eStateStopped, true); - return ExceptionResult::MaskException; } if (!initial_stop) { diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.cpp index 9128363eaa577..effe6df36b576 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.cpp @@ -18,10 +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(&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 841b8547f3e90..0f9e37dbd9f52 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows.h @@ -17,12 +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 CreateHostNativeRegisterContextWindows(const ArchSpec &target_arch, NativeThreadProtocol &native_thread); diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_WoW64.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_WoW64.cpp index a9642d1c5e48d..069c327ee2f9a 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 4209fdf3c7109..fd8a0c05c1b25 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 080a9140e36a6..d065ad6957f7d 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,13 @@ 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; +} bool NativeRegisterContextWindows_arm64::IsGPR(uint32_t reg_index) const { return (reg_index >= k_first_gpr_arm64 && reg_index <= k_last_gpr_arm64); @@ -709,48 +713,37 @@ 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"); -} +llvm::Error NativeRegisterContextWindows_arm64::ReadHardwareDebugInfo() { + ::CONTEXT tls_context; + Status error = GetThreadContextHelper(GetThreadHandle(), &tls_context, + CONTEXT_DEBUG_REGISTERS); + if (error.Fail()) + return error.ToError(); -bool NativeRegisterContextWindows_arm64::ClearHardwareWatchpoint( - uint32_t wp_index) { - return false; -} + 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]; + } -Status NativeRegisterContextWindows_arm64::ClearAllHardwareWatchpoints() { - return Status::FromErrorString("unimplemented"); + return llvm::Error::success(); } -uint32_t NativeRegisterContextWindows_arm64::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - return LLDB_INVALID_INDEX32; -} +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(); -lldb::addr_t -NativeRegisterContextWindows_arm64::GetWatchpointAddress(uint32_t wp_index) { - return LLDB_INVALID_ADDRESS; -} + 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; + } + } -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 88afc1e7b18a2..e73a6af4cbf80 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 53df986679394..7c13759df462d 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 4c59273b845aa..c54c31e48e4e5 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/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index 0b4afc77ab9dd..35aa44f93e45a 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 ---------------------------------