Home | History | Annotate | Download | only in call-restarts
      1 """
      2 Test calling a function that hits a signal set to auto-restart, make sure the call completes.
      3 """
      4 
      5 import unittest2
      6 import lldb
      7 import lldbutil
      8 from lldbtest import *
      9 
     10 class ExprCommandWithTimeoutsTestCase(TestBase):
     11 
     12     mydir = os.path.join("expression_command", "call-restarts")
     13 
     14     def setUp(self):
     15         # Call super's setUp().
     16         TestBase.setUp(self)
     17 
     18         self.main_source = "lotta-signals.c"
     19         self.main_source_spec = lldb.SBFileSpec (self.main_source)
     20 
     21 
     22     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     23     @dsym_test
     24     def test_with_dsym(self):
     25         """Test calling std::String member function."""
     26         self.buildDsym()
     27         self.call_function()
     28 
     29     @skipIfLinux # llvm.org/pr15278: handle expressions that generate signals on Linux
     30     @dwarf_test
     31     def test_with_dwarf(self):
     32         """Test calling std::String member function."""
     33         self.buildDwarf()
     34         self.call_function()
     35 
     36     def check_after_call (self, num_sigchld):
     37         after_call = self.sigchld_no.GetValueAsSigned(-1)
     38         self.assertTrue (after_call - self.start_sigchld_no == num_sigchld, "Really got %d SIGCHLD signals through the call."%(num_sigchld))
     39         self.start_sigchld_no = after_call
     40 
     41         # Check that we are back where we were before:
     42         frame = self.thread.GetFrameAtIndex(0)
     43         self.assertTrue (self.orig_frame_pc == frame.GetPC(), "Restored the zeroth frame correctly")
     44 
     45         
     46     def call_function(self):
     47         """Test calling function with timeout."""
     48         exe_name = "a.out"
     49         exe = os.path.join(os.getcwd(), exe_name)
     50 
     51         target = self.dbg.CreateTarget(exe)
     52         self.assertTrue(target, VALID_TARGET)
     53         empty = lldb.SBFileSpec()
     54         breakpoint = target.BreakpointCreateBySourceRegex('Stop here in main.',self.main_source_spec)
     55         self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT)
     56 
     57         # Launch the process, and do not stop at the entry point.
     58         process = target.LaunchSimple(None, None, os.getcwd())
     59 
     60         self.assertTrue(process, PROCESS_IS_VALID)
     61 
     62         # Frame #0 should be at our breakpoint.
     63         threads = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint)
     64         
     65         self.assertTrue(len(threads) == 1)
     66         self.thread = threads[0]
     67         
     68         # Make sure the SIGCHLD behavior is pass/no-stop/no-notify:
     69         return_obj = lldb.SBCommandReturnObject()
     70         self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 0 -p 1 -n 0", return_obj)
     71         self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, no-stop")
     72 
     73         # The sigchld_no variable should be 0 at this point.
     74         self.sigchld_no = target.FindFirstGlobalVariable("sigchld_no")
     75         self.assertTrue (self.sigchld_no.IsValid(), "Got a value for sigchld_no")
     76 
     77         self.start_sigchld_no = self.sigchld_no.GetValueAsSigned (-1)
     78         self.assertTrue (self.start_sigchld_no != -1, "Got an actual value for sigchld_no")
     79 
     80         options = lldb.SBExpressionOptions()
     81         options.SetUnwindOnError(True)
     82 
     83         frame = self.thread.GetFrameAtIndex(0)
     84         # Store away the PC to check that the functions unwind to the right place after calls
     85         self.orig_frame_pc = frame.GetPC()
     86 
     87         num_sigchld = 30
     88         value = frame.EvaluateExpression ("call_me (%d)"%(num_sigchld), options)
     89         self.assertTrue (value.IsValid())
     90         self.assertTrue (value.GetError().Success() == True)
     91         self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld)
     92 
     93         self.check_after_call(num_sigchld)
     94 
     95         # Okay, now try with a breakpoint in the called code in the case where
     96         # we are ignoring breakpoint hits.
     97         handler_bkpt = target.BreakpointCreateBySourceRegex("Got sigchld %d.", self.main_source_spec)
     98         self.assertTrue (handler_bkpt.GetNumLocations() > 0)
     99         options.SetIgnoreBreakpoints(True)
    100         options.SetUnwindOnError(True)
    101 
    102         value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options)
    103 
    104         self.assertTrue (value.IsValid() and value.GetError().Success() == True)
    105         self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld)
    106         self.check_after_call(num_sigchld)
    107 
    108         # Now set the signal to print but not stop and make sure that calling still works:
    109         self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 0 -p 1 -n 1", return_obj)
    110         self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, no-stop, notify")
    111 
    112         value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options)
    113 
    114         self.assertTrue (value.IsValid() and value.GetError().Success() == True)
    115         self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld)
    116         self.check_after_call(num_sigchld)
    117 
    118         # Now set this unwind on error to false, and make sure that we still complete the call:
    119         options.SetUnwindOnError(False)
    120         value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options)
    121 
    122         self.assertTrue (value.IsValid() and value.GetError().Success() == True)
    123         self.assertTrue (value.GetValueAsSigned(-1) == num_sigchld)
    124         self.check_after_call(num_sigchld)
    125 
    126         # Okay, now set UnwindOnError to true, and then make the signal behavior to stop
    127         # and see that now we do stop at the signal point:
    128         
    129         self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 1 -p 1 -n 1", return_obj)
    130         self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, stop, notify")
    131         
    132         value = frame.EvaluateExpression("call_me (%d)"%(num_sigchld), options)
    133         self.assertTrue (value.IsValid() and value.GetError().Success() == False)
    134         
    135         # Set signal handling back to no-stop, and continue and we should end up back in out starting frame:
    136         self.dbg.GetCommandInterpreter().HandleCommand("process handle SIGCHLD -s 0 -p 1 -n 1", return_obj)
    137         self.assertTrue (return_obj.Succeeded() == True, "Set SIGCHLD to pass, no-stop, notify")
    138 
    139         error = process.Continue()
    140         self.assertTrue (error.Success(), "Continuing after stopping for signal succeeds.")
    141         
    142         frame = self.thread.GetFrameAtIndex(0)
    143         self.assertTrue (frame.GetPC() == self.orig_frame_pc, "Continuing returned to the place we started.")
    144         
    145 if __name__ == '__main__':
    146     import atexit
    147     lldb.SBDebugger.Initialize()
    148     atexit.register(lambda: lldb.SBDebugger.Terminate())
    149     unittest2.main()
    150