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