forked from OSchip/llvm-project
Modify the delegation chain from MachThreadList -> MachThread -> DNBArchProtocol so that when
the watchpoint state is changed, not only does the change propagate to all the thread instances, it also updates a global debug state, if chosen by the DNBArchProtocol derivative. Once implemented, the DNBArchProtocol derivative, also makes sure that when new thread comes along, it tries to inherit from the global debug state, if it is valid. Modify TestWatchpointMultipleThreads.py to test this functionality. llvm-svn: 140811
This commit is contained in:
parent
3f030ff016
commit
a9b68f4dd6
|
@ -30,7 +30,8 @@ class WatchpointForMultipleThreadsTestCase(TestBase):
|
|||
# Our simple source filename.
|
||||
self.source = 'main.cpp'
|
||||
# Find the line number to break inside main().
|
||||
self.line = line_number(self.source, '// Set break point at this line.')
|
||||
self.first_stop = line_number(self.source, '// Set break point at this line')
|
||||
self.thread_function = line_number(self.source, '// Break here in order to allow the thread')
|
||||
# Build dictionary to have unique executable names for each test method.
|
||||
self.exe_name = self.testMethodName
|
||||
self.d = {'CXX_SOURCES': self.source, 'EXE': self.exe_name}
|
||||
|
@ -41,9 +42,14 @@ class WatchpointForMultipleThreadsTestCase(TestBase):
|
|||
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
|
||||
|
||||
# Add a breakpoint to set a watchpoint when stopped on the breakpoint.
|
||||
self.expect("breakpoint set -l %d" % self.line, BREAKPOINT_CREATED,
|
||||
self.expect("breakpoint set -l %d" % self.first_stop, BREAKPOINT_CREATED,
|
||||
startstr = "Breakpoint created: 1: file ='%s', line = %d, locations = 1" %
|
||||
(self.source, self.line))
|
||||
(self.source, self.first_stop))
|
||||
|
||||
# Set this breakpoint to allow newly created thread to inherit the global watchpoint state.
|
||||
self.expect("breakpoint set -l %d" % self.thread_function, BREAKPOINT_CREATED,
|
||||
startstr = "Breakpoint created: 2: file ='%s', line = %d, locations = 1" %
|
||||
(self.source, self.thread_function))
|
||||
|
||||
# Run the program.
|
||||
self.runCmd("run", RUN_SUCCEEDED)
|
||||
|
@ -66,22 +72,28 @@ class WatchpointForMultipleThreadsTestCase(TestBase):
|
|||
self.expect("watchpoint list -v",
|
||||
substrs = ['hit_count = 0'])
|
||||
|
||||
self.runCmd("process continue")
|
||||
breakpoint_stops = 0
|
||||
while True:
|
||||
self.runCmd("process continue")
|
||||
|
||||
# We should be stopped again due to the watchpoint (write type) in a
|
||||
# different work thread. And the stop reason of the thread should be
|
||||
# watchpoint.
|
||||
self.expect("thread list", STOPPED_DUE_TO_WATCHPOINT,
|
||||
substrs = ['stopped',
|
||||
'stop reason = watchpoint'])
|
||||
self.runCmd("thread list")
|
||||
if "stop reason = breakpoint" in self.res.GetOutput():
|
||||
breakpoint_stops += 1
|
||||
if breakpoint_stops > 3:
|
||||
self.fail("Do not expect to break more than 3 times")
|
||||
continue
|
||||
elif "stop reason = watchpoint" in self.res.GetOutput():
|
||||
# Good, we verified that the watchpoint works!
|
||||
self.runCmd("thread backtrace all")
|
||||
break
|
||||
else:
|
||||
self.fail("The stop reason should be either break or watchpoint")
|
||||
|
||||
# Use the '-v' option to do verbose listing of the watchpoint.
|
||||
# The hit count should now be 1.
|
||||
self.expect("watchpoint list -v",
|
||||
substrs = ['hit_count = 1'])
|
||||
|
||||
self.runCmd("thread backtrace all")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import atexit
|
||||
|
|
|
@ -41,7 +41,8 @@ access_pool (uint32_t flag)
|
|||
void *
|
||||
thread_func (void *arg)
|
||||
{
|
||||
uint32_t thread_index = *((uint32_t *)arg);
|
||||
uint32_t thread_index = *((uint32_t *)arg); // Break here in order to allow the thread
|
||||
// to inherit the global watchpoint state.
|
||||
printf ("%s (thread index = %u) startng...\n", __FUNCTION__, thread_index);
|
||||
|
||||
uint32_t count = 0;
|
||||
|
@ -73,13 +74,13 @@ int main (int argc, char const *argv[])
|
|||
uint32_t thread_index_2 = 2;
|
||||
uint32_t thread_index_3 = 3;
|
||||
|
||||
printf ("Before turning all three threads loose...\n"); // Set break point at this line,
|
||||
// in order to set our watchpoint.
|
||||
// Create 3 threads
|
||||
err = ::pthread_create (&g_thread_1, NULL, thread_func, &thread_index_1);
|
||||
err = ::pthread_create (&g_thread_2, NULL, thread_func, &thread_index_2);
|
||||
err = ::pthread_create (&g_thread_3, NULL, thread_func, &thread_index_3);
|
||||
|
||||
printf ("Before turning all three threads loose...\n"); // Set break point at this line.
|
||||
|
||||
// Join all of our threads
|
||||
err = ::pthread_join (g_thread_1, &thread_result);
|
||||
err = ::pthread_join (g_thread_2, &thread_result);
|
||||
|
|
|
@ -77,6 +77,7 @@ public:
|
|||
virtual uint32_t NumSupportedHardwareWatchpoints() { return 0; }
|
||||
virtual uint32_t EnableHardwareBreakpoint (nub_addr_t addr, nub_size_t size) { return INVALID_NUB_HW_INDEX; }
|
||||
virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write) { return INVALID_NUB_HW_INDEX; }
|
||||
virtual void HardwareWatchpointStateChanged () { ; }
|
||||
virtual bool DisableHardwareBreakpoint (uint32_t hw_index) { return false; }
|
||||
virtual bool DisableHardwareWatchpoint (uint32_t hw_index) { return false; }
|
||||
virtual uint32_t GetHardwareWatchpointHit() { return INVALID_NUB_HW_INDEX; }
|
||||
|
|
|
@ -687,6 +687,13 @@ MachThread::EnableHardwareWatchpoint (const DNBBreakpoint *wp)
|
|||
return INVALID_NUB_HW_INDEX;
|
||||
}
|
||||
|
||||
// Provide a chance to update the global view of the hardware watchpoint state.
|
||||
void
|
||||
MachThread::HardwareWatchpointStateChanged ()
|
||||
{
|
||||
m_arch_ap->HardwareWatchpointStateChanged();
|
||||
}
|
||||
|
||||
bool
|
||||
MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp)
|
||||
{
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
class DNBBreakpoint;
|
||||
class MachProcess;
|
||||
class MachThreadList;
|
||||
|
||||
class MachThread
|
||||
{
|
||||
|
@ -131,6 +132,9 @@ protected:
|
|||
std::string m_dispatch_queue_name;
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class MachThreadList;
|
||||
void HardwareWatchpointStateChanged(); // Provide a chance to update the global view of the hardware watchpoint state
|
||||
};
|
||||
|
||||
typedef std::tr1::shared_ptr<MachThread> MachThreadSP;
|
||||
|
|
|
@ -480,6 +480,9 @@ MachThreadList::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const
|
|||
if ((hw_index = m_threads[idx]->EnableHardwareWatchpoint(wp)) == INVALID_NUB_HW_INDEX)
|
||||
return INVALID_NUB_HW_INDEX;
|
||||
}
|
||||
// Use an arbitrary thread to signal the completion of our transaction.
|
||||
if (num_threads)
|
||||
m_threads[0]->HardwareWatchpointStateChanged();
|
||||
return hw_index;
|
||||
}
|
||||
return INVALID_NUB_HW_INDEX;
|
||||
|
@ -497,6 +500,9 @@ MachThreadList::DisableHardwareWatchpoint (const DNBBreakpoint* wp) const
|
|||
if (!m_threads[idx]->DisableHardwareWatchpoint(wp))
|
||||
return false;
|
||||
}
|
||||
// Use an arbitrary thread to signal the completion of our transaction.
|
||||
if (num_threads)
|
||||
m_threads[0]->HardwareWatchpointStateChanged();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -555,7 +555,7 @@ DNBArchImplI386::ThreadWillResume()
|
|||
|
||||
// Reset the debug status register, if necessary, before we resume.
|
||||
kern_return_t kret = GetDBGState(false);
|
||||
DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::ThreadWillResume() GetDBGState() => 0x%8.8x.", kret);
|
||||
DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::ThreadWillResume() GetDBGState() => 0x%8.8x.", kret);
|
||||
if (kret != KERN_SUCCESS)
|
||||
return;
|
||||
|
||||
|
@ -570,7 +570,7 @@ DNBArchImplI386::ThreadWillResume()
|
|||
{
|
||||
ClearWatchpointHits(debug_state);
|
||||
kret = SetDBGState();
|
||||
DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::ThreadWillResume() SetDBGState() => 0x%8.8x.", kret);
|
||||
DNBLogThreadedIf(LOG_WATCHPOINTS,"DNBArchImplI386::ThreadWillResume() SetDBGState() => 0x%8.8x.", kret);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -894,6 +894,19 @@ DNBArchImplI386::DisableHardwareWatchpoint (uint32_t hw_index)
|
|||
return false;
|
||||
}
|
||||
|
||||
DNBArchImplI386::DBG DNBArchImplI386::Global_Debug_State = {0,0,0,0,0,0,0,0};
|
||||
bool DNBArchImplI386::Valid_Global_Debug_State = false;
|
||||
|
||||
// Use this callback from MachThread, which in turn was called from MachThreadList, to update
|
||||
// the global view of the hardware watchpoint state, so that when new thread comes along, they
|
||||
// get to inherit the existing hardware watchpoint state.
|
||||
void
|
||||
DNBArchImplI386::HardwareWatchpointStateChanged ()
|
||||
{
|
||||
Global_Debug_State = m_state.context.dbg;
|
||||
Valid_Global_Debug_State = true;
|
||||
}
|
||||
|
||||
// Iterate through the debug status register; return the index of the first hit.
|
||||
uint32_t
|
||||
DNBArchImplI386::GetHardwareWatchpointHit(nub_addr_t &addr)
|
||||
|
@ -1109,7 +1122,17 @@ const size_t DNBArchImplI386::k_num_register_sets = sizeof(g_reg_sets_no_avx)/si
|
|||
DNBArchProtocol *
|
||||
DNBArchImplI386::Create (MachThread *thread)
|
||||
{
|
||||
return new DNBArchImplI386 (thread);
|
||||
DNBArchImplI386 *obj = new DNBArchImplI386 (thread);
|
||||
|
||||
// When new thread comes along, it tries to inherit from the global debug state, if it is valid.
|
||||
if (Valid_Global_Debug_State)
|
||||
{
|
||||
obj->m_state.context.dbg = Global_Debug_State;
|
||||
kern_return_t kret = obj->SetDBGState();
|
||||
DNBLogThreadedIf(LOG_WATCHPOINTS,
|
||||
"DNBArchImplX86_64::Create() Inherit and SetDBGState() => 0x%8.8x.", kret);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
const uint8_t * const
|
||||
|
|
|
@ -54,6 +54,7 @@ public:
|
|||
virtual uint32_t NumSupportedHardwareWatchpoints();
|
||||
virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write);
|
||||
virtual bool DisableHardwareWatchpoint (uint32_t hw_break_index);
|
||||
virtual void HardwareWatchpointStateChanged ();
|
||||
virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr);
|
||||
|
||||
protected:
|
||||
|
@ -116,6 +117,10 @@ protected:
|
|||
DBG dbg;
|
||||
};
|
||||
|
||||
// See also HardwareWatchpointStateChanged() which updates this class-wide variable.
|
||||
static DBG Global_Debug_State;
|
||||
static bool Valid_Global_Debug_State;
|
||||
|
||||
struct State
|
||||
{
|
||||
Context context;
|
||||
|
|
|
@ -821,6 +821,19 @@ DNBArchImplX86_64::DisableHardwareWatchpoint (uint32_t hw_index)
|
|||
return false;
|
||||
}
|
||||
|
||||
DNBArchImplX86_64::DBG DNBArchImplX86_64::Global_Debug_State = {0,0,0,0,0,0,0,0};
|
||||
bool DNBArchImplX86_64::Valid_Global_Debug_State = false;
|
||||
|
||||
// Use this callback from MachThread, which in turn was called from MachThreadList, to update
|
||||
// the global view of the hardware watchpoint state, so that when new thread comes along, they
|
||||
// get to inherit the existing hardware watchpoint state.
|
||||
void
|
||||
DNBArchImplX86_64::HardwareWatchpointStateChanged ()
|
||||
{
|
||||
Global_Debug_State = m_state.context.dbg;
|
||||
Valid_Global_Debug_State = true;
|
||||
}
|
||||
|
||||
// Iterate through the debug status register; return the index of the first hit.
|
||||
uint32_t
|
||||
DNBArchImplX86_64::GetHardwareWatchpointHit(nub_addr_t &addr)
|
||||
|
@ -1306,7 +1319,17 @@ const size_t DNBArchImplX86_64::k_num_register_sets = sizeof(g_reg_sets_avx)/siz
|
|||
DNBArchProtocol *
|
||||
DNBArchImplX86_64::Create (MachThread *thread)
|
||||
{
|
||||
return new DNBArchImplX86_64 (thread);
|
||||
DNBArchImplX86_64 *obj = new DNBArchImplX86_64 (thread);
|
||||
|
||||
// When new thread comes along, it tries to inherit from the global debug state, if it is valid.
|
||||
if (Valid_Global_Debug_State)
|
||||
{
|
||||
obj->m_state.context.dbg = Global_Debug_State;
|
||||
kern_return_t kret = obj->SetDBGState();
|
||||
DNBLogThreadedIf(LOG_WATCHPOINTS,
|
||||
"DNBArchImplX86_64::Create() Inherit and SetDBGState() => 0x%8.8x.", kret);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
const uint8_t * const
|
||||
|
|
|
@ -53,6 +53,7 @@ public:
|
|||
virtual uint32_t NumSupportedHardwareWatchpoints();
|
||||
virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write);
|
||||
virtual bool DisableHardwareWatchpoint (uint32_t hw_break_index);
|
||||
virtual void HardwareWatchpointStateChanged ();
|
||||
virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr);
|
||||
|
||||
protected:
|
||||
|
@ -115,6 +116,10 @@ protected:
|
|||
DBG dbg;
|
||||
};
|
||||
|
||||
// See also HardwareWatchpointStateChanged() which updates this class-wide variable.
|
||||
static DBG Global_Debug_State;
|
||||
static bool Valid_Global_Debug_State;
|
||||
|
||||
struct State
|
||||
{
|
||||
Context context;
|
||||
|
|
Loading…
Reference in New Issue