1""" 2Test calling a function that hits a signal set to auto-restart, make sure the call completes. 3""" 4 5 6import lldb 7from lldbsuite.test.decorators import * 8from lldbsuite.test.lldbtest import * 9from lldbsuite.test import lldbutil 10 11 12class ExprCommandThatRestartsTestCase(TestBase): 13 NO_DEBUG_INFO_TESTCASE = True 14 15 def setUp(self): 16 # Call super's setUp(). 17 TestBase.setUp(self) 18 19 self.main_source = "lotta-signals.c" 20 self.main_source_spec = lldb.SBFileSpec(self.main_source) 21 22 @skipIfDarwin # llvm.org/pr19246: intermittent failure 23 @skipIfWindows # Test relies on signals, unsupported on Windows 24 @expectedFlakeyAndroid(bugnumber="llvm.org/pr19246") 25 @expectedFlakeyNetBSD 26 def test(self): 27 """Test calling function that hits a signal and restarts.""" 28 self.build() 29 self.call_function() 30 31 def check_after_call(self, num_sigchld): 32 after_call = self.sigchld_no.GetValueAsSigned(-1) 33 self.assertEqual( 34 after_call - self.start_sigchld_no, 35 num_sigchld, 36 "Really got %d SIGCHLD signals through the call." % (num_sigchld), 37 ) 38 self.start_sigchld_no = after_call 39 40 # Check that we are back where we were before: 41 frame = self.thread.GetFrameAtIndex(0) 42 self.assertEqual( 43 self.orig_frame_pc, frame.GetPC(), "Restored the zeroth frame correctly" 44 ) 45 46 def call_function(self): 47 (target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint( 48 self, "Stop here in main.", self.main_source_spec 49 ) 50 51 # Make sure the SIGCHLD behavior is pass/no-stop/no-notify: 52 self.runCmd("process handle SIGCHLD -s 0 -p 1 -n 0") 53 54 # The sigchld_no variable should be 0 at this point. 55 self.sigchld_no = target.FindFirstGlobalVariable("sigchld_no") 56 self.assertTrue(self.sigchld_no.IsValid(), "Got a value for sigchld_no") 57 58 self.start_sigchld_no = self.sigchld_no.GetValueAsSigned(-1) 59 self.assertNotEqual( 60 self.start_sigchld_no, -1, "Got an actual value for sigchld_no" 61 ) 62 63 options = lldb.SBExpressionOptions() 64 # processing 30 signals takes a while, increase the expression timeout 65 # a bit 66 options.SetTimeoutInMicroSeconds(3000000) # 3s 67 options.SetUnwindOnError(True) 68 69 frame = self.thread.GetFrameAtIndex(0) 70 # Store away the PC to check that the functions unwind to the right 71 # place after calls 72 self.orig_frame_pc = frame.GetPC() 73 74 num_sigchld = 30 75 value = frame.EvaluateExpression("call_me (%d)" % (num_sigchld), options) 76 self.assertTrue(value.IsValid()) 77 self.assertSuccess(value.GetError()) 78 self.assertEqual(value.GetValueAsSigned(-1), num_sigchld) 79 80 self.check_after_call(num_sigchld) 81 82 # Okay, now try with a breakpoint in the called code in the case where 83 # we are ignoring breakpoint hits. 84 handler_bkpt = target.BreakpointCreateBySourceRegex( 85 "Got sigchld %d.", self.main_source_spec 86 ) 87 self.assertGreater(handler_bkpt.GetNumLocations(), 0) 88 options.SetIgnoreBreakpoints(True) 89 options.SetUnwindOnError(True) 90 91 value = frame.EvaluateExpression("call_me (%d)" % (num_sigchld), options) 92 93 self.assertTrue(value.IsValid()) 94 self.assertSuccess(value.GetError()) 95 self.assertEqual(value.GetValueAsSigned(-1), num_sigchld) 96 self.check_after_call(num_sigchld) 97 98 # Now set the signal to print but not stop and make sure that calling 99 # still works: 100 self.runCmd("process handle SIGCHLD -s 0 -p 1 -n 1") 101 102 value = frame.EvaluateExpression("call_me (%d)" % (num_sigchld), options) 103 104 self.assertTrue(value.IsValid()) 105 self.assertSuccess(value.GetError()) 106 self.assertEqual(value.GetValueAsSigned(-1), num_sigchld) 107 self.check_after_call(num_sigchld) 108 109 # Now set this unwind on error to false, and make sure that we still 110 # complete the call: 111 options.SetUnwindOnError(False) 112 value = frame.EvaluateExpression("call_me (%d)" % (num_sigchld), options) 113 114 self.assertTrue(value.IsValid()) 115 self.assertSuccess(value.GetError()) 116 self.assertEqual(value.GetValueAsSigned(-1), num_sigchld) 117 self.check_after_call(num_sigchld) 118 119 # Okay, now set UnwindOnError to true, and then make the signal behavior to stop 120 # and see that now we do stop at the signal point: 121 122 self.runCmd("process handle SIGCHLD -s 1 -p 1 -n 1") 123 124 value = frame.EvaluateExpression("call_me (%d)" % (num_sigchld), options) 125 self.assertTrue(value.IsValid()) 126 self.assertFalse(value.GetError().Success()) 127 128 # Set signal handling back to no-stop, and continue and we should end 129 # up back in out starting frame: 130 self.runCmd("process handle SIGCHLD -s 0 -p 1 -n 1") 131 132 error = process.Continue() 133 self.assertSuccess(error, "Continuing after stopping for signal succeeds.") 134 135 frame = self.thread.GetFrameAtIndex(0) 136 self.assertEqual( 137 frame.GetPC(), 138 self.orig_frame_pc, 139 "Continuing returned to the place we started.", 140 ) 141