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:
Johnny Chen 2012-06-01 23:43:05 +00:00
parent 2e1d9bac35
commit 847075607f
8 changed files with 148 additions and 13 deletions

View File

@ -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; }
};

View File

@ -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)
{

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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__)

View File

@ -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;

View File

@ -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__)