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