xref: /llvm-project/lldb/test/API/commands/target/stop-hooks/TestStopHooks.py (revision 2238dcc39358353cac21df75c3c3286ab20b8f53)
1"""
2Test stop hook functionality
3"""
4
5
6import lldb
7import lldbsuite.test.lldbutil as lldbutil
8from lldbsuite.test.lldbtest import *
9
10
11class TestStopHooks(TestBase):
12    # If your test case doesn't stress debug info, then
13    # set this to true.  That way it won't be run once for
14    # each debug info format.
15    NO_DEBUG_INFO_TESTCASE = True
16
17    def setUp(self):
18        TestBase.setUp(self)
19        self.build()
20        self.main_source_file = lldb.SBFileSpec("main.c")
21        full_path = os.path.join(self.getSourceDir(), "main.c")
22        self.main_start_line = line_number(full_path, "main()")
23
24    def test_stop_hooks_step_out(self):
25        """Test that stop hooks fire on step-out."""
26        self.step_out_test()
27
28    def test_stop_hooks_after_expr(self):
29        """Test that a stop hook fires when hitting a breakpoint
30        that runs an expression"""
31        self.after_expr_test()
32
33    def step_out_test(self):
34        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
35            self, "Set a breakpoint here", self.main_source_file
36        )
37
38        interp = self.dbg.GetCommandInterpreter()
39        result = lldb.SBCommandReturnObject()
40        interp.HandleCommand("target stop-hook add -o 'expr g_var++'", result)
41        self.assertTrue(result.Succeeded(), "Set the target stop hook")
42        thread.StepOut()
43        var = target.FindFirstGlobalVariable("g_var")
44        self.assertTrue(var.IsValid())
45        self.assertEqual(var.GetValueAsUnsigned(), 1, "Updated g_var")
46
47    def after_expr_test(self):
48        interp = self.dbg.GetCommandInterpreter()
49        result = lldb.SBCommandReturnObject()
50        interp.HandleCommand("target stop-hook add -o 'expr g_var++'", result)
51        self.assertTrue(result.Succeeded(), "Set the target stop hook")
52
53        (target, process, thread, first_bkpt) = lldbutil.run_to_source_breakpoint(
54            self, "Set a breakpoint here", self.main_source_file
55        )
56
57        var = target.FindFirstGlobalVariable("g_var")
58        self.assertTrue(var.IsValid())
59        self.assertEqual(var.GetValueAsUnsigned(), 1, "Updated g_var")
60
61        bkpt = target.BreakpointCreateBySourceRegex(
62            "Continue to here", self.main_source_file
63        )
64        self.assertNotEqual(bkpt.GetNumLocations(), 0, "Set the second breakpoint")
65        commands = lldb.SBStringList()
66        commands.AppendString("expr increment_gvar()")
67        bkpt.SetCommandLineCommands(commands)
68
69        threads = lldbutil.continue_to_breakpoint(process, bkpt)
70        self.assertEqual(len(threads), 1, "Hit my breakpoint")
71
72        self.assertTrue(var.IsValid())
73        self.assertEqual(var.GetValueAsUnsigned(), 3, "Updated g_var")
74
75        # Make sure running an expression does NOT run the stop hook.
76        # Our expression will increment it by one, but the stop shouldn't
77        # have gotten it to 5.
78        threads[0].frames[0].EvaluateExpression("increment_gvar()")
79        self.assertTrue(var.IsValid())
80        self.assertEqual(var.GetValueAsUnsigned(), 4, "Updated g_var")
81
82        # Make sure a rerun doesn't upset the state we've set up:
83        process.Kill()
84        lldbutil.run_to_breakpoint_do_run(self, target, first_bkpt)
85        var = target.FindFirstGlobalVariable("g_var")
86        self.assertTrue(var.IsValid())
87        self.assertEqual(var.GetValueAsUnsigned(), 1, "Updated g_var")
88