diff options
author | 2020-08-03 14:33:06 +0000 | |
---|---|---|
committer | 2020-08-03 14:33:06 +0000 | |
commit | 061da546b983eb767bad15e67af1174fb0bcf31c (patch) | |
tree | 83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/packages/Python/lldbsuite/test/concurrent_base.py | |
parent | Import LLVM 10.0.0 release including clang, lld and lldb. (diff) | |
download | wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip |
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom
tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/packages/Python/lldbsuite/test/concurrent_base.py')
-rw-r--r-- | gnu/llvm/lldb/packages/Python/lldbsuite/test/concurrent_base.py | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/concurrent_base.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/concurrent_base.py new file mode 100644 index 00000000000..6acd71ce9e4 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/concurrent_base.py @@ -0,0 +1,284 @@ +""" +A stress-test of sorts for LLDB's handling of threads in the inferior. + +This test sets a breakpoint in the main thread where test parameters (numbers of +threads) can be adjusted, runs the inferior to that point, and modifies the +locals that control the event thread counts. This test also sets a breakpoint in +breakpoint_func (the function executed by each 'breakpoint' thread) and a +watchpoint on a global modified in watchpoint_func. The inferior is continued +until exit or a crash takes place, and the number of events seen by LLDB is +verified to match the expected number of events. +""" + + + +import unittest2 +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ConcurrentEventsBase(TestBase): + + # Concurrency is the primary test factor here, not debug info variants. + NO_DEBUG_INFO_TESTCASE = True + + def setUp(self): + # Call super's setUp(). + super(ConcurrentEventsBase, self).setUp() + # Find the line number for our breakpoint. + self.filename = 'main.cpp' + self.thread_breakpoint_line = line_number( + self.filename, '// Set breakpoint here') + self.setup_breakpoint_line = line_number( + self.filename, '// Break here and adjust num') + self.finish_breakpoint_line = line_number( + self.filename, '// Break here and verify one thread is active') + + def describe_threads(self): + ret = [] + for x in self.inferior_process: + id = x.GetIndexID() + reason = x.GetStopReason() + status = "stopped" if x.IsStopped() else "running" + reason_str = lldbutil.stop_reason_to_str(reason) + if reason == lldb.eStopReasonBreakpoint: + bpid = x.GetStopReasonDataAtIndex(0) + bp = self.inferior_target.FindBreakpointByID(bpid) + reason_str = "%s hit %d times" % ( + lldbutil.get_description(bp), bp.GetHitCount()) + elif reason == lldb.eStopReasonWatchpoint: + watchid = x.GetStopReasonDataAtIndex(0) + watch = self.inferior_target.FindWatchpointByID(watchid) + reason_str = "%s hit %d times" % ( + lldbutil.get_description(watch), watch.GetHitCount()) + elif reason == lldb.eStopReasonSignal: + signals = self.inferior_process.GetUnixSignals() + signal_name = signals.GetSignalAsCString( + x.GetStopReasonDataAtIndex(0)) + reason_str = "signal %s" % signal_name + + location = "\t".join([lldbutil.get_description( + x.GetFrameAtIndex(i)) for i in range(x.GetNumFrames())]) + ret.append( + "thread %d %s due to %s at\n\t%s" % + (id, status, reason_str, location)) + return ret + + def add_breakpoint(self, line, descriptions): + """ Adds a breakpoint at self.filename:line and appends its description to descriptions, and + returns the LLDB SBBreakpoint object. + """ + + bpno = lldbutil.run_break_set_by_file_and_line( + self, self.filename, line, num_expected_locations=-1) + bp = self.inferior_target.FindBreakpointByID(bpno) + descriptions.append( + ": file = 'main.cpp', line = %d" % + self.finish_breakpoint_line) + return bp + + def inferior_done(self): + """ Returns true if the inferior is done executing all the event threads (and is stopped at self.finish_breakpoint, + or has terminated execution. + """ + return self.finish_breakpoint.GetHitCount() > 0 or \ + self.crash_count > 0 or \ + self.inferior_process.GetState() == lldb.eStateExited + + def count_signaled_threads(self): + count = 0 + for thread in self.inferior_process: + if thread.GetStopReason() == lldb.eStopReasonSignal and thread.GetStopReasonDataAtIndex( + 0) == self.inferior_process.GetUnixSignals().GetSignalNumberFromName('SIGUSR1'): + count += 1 + return count + + def do_thread_actions(self, + num_breakpoint_threads=0, + num_signal_threads=0, + num_watchpoint_threads=0, + num_crash_threads=0, + num_delay_breakpoint_threads=0, + num_delay_signal_threads=0, + num_delay_watchpoint_threads=0, + num_delay_crash_threads=0): + """ Sets a breakpoint in the main thread where test parameters (numbers of threads) can be adjusted, runs the inferior + to that point, and modifies the locals that control the event thread counts. Also sets a breakpoint in + breakpoint_func (the function executed by each 'breakpoint' thread) and a watchpoint on a global modified in + watchpoint_func. The inferior is continued until exit or a crash takes place, and the number of events seen by LLDB + is verified to match the expected number of events. + """ + exe = self.getBuildArtifact("a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + # Get the target + self.inferior_target = self.dbg.GetSelectedTarget() + + expected_bps = [] + + # Initialize all the breakpoints (main thread/aux thread) + self.setup_breakpoint = self.add_breakpoint( + self.setup_breakpoint_line, expected_bps) + self.finish_breakpoint = self.add_breakpoint( + self.finish_breakpoint_line, expected_bps) + + # Set the thread breakpoint + if num_breakpoint_threads + num_delay_breakpoint_threads > 0: + self.thread_breakpoint = self.add_breakpoint( + self.thread_breakpoint_line, expected_bps) + + # Verify breakpoints + self.expect( + "breakpoint list -f", + "Breakpoint locations shown correctly", + substrs=expected_bps) + + # Run the program. + self.runCmd("run", RUN_SUCCEEDED) + + # Check we are at line self.setup_breakpoint + self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT, + substrs=["stop reason = breakpoint 1."]) + + # Initialize the (single) watchpoint on the global variable (g_watchme) + if num_watchpoint_threads + num_delay_watchpoint_threads > 0: + self.runCmd("watchpoint set variable g_watchme") + for w in self.inferior_target.watchpoint_iter(): + self.thread_watchpoint = w + self.assertTrue( + "g_watchme" in str( + self.thread_watchpoint), + "Watchpoint location not shown correctly") + + # Get the process + self.inferior_process = self.inferior_target.GetProcess() + + # We should be stopped at the setup site where we can set the number of + # threads doing each action (break/crash/signal/watch) + self.assertEqual( + self.inferior_process.GetNumThreads(), + 1, + 'Expected to stop before any additional threads are spawned.') + + self.runCmd("expr num_breakpoint_threads=%d" % num_breakpoint_threads) + self.runCmd("expr num_crash_threads=%d" % num_crash_threads) + self.runCmd("expr num_signal_threads=%d" % num_signal_threads) + self.runCmd("expr num_watchpoint_threads=%d" % num_watchpoint_threads) + + self.runCmd( + "expr num_delay_breakpoint_threads=%d" % + num_delay_breakpoint_threads) + self.runCmd( + "expr num_delay_crash_threads=%d" % + num_delay_crash_threads) + self.runCmd( + "expr num_delay_signal_threads=%d" % + num_delay_signal_threads) + self.runCmd( + "expr num_delay_watchpoint_threads=%d" % + num_delay_watchpoint_threads) + + # Continue the inferior so threads are spawned + self.runCmd("continue") + + # Make sure we see all the threads. The inferior program's threads all synchronize with a pseudo-barrier; that is, + # the inferior program ensures all threads are started and running + # before any thread triggers its 'event'. + num_threads = self.inferior_process.GetNumThreads() + expected_num_threads = num_breakpoint_threads + num_delay_breakpoint_threads \ + + num_signal_threads + num_delay_signal_threads \ + + num_watchpoint_threads + num_delay_watchpoint_threads \ + + num_crash_threads + num_delay_crash_threads + 1 + self.assertEqual( + num_threads, + expected_num_threads, + 'Expected to see %d threads, but seeing %d. Details:\n%s' % + (expected_num_threads, + num_threads, + "\n\t".join( + self.describe_threads()))) + + self.signal_count = self.count_signaled_threads() + self.crash_count = len( + lldbutil.get_crashed_threads( + self, self.inferior_process)) + + # Run to completion (or crash) + while not self.inferior_done(): + if self.TraceOn(): + self.runCmd("thread backtrace all") + self.runCmd("continue") + self.signal_count += self.count_signaled_threads() + self.crash_count += len( + lldbutil.get_crashed_threads( + self, self.inferior_process)) + + if num_crash_threads > 0 or num_delay_crash_threads > 0: + # Expecting a crash + self.assertTrue( + self.crash_count > 0, + "Expecting at least one thread to crash. Details: %s" % + "\t\n".join( + self.describe_threads())) + + # Ensure the zombie process is reaped + self.runCmd("process kill") + + elif num_crash_threads == 0 and num_delay_crash_threads == 0: + # There should be a single active thread (the main one) which hit + # the breakpoint after joining + self.assertEqual( + 1, + self.finish_breakpoint.GetHitCount(), + "Expected main thread (finish) breakpoint to be hit once") + + num_threads = self.inferior_process.GetNumThreads() + self.assertEqual( + 1, + num_threads, + "Expecting 1 thread but seeing %d. Details:%s" % + (num_threads, + "\n\t".join( + self.describe_threads()))) + self.runCmd("continue") + + # The inferior process should have exited without crashing + self.assertEqual( + 0, + self.crash_count, + "Unexpected thread(s) in crashed state") + self.assertEqual( + self.inferior_process.GetState(), + lldb.eStateExited, + PROCESS_EXITED) + + # Verify the number of actions took place matches expected numbers + expected_breakpoint_threads = num_delay_breakpoint_threads + num_breakpoint_threads + breakpoint_hit_count = self.thread_breakpoint.GetHitCount( + ) if expected_breakpoint_threads > 0 else 0 + self.assertEqual( + expected_breakpoint_threads, + breakpoint_hit_count, + "Expected %d breakpoint hits, but got %d" % + (expected_breakpoint_threads, + breakpoint_hit_count)) + + expected_signal_threads = num_delay_signal_threads + num_signal_threads + self.assertEqual( + expected_signal_threads, + self.signal_count, + "Expected %d stops due to signal delivery, but got %d" % + (expected_signal_threads, + self.signal_count)) + + expected_watchpoint_threads = num_delay_watchpoint_threads + num_watchpoint_threads + watchpoint_hit_count = self.thread_watchpoint.GetHitCount( + ) if expected_watchpoint_threads > 0 else 0 + self.assertEqual( + expected_watchpoint_threads, + watchpoint_hit_count, + "Expected %d watchpoint hits, got %d" % + (expected_watchpoint_threads, + watchpoint_hit_count)) |