1*99451b44SJordan Rupprecht""" 2*99451b44SJordan RupprechtTest lldb Python event APIs. 3*99451b44SJordan Rupprecht""" 4*99451b44SJordan Rupprecht 5*99451b44SJordan Rupprechtfrom __future__ import print_function 6*99451b44SJordan Rupprecht 7*99451b44SJordan Rupprecht 8*99451b44SJordan Rupprechtimport re 9*99451b44SJordan Rupprechtimport lldb 10*99451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 11*99451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 12*99451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil 13*99451b44SJordan Rupprecht 14*99451b44SJordan Rupprecht 15*99451b44SJordan Rupprecht@skipIfLinux # llvm.org/pr25924, sometimes generating SIGSEGV 16*99451b44SJordan Rupprecht@skipIfDarwin 17*99451b44SJordan Rupprechtclass EventAPITestCase(TestBase): 18*99451b44SJordan Rupprecht 19*99451b44SJordan Rupprecht mydir = TestBase.compute_mydir(__file__) 20*99451b44SJordan Rupprecht NO_DEBUG_INFO_TESTCASE = True 21*99451b44SJordan Rupprecht 22*99451b44SJordan Rupprecht def setUp(self): 23*99451b44SJordan Rupprecht # Call super's setUp(). 24*99451b44SJordan Rupprecht TestBase.setUp(self) 25*99451b44SJordan Rupprecht # Find the line number to of function 'c'. 26*99451b44SJordan Rupprecht self.line = line_number( 27*99451b44SJordan Rupprecht 'main.c', '// Find the line number of function "c" here.') 28*99451b44SJordan Rupprecht 29*99451b44SJordan Rupprecht @add_test_categories(['pyapi']) 30*99451b44SJordan Rupprecht @expectedFailureAll( 31*99451b44SJordan Rupprecht oslist=["linux"], 32*99451b44SJordan Rupprecht bugnumber="llvm.org/pr23730 Flaky, fails ~1/10 cases") 33*99451b44SJordan Rupprecht @skipIfWindows # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr38373 34*99451b44SJordan Rupprecht @skipIfNetBSD 35*99451b44SJordan Rupprecht def test_listen_for_and_print_event(self): 36*99451b44SJordan Rupprecht """Exercise SBEvent API.""" 37*99451b44SJordan Rupprecht self.build() 38*99451b44SJordan Rupprecht exe = self.getBuildArtifact("a.out") 39*99451b44SJordan Rupprecht 40*99451b44SJordan Rupprecht self.dbg.SetAsync(True) 41*99451b44SJordan Rupprecht 42*99451b44SJordan Rupprecht # Create a target by the debugger. 43*99451b44SJordan Rupprecht target = self.dbg.CreateTarget(exe) 44*99451b44SJordan Rupprecht self.assertTrue(target, VALID_TARGET) 45*99451b44SJordan Rupprecht 46*99451b44SJordan Rupprecht # Now create a breakpoint on main.c by name 'c'. 47*99451b44SJordan Rupprecht breakpoint = target.BreakpointCreateByName('c', 'a.out') 48*99451b44SJordan Rupprecht 49*99451b44SJordan Rupprecht listener = lldb.SBListener("my listener") 50*99451b44SJordan Rupprecht 51*99451b44SJordan Rupprecht # Now launch the process, and do not stop at the entry point. 52*99451b44SJordan Rupprecht error = lldb.SBError() 53*99451b44SJordan Rupprecht process = target.Launch(listener, 54*99451b44SJordan Rupprecht None, # argv 55*99451b44SJordan Rupprecht None, # envp 56*99451b44SJordan Rupprecht None, # stdin_path 57*99451b44SJordan Rupprecht None, # stdout_path 58*99451b44SJordan Rupprecht None, # stderr_path 59*99451b44SJordan Rupprecht None, # working directory 60*99451b44SJordan Rupprecht 0, # launch flags 61*99451b44SJordan Rupprecht False, # Stop at entry 62*99451b44SJordan Rupprecht error) # error 63*99451b44SJordan Rupprecht 64*99451b44SJordan Rupprecht self.assertTrue( 65*99451b44SJordan Rupprecht process.GetState() == lldb.eStateStopped, 66*99451b44SJordan Rupprecht PROCESS_STOPPED) 67*99451b44SJordan Rupprecht 68*99451b44SJordan Rupprecht # Create an empty event object. 69*99451b44SJordan Rupprecht event = lldb.SBEvent() 70*99451b44SJordan Rupprecht 71*99451b44SJordan Rupprecht traceOn = self.TraceOn() 72*99451b44SJordan Rupprecht if traceOn: 73*99451b44SJordan Rupprecht lldbutil.print_stacktraces(process) 74*99451b44SJordan Rupprecht 75*99451b44SJordan Rupprecht # Create MyListeningThread class to wait for any kind of event. 76*99451b44SJordan Rupprecht import threading 77*99451b44SJordan Rupprecht 78*99451b44SJordan Rupprecht class MyListeningThread(threading.Thread): 79*99451b44SJordan Rupprecht 80*99451b44SJordan Rupprecht def run(self): 81*99451b44SJordan Rupprecht count = 0 82*99451b44SJordan Rupprecht # Let's only try at most 4 times to retrieve any kind of event. 83*99451b44SJordan Rupprecht # After that, the thread exits. 84*99451b44SJordan Rupprecht while not count > 3: 85*99451b44SJordan Rupprecht if traceOn: 86*99451b44SJordan Rupprecht print("Try wait for event...") 87*99451b44SJordan Rupprecht if listener.WaitForEvent(5, event): 88*99451b44SJordan Rupprecht if traceOn: 89*99451b44SJordan Rupprecht desc = lldbutil.get_description(event) 90*99451b44SJordan Rupprecht print("Event description:", desc) 91*99451b44SJordan Rupprecht print("Event data flavor:", event.GetDataFlavor()) 92*99451b44SJordan Rupprecht print( 93*99451b44SJordan Rupprecht "Process state:", 94*99451b44SJordan Rupprecht lldbutil.state_type_to_str( 95*99451b44SJordan Rupprecht process.GetState())) 96*99451b44SJordan Rupprecht print() 97*99451b44SJordan Rupprecht else: 98*99451b44SJordan Rupprecht if traceOn: 99*99451b44SJordan Rupprecht print("timeout occurred waiting for event...") 100*99451b44SJordan Rupprecht count = count + 1 101*99451b44SJordan Rupprecht listener.Clear() 102*99451b44SJordan Rupprecht return 103*99451b44SJordan Rupprecht 104*99451b44SJordan Rupprecht # Let's start the listening thread to retrieve the events. 105*99451b44SJordan Rupprecht my_thread = MyListeningThread() 106*99451b44SJordan Rupprecht my_thread.start() 107*99451b44SJordan Rupprecht 108*99451b44SJordan Rupprecht # Use Python API to continue the process. The listening thread should be 109*99451b44SJordan Rupprecht # able to receive the state changed events. 110*99451b44SJordan Rupprecht process.Continue() 111*99451b44SJordan Rupprecht 112*99451b44SJordan Rupprecht # Use Python API to kill the process. The listening thread should be 113*99451b44SJordan Rupprecht # able to receive the state changed event, too. 114*99451b44SJordan Rupprecht process.Kill() 115*99451b44SJordan Rupprecht 116*99451b44SJordan Rupprecht # Wait until the 'MyListeningThread' terminates. 117*99451b44SJordan Rupprecht my_thread.join() 118*99451b44SJordan Rupprecht 119*99451b44SJordan Rupprecht # Shouldn't we be testing against some kind of expectation here? 120*99451b44SJordan Rupprecht 121*99451b44SJordan Rupprecht @add_test_categories(['pyapi']) 122*99451b44SJordan Rupprecht @expectedFlakeyLinux("llvm.org/pr23730") # Flaky, fails ~1/100 cases 123*99451b44SJordan Rupprecht @skipIfWindows # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr38373 124*99451b44SJordan Rupprecht @skipIfNetBSD 125*99451b44SJordan Rupprecht def test_wait_for_event(self): 126*99451b44SJordan Rupprecht """Exercise SBListener.WaitForEvent() API.""" 127*99451b44SJordan Rupprecht self.build() 128*99451b44SJordan Rupprecht exe = self.getBuildArtifact("a.out") 129*99451b44SJordan Rupprecht 130*99451b44SJordan Rupprecht self.dbg.SetAsync(True) 131*99451b44SJordan Rupprecht 132*99451b44SJordan Rupprecht # Create a target by the debugger. 133*99451b44SJordan Rupprecht target = self.dbg.CreateTarget(exe) 134*99451b44SJordan Rupprecht self.assertTrue(target, VALID_TARGET) 135*99451b44SJordan Rupprecht 136*99451b44SJordan Rupprecht # Now create a breakpoint on main.c by name 'c'. 137*99451b44SJordan Rupprecht breakpoint = target.BreakpointCreateByName('c', 'a.out') 138*99451b44SJordan Rupprecht #print("breakpoint:", breakpoint) 139*99451b44SJordan Rupprecht self.assertTrue(breakpoint and 140*99451b44SJordan Rupprecht breakpoint.GetNumLocations() == 1, 141*99451b44SJordan Rupprecht VALID_BREAKPOINT) 142*99451b44SJordan Rupprecht 143*99451b44SJordan Rupprecht # Get the debugger listener. 144*99451b44SJordan Rupprecht listener = self.dbg.GetListener() 145*99451b44SJordan Rupprecht 146*99451b44SJordan Rupprecht # Now launch the process, and do not stop at entry point. 147*99451b44SJordan Rupprecht error = lldb.SBError() 148*99451b44SJordan Rupprecht process = target.Launch(listener, 149*99451b44SJordan Rupprecht None, # argv 150*99451b44SJordan Rupprecht None, # envp 151*99451b44SJordan Rupprecht None, # stdin_path 152*99451b44SJordan Rupprecht None, # stdout_path 153*99451b44SJordan Rupprecht None, # stderr_path 154*99451b44SJordan Rupprecht None, # working directory 155*99451b44SJordan Rupprecht 0, # launch flags 156*99451b44SJordan Rupprecht False, # Stop at entry 157*99451b44SJordan Rupprecht error) # error 158*99451b44SJordan Rupprecht self.assertTrue(error.Success() and process, PROCESS_IS_VALID) 159*99451b44SJordan Rupprecht 160*99451b44SJordan Rupprecht # Create an empty event object. 161*99451b44SJordan Rupprecht event = lldb.SBEvent() 162*99451b44SJordan Rupprecht self.assertFalse(event, "Event should not be valid initially") 163*99451b44SJordan Rupprecht 164*99451b44SJordan Rupprecht # Create MyListeningThread to wait for any kind of event. 165*99451b44SJordan Rupprecht import threading 166*99451b44SJordan Rupprecht 167*99451b44SJordan Rupprecht class MyListeningThread(threading.Thread): 168*99451b44SJordan Rupprecht 169*99451b44SJordan Rupprecht def run(self): 170*99451b44SJordan Rupprecht count = 0 171*99451b44SJordan Rupprecht # Let's only try at most 3 times to retrieve any kind of event. 172*99451b44SJordan Rupprecht while not count > 3: 173*99451b44SJordan Rupprecht if listener.WaitForEvent(5, event): 174*99451b44SJordan Rupprecht #print("Got a valid event:", event) 175*99451b44SJordan Rupprecht #print("Event data flavor:", event.GetDataFlavor()) 176*99451b44SJordan Rupprecht #print("Event type:", lldbutil.state_type_to_str(event.GetType())) 177*99451b44SJordan Rupprecht listener.Clear() 178*99451b44SJordan Rupprecht return 179*99451b44SJordan Rupprecht count = count + 1 180*99451b44SJordan Rupprecht print("Timeout: listener.WaitForEvent") 181*99451b44SJordan Rupprecht listener.Clear() 182*99451b44SJordan Rupprecht return 183*99451b44SJordan Rupprecht 184*99451b44SJordan Rupprecht # Use Python API to kill the process. The listening thread should be 185*99451b44SJordan Rupprecht # able to receive a state changed event. 186*99451b44SJordan Rupprecht process.Kill() 187*99451b44SJordan Rupprecht 188*99451b44SJordan Rupprecht # Let's start the listening thread to retrieve the event. 189*99451b44SJordan Rupprecht my_thread = MyListeningThread() 190*99451b44SJordan Rupprecht my_thread.start() 191*99451b44SJordan Rupprecht 192*99451b44SJordan Rupprecht # Wait until the 'MyListeningThread' terminates. 193*99451b44SJordan Rupprecht my_thread.join() 194*99451b44SJordan Rupprecht 195*99451b44SJordan Rupprecht self.assertTrue(event, 196*99451b44SJordan Rupprecht "My listening thread successfully received an event") 197*99451b44SJordan Rupprecht 198*99451b44SJordan Rupprecht @skipIfFreeBSD # llvm.org/pr21325 199*99451b44SJordan Rupprecht @add_test_categories(['pyapi']) 200*99451b44SJordan Rupprecht @expectedFailureAll( 201*99451b44SJordan Rupprecht oslist=["linux"], 202*99451b44SJordan Rupprecht bugnumber="llvm.org/pr23617 Flaky, fails ~1/10 cases") 203*99451b44SJordan Rupprecht @skipIfWindows # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr38373 204*99451b44SJordan Rupprecht @expectedFlakeyNetBSD 205*99451b44SJordan Rupprecht def test_add_listener_to_broadcaster(self): 206*99451b44SJordan Rupprecht """Exercise some SBBroadcaster APIs.""" 207*99451b44SJordan Rupprecht self.build() 208*99451b44SJordan Rupprecht exe = self.getBuildArtifact("a.out") 209*99451b44SJordan Rupprecht 210*99451b44SJordan Rupprecht self.dbg.SetAsync(True) 211*99451b44SJordan Rupprecht 212*99451b44SJordan Rupprecht # Create a target by the debugger. 213*99451b44SJordan Rupprecht target = self.dbg.CreateTarget(exe) 214*99451b44SJordan Rupprecht self.assertTrue(target, VALID_TARGET) 215*99451b44SJordan Rupprecht 216*99451b44SJordan Rupprecht # Now create a breakpoint on main.c by name 'c'. 217*99451b44SJordan Rupprecht breakpoint = target.BreakpointCreateByName('c', 'a.out') 218*99451b44SJordan Rupprecht #print("breakpoint:", breakpoint) 219*99451b44SJordan Rupprecht self.assertTrue(breakpoint and 220*99451b44SJordan Rupprecht breakpoint.GetNumLocations() == 1, 221*99451b44SJordan Rupprecht VALID_BREAKPOINT) 222*99451b44SJordan Rupprecht 223*99451b44SJordan Rupprecht listener = lldb.SBListener("my listener") 224*99451b44SJordan Rupprecht 225*99451b44SJordan Rupprecht # Now launch the process, and do not stop at the entry point. 226*99451b44SJordan Rupprecht error = lldb.SBError() 227*99451b44SJordan Rupprecht process = target.Launch(listener, 228*99451b44SJordan Rupprecht None, # argv 229*99451b44SJordan Rupprecht None, # envp 230*99451b44SJordan Rupprecht None, # stdin_path 231*99451b44SJordan Rupprecht None, # stdout_path 232*99451b44SJordan Rupprecht None, # stderr_path 233*99451b44SJordan Rupprecht None, # working directory 234*99451b44SJordan Rupprecht 0, # launch flags 235*99451b44SJordan Rupprecht False, # Stop at entry 236*99451b44SJordan Rupprecht error) # error 237*99451b44SJordan Rupprecht 238*99451b44SJordan Rupprecht # Create an empty event object. 239*99451b44SJordan Rupprecht event = lldb.SBEvent() 240*99451b44SJordan Rupprecht self.assertFalse(event, "Event should not be valid initially") 241*99451b44SJordan Rupprecht 242*99451b44SJordan Rupprecht # The finite state machine for our custom listening thread, with an 243*99451b44SJordan Rupprecht # initial state of None, which means no event has been received. 244*99451b44SJordan Rupprecht # It changes to 'connected' after 'connected' event is received (for remote platforms) 245*99451b44SJordan Rupprecht # It changes to 'running' after 'running' event is received (should happen only if the 246*99451b44SJordan Rupprecht # currentstate is either 'None' or 'connected') 247*99451b44SJordan Rupprecht # It changes to 'stopped' if a 'stopped' event is received (should happen only if the 248*99451b44SJordan Rupprecht # current state is 'running'.) 249*99451b44SJordan Rupprecht self.state = None 250*99451b44SJordan Rupprecht 251*99451b44SJordan Rupprecht # Create MyListeningThread to wait for state changed events. 252*99451b44SJordan Rupprecht # By design, a "running" event is expected following by a "stopped" 253*99451b44SJordan Rupprecht # event. 254*99451b44SJordan Rupprecht import threading 255*99451b44SJordan Rupprecht 256*99451b44SJordan Rupprecht class MyListeningThread(threading.Thread): 257*99451b44SJordan Rupprecht 258*99451b44SJordan Rupprecht def run(self): 259*99451b44SJordan Rupprecht #print("Running MyListeningThread:", self) 260*99451b44SJordan Rupprecht 261*99451b44SJordan Rupprecht # Regular expression pattern for the event description. 262*99451b44SJordan Rupprecht pattern = re.compile("data = {.*, state = (.*)}$") 263*99451b44SJordan Rupprecht 264*99451b44SJordan Rupprecht # Let's only try at most 6 times to retrieve our events. 265*99451b44SJordan Rupprecht count = 0 266*99451b44SJordan Rupprecht while True: 267*99451b44SJordan Rupprecht if listener.WaitForEvent(5, event): 268*99451b44SJordan Rupprecht desc = lldbutil.get_description(event) 269*99451b44SJordan Rupprecht #print("Event description:", desc) 270*99451b44SJordan Rupprecht match = pattern.search(desc) 271*99451b44SJordan Rupprecht if not match: 272*99451b44SJordan Rupprecht break 273*99451b44SJordan Rupprecht if match.group(1) == 'connected': 274*99451b44SJordan Rupprecht # When debugging remote targets with lldb-server, we 275*99451b44SJordan Rupprecht # first get the 'connected' event. 276*99451b44SJordan Rupprecht self.context.assertTrue(self.context.state is None) 277*99451b44SJordan Rupprecht self.context.state = 'connected' 278*99451b44SJordan Rupprecht continue 279*99451b44SJordan Rupprecht elif match.group(1) == 'running': 280*99451b44SJordan Rupprecht self.context.assertTrue( 281*99451b44SJordan Rupprecht self.context.state is None or self.context.state == 'connected') 282*99451b44SJordan Rupprecht self.context.state = 'running' 283*99451b44SJordan Rupprecht continue 284*99451b44SJordan Rupprecht elif match.group(1) == 'stopped': 285*99451b44SJordan Rupprecht self.context.assertTrue( 286*99451b44SJordan Rupprecht self.context.state == 'running') 287*99451b44SJordan Rupprecht # Whoopee, both events have been received! 288*99451b44SJordan Rupprecht self.context.state = 'stopped' 289*99451b44SJordan Rupprecht break 290*99451b44SJordan Rupprecht else: 291*99451b44SJordan Rupprecht break 292*99451b44SJordan Rupprecht print("Timeout: listener.WaitForEvent") 293*99451b44SJordan Rupprecht count = count + 1 294*99451b44SJordan Rupprecht if count > 6: 295*99451b44SJordan Rupprecht break 296*99451b44SJordan Rupprecht listener.Clear() 297*99451b44SJordan Rupprecht return 298*99451b44SJordan Rupprecht 299*99451b44SJordan Rupprecht # Use Python API to continue the process. The listening thread should be 300*99451b44SJordan Rupprecht # able to receive the state changed events. 301*99451b44SJordan Rupprecht process.Continue() 302*99451b44SJordan Rupprecht 303*99451b44SJordan Rupprecht # Start the listening thread to receive the "running" followed by the 304*99451b44SJordan Rupprecht # "stopped" events. 305*99451b44SJordan Rupprecht my_thread = MyListeningThread() 306*99451b44SJordan Rupprecht # Supply the enclosing context so that our listening thread can access 307*99451b44SJordan Rupprecht # the 'state' variable. 308*99451b44SJordan Rupprecht my_thread.context = self 309*99451b44SJordan Rupprecht my_thread.start() 310*99451b44SJordan Rupprecht 311*99451b44SJordan Rupprecht # Wait until the 'MyListeningThread' terminates. 312*99451b44SJordan Rupprecht my_thread.join() 313*99451b44SJordan Rupprecht 314*99451b44SJordan Rupprecht # The final judgement. :-) 315*99451b44SJordan Rupprecht self.assertTrue(self.state == 'stopped', 316*99451b44SJordan Rupprecht "Both expected state changed events received") 317