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