199451b44SJordan Rupprecht""" 299451b44SJordan RupprechtTest lldb Python event APIs. 399451b44SJordan Rupprecht""" 499451b44SJordan Rupprecht 599451b44SJordan Rupprechtfrom __future__ import print_function 699451b44SJordan Rupprecht 799451b44SJordan Rupprecht 899451b44SJordan Rupprechtimport re 999451b44SJordan Rupprechtimport lldb 1099451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 1199451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 1299451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil 1399451b44SJordan Rupprecht 1499451b44SJordan Rupprecht 1599451b44SJordan Rupprecht@skipIfLinux # llvm.org/pr25924, sometimes generating SIGSEGV 1699451b44SJordan Rupprechtclass EventAPITestCase(TestBase): 1799451b44SJordan Rupprecht NO_DEBUG_INFO_TESTCASE = True 1899451b44SJordan Rupprecht 1999451b44SJordan Rupprecht def setUp(self): 2099451b44SJordan Rupprecht # Call super's setUp(). 2199451b44SJordan Rupprecht TestBase.setUp(self) 2299451b44SJordan Rupprecht # Find the line number to of function 'c'. 2399451b44SJordan Rupprecht self.line = line_number( 2499451b44SJordan Rupprecht 'main.c', '// Find the line number of function "c" here.') 2599451b44SJordan Rupprecht 2699451b44SJordan Rupprecht @expectedFailureAll( 2799451b44SJordan Rupprecht oslist=["linux"], 2899451b44SJordan Rupprecht bugnumber="llvm.org/pr23730 Flaky, fails ~1/10 cases") 2999451b44SJordan Rupprecht @skipIfWindows # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr38373 3099451b44SJordan Rupprecht @skipIfNetBSD 3199451b44SJordan Rupprecht def test_listen_for_and_print_event(self): 3299451b44SJordan Rupprecht """Exercise SBEvent API.""" 3399451b44SJordan Rupprecht self.build() 3499451b44SJordan Rupprecht exe = self.getBuildArtifact("a.out") 3599451b44SJordan Rupprecht 3699451b44SJordan Rupprecht self.dbg.SetAsync(True) 3799451b44SJordan Rupprecht 3899451b44SJordan Rupprecht # Create a target by the debugger. 3999451b44SJordan Rupprecht target = self.dbg.CreateTarget(exe) 4099451b44SJordan Rupprecht self.assertTrue(target, VALID_TARGET) 4199451b44SJordan Rupprecht 4299451b44SJordan Rupprecht # Now create a breakpoint on main.c by name 'c'. 4399451b44SJordan Rupprecht breakpoint = target.BreakpointCreateByName('c', 'a.out') 4499451b44SJordan Rupprecht 4599451b44SJordan Rupprecht listener = lldb.SBListener("my listener") 4699451b44SJordan Rupprecht 4799451b44SJordan Rupprecht # Now launch the process, and do not stop at the entry point. 4899451b44SJordan Rupprecht error = lldb.SBError() 492ddba09eSJonas Devlieghere flags = target.GetLaunchInfo().GetLaunchFlags() 5099451b44SJordan Rupprecht process = target.Launch(listener, 5199451b44SJordan Rupprecht None, # argv 5299451b44SJordan Rupprecht None, # envp 5399451b44SJordan Rupprecht None, # stdin_path 5499451b44SJordan Rupprecht None, # stdout_path 5599451b44SJordan Rupprecht None, # stderr_path 5699451b44SJordan Rupprecht None, # working directory 572ddba09eSJonas Devlieghere flags, # launch flags 5899451b44SJordan Rupprecht False, # Stop at entry 5999451b44SJordan Rupprecht error) # error 6099451b44SJordan Rupprecht 610ed758b2SDave Lee self.assertEqual( 620ed758b2SDave Lee process.GetState(), lldb.eStateStopped, 6399451b44SJordan Rupprecht PROCESS_STOPPED) 6499451b44SJordan Rupprecht 6599451b44SJordan Rupprecht # Create an empty event object. 6699451b44SJordan Rupprecht event = lldb.SBEvent() 6799451b44SJordan Rupprecht 6899451b44SJordan Rupprecht traceOn = self.TraceOn() 6999451b44SJordan Rupprecht if traceOn: 7099451b44SJordan Rupprecht lldbutil.print_stacktraces(process) 7199451b44SJordan Rupprecht 7299451b44SJordan Rupprecht # Create MyListeningThread class to wait for any kind of event. 7399451b44SJordan Rupprecht import threading 7499451b44SJordan Rupprecht 7599451b44SJordan Rupprecht class MyListeningThread(threading.Thread): 7699451b44SJordan Rupprecht 7799451b44SJordan Rupprecht def run(self): 7899451b44SJordan Rupprecht count = 0 7999451b44SJordan Rupprecht # Let's only try at most 4 times to retrieve any kind of event. 8099451b44SJordan Rupprecht # After that, the thread exits. 8199451b44SJordan Rupprecht while not count > 3: 8299451b44SJordan Rupprecht if traceOn: 8399451b44SJordan Rupprecht print("Try wait for event...") 8499451b44SJordan Rupprecht if listener.WaitForEvent(5, event): 8599451b44SJordan Rupprecht if traceOn: 8699451b44SJordan Rupprecht desc = lldbutil.get_description(event) 8799451b44SJordan Rupprecht print("Event description:", desc) 8899451b44SJordan Rupprecht print("Event data flavor:", event.GetDataFlavor()) 8999451b44SJordan Rupprecht print( 9099451b44SJordan Rupprecht "Process state:", 9199451b44SJordan Rupprecht lldbutil.state_type_to_str( 9299451b44SJordan Rupprecht process.GetState())) 9399451b44SJordan Rupprecht print() 9499451b44SJordan Rupprecht else: 9599451b44SJordan Rupprecht if traceOn: 9699451b44SJordan Rupprecht print("timeout occurred waiting for event...") 9799451b44SJordan Rupprecht count = count + 1 9899451b44SJordan Rupprecht listener.Clear() 9999451b44SJordan Rupprecht return 10099451b44SJordan Rupprecht 10199451b44SJordan Rupprecht # Let's start the listening thread to retrieve the events. 10299451b44SJordan Rupprecht my_thread = MyListeningThread() 10399451b44SJordan Rupprecht my_thread.start() 10499451b44SJordan Rupprecht 10599451b44SJordan Rupprecht # Use Python API to continue the process. The listening thread should be 10699451b44SJordan Rupprecht # able to receive the state changed events. 10799451b44SJordan Rupprecht process.Continue() 10899451b44SJordan Rupprecht 10999451b44SJordan Rupprecht # Use Python API to kill the process. The listening thread should be 11099451b44SJordan Rupprecht # able to receive the state changed event, too. 11199451b44SJordan Rupprecht process.Kill() 11299451b44SJordan Rupprecht 11399451b44SJordan Rupprecht # Wait until the 'MyListeningThread' terminates. 11499451b44SJordan Rupprecht my_thread.join() 11599451b44SJordan Rupprecht 11699451b44SJordan Rupprecht # Shouldn't we be testing against some kind of expectation here? 11799451b44SJordan Rupprecht 11899451b44SJordan Rupprecht @expectedFlakeyLinux("llvm.org/pr23730") # Flaky, fails ~1/100 cases 11999451b44SJordan Rupprecht @skipIfWindows # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr38373 12099451b44SJordan Rupprecht @skipIfNetBSD 12199451b44SJordan Rupprecht def test_wait_for_event(self): 12299451b44SJordan Rupprecht """Exercise SBListener.WaitForEvent() API.""" 12399451b44SJordan Rupprecht self.build() 12499451b44SJordan Rupprecht exe = self.getBuildArtifact("a.out") 12599451b44SJordan Rupprecht 12699451b44SJordan Rupprecht self.dbg.SetAsync(True) 12799451b44SJordan Rupprecht 12899451b44SJordan Rupprecht # Create a target by the debugger. 12999451b44SJordan Rupprecht target = self.dbg.CreateTarget(exe) 13099451b44SJordan Rupprecht self.assertTrue(target, VALID_TARGET) 13199451b44SJordan Rupprecht 13299451b44SJordan Rupprecht # Now create a breakpoint on main.c by name 'c'. 13399451b44SJordan Rupprecht breakpoint = target.BreakpointCreateByName('c', 'a.out') 134b321b429SJonas Devlieghere self.trace("breakpoint:", breakpoint) 13599451b44SJordan Rupprecht self.assertTrue(breakpoint and 13699451b44SJordan Rupprecht breakpoint.GetNumLocations() == 1, 13799451b44SJordan Rupprecht VALID_BREAKPOINT) 13899451b44SJordan Rupprecht 13999451b44SJordan Rupprecht # Get the debugger listener. 14099451b44SJordan Rupprecht listener = self.dbg.GetListener() 14199451b44SJordan Rupprecht 14299451b44SJordan Rupprecht # Now launch the process, and do not stop at entry point. 14399451b44SJordan Rupprecht error = lldb.SBError() 1442ddba09eSJonas Devlieghere flags = target.GetLaunchInfo().GetLaunchFlags() 14599451b44SJordan Rupprecht process = target.Launch(listener, 14699451b44SJordan Rupprecht None, # argv 14799451b44SJordan Rupprecht None, # envp 14899451b44SJordan Rupprecht None, # stdin_path 14999451b44SJordan Rupprecht None, # stdout_path 15099451b44SJordan Rupprecht None, # stderr_path 15199451b44SJordan Rupprecht None, # working directory 1522ddba09eSJonas Devlieghere flags, # launch flags 15399451b44SJordan Rupprecht False, # Stop at entry 15499451b44SJordan Rupprecht error) # error 15599451b44SJordan Rupprecht self.assertTrue(error.Success() and process, PROCESS_IS_VALID) 15699451b44SJordan Rupprecht 15799451b44SJordan Rupprecht # Create an empty event object. 15899451b44SJordan Rupprecht event = lldb.SBEvent() 15999451b44SJordan Rupprecht self.assertFalse(event, "Event should not be valid initially") 16099451b44SJordan Rupprecht 16199451b44SJordan Rupprecht # Create MyListeningThread to wait for any kind of event. 16299451b44SJordan Rupprecht import threading 16399451b44SJordan Rupprecht 16499451b44SJordan Rupprecht class MyListeningThread(threading.Thread): 16599451b44SJordan Rupprecht 16699451b44SJordan Rupprecht def run(self): 16799451b44SJordan Rupprecht count = 0 16899451b44SJordan Rupprecht # Let's only try at most 3 times to retrieve any kind of event. 16999451b44SJordan Rupprecht while not count > 3: 17099451b44SJordan Rupprecht if listener.WaitForEvent(5, event): 171*2a29c3f7SMed Ismail Bennani self.context.trace("Got a valid event:", event) 172*2a29c3f7SMed Ismail Bennani self.context.trace("Event data flavor:", event.GetDataFlavor()) 173*2a29c3f7SMed Ismail Bennani self.context.trace("Event type:", lldbutil.state_type_to_str(event.GetType())) 17499451b44SJordan Rupprecht listener.Clear() 17599451b44SJordan Rupprecht return 17699451b44SJordan Rupprecht count = count + 1 17799451b44SJordan Rupprecht print("Timeout: listener.WaitForEvent") 17899451b44SJordan Rupprecht listener.Clear() 17999451b44SJordan Rupprecht return 18099451b44SJordan Rupprecht 18199451b44SJordan Rupprecht # Use Python API to kill the process. The listening thread should be 18299451b44SJordan Rupprecht # able to receive a state changed event. 18399451b44SJordan Rupprecht process.Kill() 18499451b44SJordan Rupprecht 18599451b44SJordan Rupprecht # Let's start the listening thread to retrieve the event. 18699451b44SJordan Rupprecht my_thread = MyListeningThread() 187*2a29c3f7SMed Ismail Bennani my_thread.context = self 18899451b44SJordan Rupprecht my_thread.start() 18999451b44SJordan Rupprecht 19099451b44SJordan Rupprecht # Wait until the 'MyListeningThread' terminates. 19199451b44SJordan Rupprecht my_thread.join() 19299451b44SJordan Rupprecht 19399451b44SJordan Rupprecht self.assertTrue(event, 19499451b44SJordan Rupprecht "My listening thread successfully received an event") 19599451b44SJordan Rupprecht 19699451b44SJordan Rupprecht @expectedFailureAll( 19799451b44SJordan Rupprecht oslist=["linux"], 19899451b44SJordan Rupprecht bugnumber="llvm.org/pr23617 Flaky, fails ~1/10 cases") 19999451b44SJordan Rupprecht @skipIfWindows # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr38373 20099562332SMichał Górny @expectedFailureNetBSD 20199451b44SJordan Rupprecht def test_add_listener_to_broadcaster(self): 20299451b44SJordan Rupprecht """Exercise some SBBroadcaster APIs.""" 20399451b44SJordan Rupprecht self.build() 20499451b44SJordan Rupprecht exe = self.getBuildArtifact("a.out") 20599451b44SJordan Rupprecht 20699451b44SJordan Rupprecht self.dbg.SetAsync(True) 20799451b44SJordan Rupprecht 20899451b44SJordan Rupprecht # Create a target by the debugger. 20999451b44SJordan Rupprecht target = self.dbg.CreateTarget(exe) 21099451b44SJordan Rupprecht self.assertTrue(target, VALID_TARGET) 21199451b44SJordan Rupprecht 21299451b44SJordan Rupprecht # Now create a breakpoint on main.c by name 'c'. 21399451b44SJordan Rupprecht breakpoint = target.BreakpointCreateByName('c', 'a.out') 214b321b429SJonas Devlieghere self.trace("breakpoint:", breakpoint) 21599451b44SJordan Rupprecht self.assertTrue(breakpoint and 21699451b44SJordan Rupprecht breakpoint.GetNumLocations() == 1, 21799451b44SJordan Rupprecht VALID_BREAKPOINT) 21899451b44SJordan Rupprecht 21999451b44SJordan Rupprecht listener = lldb.SBListener("my listener") 22099451b44SJordan Rupprecht 22199451b44SJordan Rupprecht # Now launch the process, and do not stop at the entry point. 22299451b44SJordan Rupprecht error = lldb.SBError() 2232ddba09eSJonas Devlieghere flags = target.GetLaunchInfo().GetLaunchFlags() 22499451b44SJordan Rupprecht process = target.Launch(listener, 22599451b44SJordan Rupprecht None, # argv 22699451b44SJordan Rupprecht None, # envp 22799451b44SJordan Rupprecht None, # stdin_path 22899451b44SJordan Rupprecht None, # stdout_path 22999451b44SJordan Rupprecht None, # stderr_path 23099451b44SJordan Rupprecht None, # working directory 2312ddba09eSJonas Devlieghere flags, # launch flags 23299451b44SJordan Rupprecht False, # Stop at entry 23399451b44SJordan Rupprecht error) # error 23499451b44SJordan Rupprecht 23599451b44SJordan Rupprecht # Create an empty event object. 23699451b44SJordan Rupprecht event = lldb.SBEvent() 23799451b44SJordan Rupprecht self.assertFalse(event, "Event should not be valid initially") 23899451b44SJordan Rupprecht 23999451b44SJordan Rupprecht # The finite state machine for our custom listening thread, with an 24099451b44SJordan Rupprecht # initial state of None, which means no event has been received. 24199451b44SJordan Rupprecht # It changes to 'connected' after 'connected' event is received (for remote platforms) 24299451b44SJordan Rupprecht # It changes to 'running' after 'running' event is received (should happen only if the 24399451b44SJordan Rupprecht # currentstate is either 'None' or 'connected') 24499451b44SJordan Rupprecht # It changes to 'stopped' if a 'stopped' event is received (should happen only if the 24599451b44SJordan Rupprecht # current state is 'running'.) 24699451b44SJordan Rupprecht self.state = None 24799451b44SJordan Rupprecht 24899451b44SJordan Rupprecht # Create MyListeningThread to wait for state changed events. 24999451b44SJordan Rupprecht # By design, a "running" event is expected following by a "stopped" 25099451b44SJordan Rupprecht # event. 25199451b44SJordan Rupprecht import threading 25299451b44SJordan Rupprecht 25399451b44SJordan Rupprecht class MyListeningThread(threading.Thread): 25499451b44SJordan Rupprecht 25599451b44SJordan Rupprecht def run(self): 256*2a29c3f7SMed Ismail Bennani self.context.trace("Running MyListeningThread:", self) 25799451b44SJordan Rupprecht 25899451b44SJordan Rupprecht # Regular expression pattern for the event description. 25999451b44SJordan Rupprecht pattern = re.compile("data = {.*, state = (.*)}$") 26099451b44SJordan Rupprecht 26199451b44SJordan Rupprecht # Let's only try at most 6 times to retrieve our events. 26299451b44SJordan Rupprecht count = 0 26399451b44SJordan Rupprecht while True: 26499451b44SJordan Rupprecht if listener.WaitForEvent(5, event): 26599451b44SJordan Rupprecht desc = lldbutil.get_description(event) 266*2a29c3f7SMed Ismail Bennani self.context.trace("Event description:", desc) 26799451b44SJordan Rupprecht match = pattern.search(desc) 26899451b44SJordan Rupprecht if not match: 26999451b44SJordan Rupprecht break 27099451b44SJordan Rupprecht if match.group(1) == 'connected': 27199451b44SJordan Rupprecht # When debugging remote targets with lldb-server, we 27299451b44SJordan Rupprecht # first get the 'connected' event. 27399451b44SJordan Rupprecht self.context.assertTrue(self.context.state is None) 27499451b44SJordan Rupprecht self.context.state = 'connected' 27599451b44SJordan Rupprecht continue 27699451b44SJordan Rupprecht elif match.group(1) == 'running': 27799451b44SJordan Rupprecht self.context.assertTrue( 27899451b44SJordan Rupprecht self.context.state is None or self.context.state == 'connected') 27999451b44SJordan Rupprecht self.context.state = 'running' 28099451b44SJordan Rupprecht continue 28199451b44SJordan Rupprecht elif match.group(1) == 'stopped': 28299451b44SJordan Rupprecht self.context.assertTrue( 28399451b44SJordan Rupprecht self.context.state == 'running') 28499451b44SJordan Rupprecht # Whoopee, both events have been received! 28599451b44SJordan Rupprecht self.context.state = 'stopped' 28699451b44SJordan Rupprecht break 28799451b44SJordan Rupprecht else: 28899451b44SJordan Rupprecht break 28999451b44SJordan Rupprecht print("Timeout: listener.WaitForEvent") 29099451b44SJordan Rupprecht count = count + 1 29199451b44SJordan Rupprecht if count > 6: 29299451b44SJordan Rupprecht break 29399451b44SJordan Rupprecht listener.Clear() 29499451b44SJordan Rupprecht return 29599451b44SJordan Rupprecht 29699451b44SJordan Rupprecht # Use Python API to continue the process. The listening thread should be 29799451b44SJordan Rupprecht # able to receive the state changed events. 29899451b44SJordan Rupprecht process.Continue() 29999451b44SJordan Rupprecht 30099451b44SJordan Rupprecht # Start the listening thread to receive the "running" followed by the 30199451b44SJordan Rupprecht # "stopped" events. 30299451b44SJordan Rupprecht my_thread = MyListeningThread() 30399451b44SJordan Rupprecht # Supply the enclosing context so that our listening thread can access 30499451b44SJordan Rupprecht # the 'state' variable. 30599451b44SJordan Rupprecht my_thread.context = self 30699451b44SJordan Rupprecht my_thread.start() 30799451b44SJordan Rupprecht 30899451b44SJordan Rupprecht # Wait until the 'MyListeningThread' terminates. 30999451b44SJordan Rupprecht my_thread.join() 31099451b44SJordan Rupprecht 31199451b44SJordan Rupprecht # The final judgement. :-) 312619e2e09SDave Lee self.assertEqual(self.state, 'stopped', 31399451b44SJordan Rupprecht "Both expected state changed events received") 314