diff --git a/lldb/tools/debugserver/source/DNBArch.h b/lldb/tools/debugserver/source/DNBArch.h index db0c614c28b4..08e7042f43fa 100644 --- a/lldb/tools/debugserver/source/DNBArch.h +++ b/lldb/tools/debugserver/source/DNBArch.h @@ -82,6 +82,19 @@ public: virtual bool DisableHardwareWatchpoint (uint32_t hw_index) { return false; } virtual uint32_t GetHardwareWatchpointHit() { return INVALID_NUB_HW_INDEX; } virtual bool StepNotComplete () { return false; } + +protected: + friend class MachThread; + + enum + { + Trans_Pending = 0, // Transaction is pending, and checkpoint state has been snapshotted. + Trans_Done = 1, // Transaction is done, the current state is committed, and checkpoint state is irrelevant. + Trans_Rolled_Back = 2 // Transaction is done, the current state has been rolled back to the checkpoint state. + }; + virtual bool StartTransForHWP() { return true; } + virtual bool RollbackTransForHWP() { return true; } + virtual bool FinishTransForHWP() { return true; } }; diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp index aca47f9120fa..f9e3dd569f61 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp @@ -699,6 +699,18 @@ MachThread::HardwareWatchpointStateChanged () m_arch_ap->HardwareWatchpointStateChanged(); } +bool +MachThread::RollbackTransForHWP() +{ + return m_arch_ap->RollbackTransForHWP(); +} + +bool +MachThread::FinishTransForHWP() +{ + return m_arch_ap->FinishTransForHWP(); +} + bool MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp) { diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.h b/lldb/tools/debugserver/source/MacOSX/MachThread.h index 724043ab0396..90bd05f2dc75 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThread.h +++ b/lldb/tools/debugserver/source/MacOSX/MachThread.h @@ -66,6 +66,8 @@ public: bool DisableHardwareBreakpoint (const DNBBreakpoint *breakpoint); bool DisableHardwareWatchpoint (const DNBBreakpoint *watchpoint); uint32_t NumSupportedHardwareWatchpoints () const; + bool RollbackTransForHWP(); + bool FinishTransForHWP(); nub_state_t GetState(); void SetState(nub_state_t state); diff --git a/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp index e2aa0f2eedd7..b8044fe6c7fb 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp @@ -478,8 +478,17 @@ MachThreadList::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const for (uint32_t idx = 0; idx < num_threads; ++idx) { if ((hw_index = m_threads[idx]->EnableHardwareWatchpoint(wp)) == INVALID_NUB_HW_INDEX) + { + // We know that idx failed for some reason. Let's rollback the transaction for [0, idx). + for (uint32_t i = 0; i < idx; ++i) + m_threads[i]->RollbackTransForHWP(); return INVALID_NUB_HW_INDEX; + } } + // Notify each thread to commit the pending transaction. + for (uint32_t idx = 0; idx < num_threads; ++idx) + m_threads[idx]->FinishTransForHWP(); + // Use an arbitrary thread to signal the completion of our transaction. if (num_threads) m_threads[0]->HardwareWatchpointStateChanged(); @@ -498,8 +507,17 @@ MachThreadList::DisableHardwareWatchpoint (const DNBBreakpoint* wp) const for (uint32_t idx = 0; idx < num_threads; ++idx) { if (!m_threads[idx]->DisableHardwareWatchpoint(wp)) + { + // We know that idx failed for some reason. Let's rollback the transaction for [0, idx). + for (uint32_t i = 0; i < idx; ++i) + m_threads[i]->RollbackTransForHWP(); return false; + } } + // Notify each thread to commit the pending transaction. + for (uint32_t idx = 0; idx < num_threads; ++idx) + m_threads[idx]->FinishTransForHWP(); + // Use an arbitrary thread to signal the completion of our transaction. if (num_threads) m_threads[0]->HardwareWatchpointStateChanged(); diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp index 3962b9b6c5da..9a1abfbf286e 100644 --- a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp +++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp @@ -818,6 +818,42 @@ DNBArchImplI386::GetWatchAddress(const DBG &debug_state, uint32_t hw_index) } } +bool +DNBArchImplI386::StartTransForHWP() +{ + if (m_2pc_trans_state != Trans_Done || m_2pc_trans_state != Trans_Rolled_Back) + DNBLogError ("%s inconsistent state detected, expected %d or %d, got: %d", __FUNCTION__, Trans_Done, Trans_Rolled_Back, m_2pc_trans_state); + m_2pc_dbg_checkpoint = m_state.context.dbg; + m_2pc_trans_state = Trans_Pending; + return true; +} +bool +DNBArchImplI386::RollbackTransForHWP() +{ + m_state.context.dbg = m_2pc_dbg_checkpoint; + if (m_2pc_trans_state != Trans_Pending) + DNBLogError ("%s inconsistent state detected, expected %d, got: %d", __FUNCTION__, Trans_Pending, m_2pc_trans_state); + m_2pc_trans_state = Trans_Rolled_Back; + kern_return_t kret = SetDBGState(); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::RollbackTransForHWP() SetDBGState() => 0x%8.8x.", kret); + + if (kret == KERN_SUCCESS) + return true; + else + return false; +} +bool +DNBArchImplI386::FinishTransForHWP() +{ + m_2pc_trans_state = Trans_Done; + return true; +} +DNBArchImplI386::DBG +DNBArchImplI386::GetDBGCheckpoint() +{ + return m_2pc_dbg_checkpoint; +} + uint32_t DNBArchImplI386::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write) { @@ -842,7 +878,6 @@ DNBArchImplI386::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, boo uint32_t i = 0; DBG &debug_state = m_state.context.dbg; - DBG dsCheckPoint = m_state.context.dbg; for (i = 0; i < num_hw_watchpoints; ++i) { if (IsWatchpointVacant(debug_state, i)) @@ -852,6 +887,8 @@ DNBArchImplI386::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, boo // See if we found an available hw breakpoint slot above if (i < num_hw_watchpoints) { + StartTransForHWP(); + // Modify our local copy of the debug state, first. SetWatchpoint(debug_state, i, addr, size, read, write); // Now set the watch point in the inferior. @@ -860,8 +897,8 @@ DNBArchImplI386::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, boo if (kret == KERN_SUCCESS) return i; - else // Recovery block. - m_state.context.dbg = dsCheckPoint; + else // Revert to the previous debug state voluntarily. The transaction coordinator knows that we have failed. + m_state.context.dbg = GetDBGCheckpoint(); } else { @@ -880,9 +917,10 @@ DNBArchImplI386::DisableHardwareWatchpoint (uint32_t hw_index) if (kret == KERN_SUCCESS) { DBG &debug_state = m_state.context.dbg; - DBG dsCheckPoint = m_state.context.dbg; if (hw_index < num_hw_points && !IsWatchpointVacant(debug_state, hw_index)) { + StartTransForHWP(); + // Modify our local copy of the debug state, first. ClearWatchpoint(debug_state, hw_index); // Now disable the watch point in the inferior. @@ -892,8 +930,8 @@ DNBArchImplI386::DisableHardwareWatchpoint (uint32_t hw_index) if (kret == KERN_SUCCESS) return true; - else // Recovery block. - m_state.context.dbg = dsCheckPoint; + else // Revert to the previous debug state voluntarily. The transaction coordinator knows that we have failed. + m_state.context.dbg = GetDBGCheckpoint(); } } return false; diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h index 316aed2ba50e..7a282bd85777 100644 --- a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h +++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h @@ -231,8 +231,15 @@ protected: static bool IsWatchpointHit(const DBG &debug_state, uint32_t hw_index); static nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); + virtual bool StartTransForHWP(); + virtual bool RollbackTransForHWP(); + virtual bool FinishTransForHWP(); + DBG GetDBGCheckpoint(); + MachThread *m_thread; State m_state; + DBG m_2pc_dbg_checkpoint; + uint32_t m_2pc_trans_state; // Is transaction of DBG state change: Pedning (0), Done (1), or Rolled Back (2)? }; #endif // #if defined (__i386__) || defined (__x86_64__) diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp index 94aa9a186645..2a8cf69c26a4 100644 --- a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp +++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp @@ -795,6 +795,42 @@ DNBArchImplX86_64::GetWatchAddress(const DBG &debug_state, uint32_t hw_index) } } +bool +DNBArchImplX86_64::StartTransForHWP() +{ + if (m_2pc_trans_state != Trans_Done || m_2pc_trans_state != Trans_Rolled_Back) + DNBLogError ("%s inconsistent state detected, expected %d or %d, got: %d", __FUNCTION__, Trans_Done, Trans_Rolled_Back, m_2pc_trans_state); + m_2pc_dbg_checkpoint = m_state.context.dbg; + m_2pc_trans_state = Trans_Pending; + return true; +} +bool +DNBArchImplX86_64::RollbackTransForHWP() +{ + m_state.context.dbg = m_2pc_dbg_checkpoint; + if (m_2pc_trans_state != Trans_Pending) + DNBLogError ("%s inconsistent state detected, expected %d, got: %d", __FUNCTION__, Trans_Pending, m_2pc_trans_state); + m_2pc_trans_state = Trans_Rolled_Back; + kern_return_t kret = SetDBGState(); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::RollbackTransForHWP() SetDBGState() => 0x%8.8x.", kret); + + if (kret == KERN_SUCCESS) + return true; + else + return false; +} +bool +DNBArchImplX86_64::FinishTransForHWP() +{ + m_2pc_trans_state = Trans_Done; + return true; +} +DNBArchImplX86_64::DBG +DNBArchImplX86_64::GetDBGCheckpoint() +{ + return m_2pc_dbg_checkpoint; +} + uint32_t DNBArchImplX86_64::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write) { @@ -819,7 +855,6 @@ DNBArchImplX86_64::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, b uint32_t i = 0; DBG &debug_state = m_state.context.dbg; - DBG dsCheckPoint = m_state.context.dbg; for (i = 0; i < num_hw_watchpoints; ++i) { if (IsWatchpointVacant(debug_state, i)) @@ -829,6 +864,8 @@ DNBArchImplX86_64::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, b // See if we found an available hw breakpoint slot above if (i < num_hw_watchpoints) { + StartTransForHWP(); + // Modify our local copy of the debug state, first. SetWatchpoint(debug_state, i, addr, size, read, write); // Now set the watch point in the inferior. @@ -837,8 +874,8 @@ DNBArchImplX86_64::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, b if (kret == KERN_SUCCESS) return i; - else // Recovery block. - m_state.context.dbg = dsCheckPoint; + else // Revert to the previous debug state voluntarily. The transaction coordinator knows that we have failed. + m_state.context.dbg = GetDBGCheckpoint(); } else { @@ -857,9 +894,10 @@ DNBArchImplX86_64::DisableHardwareWatchpoint (uint32_t hw_index) if (kret == KERN_SUCCESS) { DBG &debug_state = m_state.context.dbg; - DBG dsCheckPoint = m_state.context.dbg; if (hw_index < num_hw_points && !IsWatchpointVacant(debug_state, hw_index)) { + StartTransForHWP(); + // Modify our local copy of the debug state, first. ClearWatchpoint(debug_state, hw_index); // Now disable the watch point in the inferior. @@ -869,8 +907,8 @@ DNBArchImplX86_64::DisableHardwareWatchpoint (uint32_t hw_index) if (kret == KERN_SUCCESS) return true; - else // Recovery block. - m_state.context.dbg = dsCheckPoint; + else // Revert to the previous debug state voluntarily. The transaction coordinator knows that we have failed. + m_state.context.dbg = GetDBGCheckpoint(); } } return false; diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h index 04c07bc0dd1f..148780ee4146 100644 --- a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h +++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h @@ -238,8 +238,15 @@ protected: static bool IsWatchpointHit(const DBG &debug_state, uint32_t hw_index); static nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); + virtual bool StartTransForHWP(); + virtual bool RollbackTransForHWP(); + virtual bool FinishTransForHWP(); + DBG GetDBGCheckpoint(); + MachThread *m_thread; - State m_state; + State m_state; + DBG m_2pc_dbg_checkpoint; + uint32_t m_2pc_trans_state; // Is transaction of DBG state change: Pedning (0), Done (1), or Rolled Back (2)? }; #endif // #if defined (__i386__) || defined (__x86_64__)