1""" 2Test stop hook functionality 3""" 4 5 6 7import lldb 8import lldbsuite.test.lldbutil as lldbutil 9from lldbsuite.test.lldbtest import * 10from lldbsuite.test.decorators import * 11 12class TestStopHooks(TestBase): 13 14 mydir = TestBase.compute_mydir(__file__) 15 16 # If your test case doesn't stress debug info, the 17 # set this to true. That way it won't be run once for 18 # each debug info format. 19 NO_DEBUG_INFO_TESTCASE = True 20 21 def setUp(self): 22 TestBase.setUp(self) 23 self.build() 24 self.main_source_file = lldb.SBFileSpec("main.c") 25 full_path = os.path.join(self.getSourceDir(), "main.c") 26 self.main_start_line = line_number(full_path, "main()") 27 28 def test_bad_handler(self): 29 """Test that we give a good error message when the handler is bad""" 30 self.script_setup() 31 result = lldb.SBCommandReturnObject() 32 33 # First try the wrong number of args handler: 34 command = "target stop-hook add -P stop_hook.bad_handle_stop" 35 self.interp.HandleCommand(command, result) 36 self.assertFalse(result.Succeeded(), "Set the target stop hook") 37 self.assertIn("Wrong number of args", result.GetError(), "Got the wrong number of args error") 38 39 # Next the no handler at all handler: 40 command = "target stop-hook add -P stop_hook.no_handle_stop" 41 42 self.interp.HandleCommand(command, result) 43 self.assertFalse(result.Succeeded(), "Set the target stop hook") 44 self.assertIn('Class "stop_hook.no_handle_stop" is missing the required handle_stop callback', result.GetError(), "Got the right error") 45 46 def test_stop_hooks_scripted(self): 47 """Test that a scripted stop hook works with no specifiers""" 48 self.stop_hooks_scripted(5) 49 50 def test_stop_hooks_scripted_right_func(self): 51 """Test that a scripted stop hook fires when there is a function match""" 52 self.stop_hooks_scripted(5, "-n step_out_of_me") 53 54 def test_stop_hooks_scripted_wrong_func(self): 55 """Test that a scripted stop hook doesn't fire when the function does not match""" 56 self.stop_hooks_scripted(0, "-n main") 57 58 def test_stop_hooks_scripted_right_lines(self): 59 """Test that a scripted stop hook fires when there is a function match""" 60 self.stop_hooks_scripted(5, "-f main.c -l 1 -e %d"%(self.main_start_line)) 61 62 def test_stop_hooks_scripted_wrong_lines(self): 63 """Test that a scripted stop hook doesn't fire when the function does not match""" 64 self.stop_hooks_scripted(0, "-f main.c -l %d -e 100"%(self.main_start_line)) 65 66 def test_stop_hooks_scripted_auto_continue(self): 67 """Test that the --auto-continue flag works""" 68 self.do_test_auto_continue(False) 69 70 def test_stop_hooks_scripted_return_false(self): 71 """Test that the returning False from a stop hook works""" 72 self.do_test_auto_continue(True) 73 74 def do_test_auto_continue(self, return_true): 75 """Test that auto-continue works.""" 76 # We set auto-continue to 1 but the stop hook only applies to step_out_of_me, 77 # so we should end up stopped in main, having run the expression only once. 78 self.script_setup() 79 80 result = lldb.SBCommandReturnObject() 81 82 if return_true: 83 command = "target stop-hook add -P stop_hook.stop_handler -k increment -v 5 -k return_false -v 1 -n step_out_of_me" 84 else: 85 command = "target stop-hook add -G 1 -P stop_hook.stop_handler -k increment -v 5 -n step_out_of_me" 86 87 self.interp.HandleCommand(command, result) 88 self.assertTrue(result.Succeeded, "Set the target stop hook") 89 90 # First run to main. If we go straight to the first stop hook hit, 91 # run_to_source_breakpoint will fail because we aren't at original breakpoint 92 93 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, 94 "Stop here first", self.main_source_file) 95 96 # Now set the breakpoint on step_out_of_me, and make sure we run the 97 # expression, then continue back to main. 98 bkpt = target.BreakpointCreateBySourceRegex("Set a breakpoint here and step out", self.main_source_file) 99 self.assertTrue(bkpt.GetNumLocations() > 0, "Got breakpoints in step_out_of_me") 100 process.Continue() 101 102 var = target.FindFirstGlobalVariable("g_var") 103 self.assertTrue(var.IsValid()) 104 self.assertEqual(var.GetValueAsUnsigned(), 5, "Updated g_var") 105 106 func_name = process.GetSelectedThread().frames[0].GetFunctionName() 107 self.assertEqual("main", func_name, "Didn't stop at the expected function.") 108 109 def script_setup(self): 110 self.interp = self.dbg.GetCommandInterpreter() 111 result = lldb.SBCommandReturnObject() 112 113 # Bring in our script file: 114 script_name = os.path.join(self.getSourceDir(), "stop_hook.py") 115 command = "command script import " + script_name 116 self.interp.HandleCommand(command, result) 117 self.assertTrue(result.Succeeded(), "com scr imp failed: %s"%(result.GetError())) 118 119 # set a breakpoint at the end of main to catch our auto-continue tests. 120 # Do it in the dummy target so it will get copied to our target even when 121 # we don't have a chance to stop. 122 dummy_target = self.dbg.GetDummyTarget() 123 dummy_target.BreakpointCreateBySourceRegex("return result", self.main_source_file) 124 125 126 def stop_hooks_scripted(self, g_var_value, specifier = None): 127 self.script_setup() 128 129 result = lldb.SBCommandReturnObject() 130 131 command = "target stop-hook add -P stop_hook.stop_handler -k increment -v 5 " 132 if specifier: 133 command += specifier 134 135 self.interp.HandleCommand(command, result) 136 self.assertTrue(result.Succeeded, "Set the target stop hook") 137 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, 138 "Set a breakpoint here", self.main_source_file) 139 # At this point we've hit our stop hook so we should have run our expression, 140 # which increments g_var by the amount specified by the increment key's value. 141 while process.GetState() == lldb.eStateRunning: 142 continue 143 144 var = target.FindFirstGlobalVariable("g_var") 145 self.assertTrue(var.IsValid()) 146 self.assertEqual(var.GetValueAsUnsigned(), g_var_value, "Updated g_var") 147