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