xref: /llvm-project/lldb/test/API/commands/target/stop-hooks/TestStopHookScripted.py (revision f732157a9d067e4d300905c831a964222e0eadee)
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