rdar://problem/11320188
Designate MachThreadList as a transaction coordinator when doing Enable/DisableHardwareWatchpoint on the list of threads. In case the operation (iterating on the threads and doing enable/disable) fails in the middle, we rollback the already enabled/disabled threads to their checkpointed states. When all the threads succeed in enable/disable, we ask each thread to finsih the transaction and commit the change of the debug state. llvm-svn: 157858
This commit is contained in:
parent
2e1d9bac35
commit
847075607f
|
@ -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; }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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__)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
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__)
|
||||
|
|
Loading…
Reference in New Issue