xref: /llvm-project/lldb/test/API/commands/expression/unwind_expression/TestUnwindExpression.py (revision 8ac0aaaebbbb38d3dc863c5c5b331c8ec3238e27)
1"""
2Test stopping at a breakpoint in an expression, and unwinding from there.
3"""
4
5import lldb
6from lldbsuite.test.decorators import *
7from lldbsuite.test.lldbtest import *
8from lldbsuite.test import lldbutil
9
10
11class UnwindFromExpressionTest(TestBase):
12    main_spec = lldb.SBFileSpec("main.cpp", False)
13
14    def build_and_run_to_bkpt(self):
15        self.build()
16
17        (target, process, self.thread, bkpt) = lldbutil.run_to_source_breakpoint(
18            self, "// Set a breakpoint here to get started", self.main_spec
19        )
20
21        # Next set a breakpoint in this function, set up Expression options to stop on
22        # breakpoint hits, and call the function.
23        self.fun_bkpt = self.target().BreakpointCreateBySourceRegex(
24            "// Stop inside the function here.", self.main_spec
25        )
26        self.assertTrue(self.fun_bkpt, VALID_BREAKPOINT)
27
28    @no_debug_info_test
29    @expectedFailureAll(bugnumber="llvm.org/pr33164")
30    def test_conditional_bktp(self):
31        """
32        Test conditional breakpoint handling in the IgnoreBreakpoints = False case
33        """
34        self.build_and_run_to_bkpt()
35
36        self.fun_bkpt.SetCondition("0")  # Should not get hit
37        options = lldb.SBExpressionOptions()
38        options.SetIgnoreBreakpoints(False)
39        options.SetUnwindOnError(False)
40
41        main_frame = self.thread.GetFrameAtIndex(0)
42        val = main_frame.EvaluateExpression("second_function(47)", options)
43        self.assertSuccess(val.GetError(), "We did complete the execution.")
44        self.assertEqual(47, val.GetValueAsSigned())
45
46    @add_test_categories(["pyapi"])
47    @expectedFlakeyNetBSD
48    def test_unwind_expression(self):
49        """Test unwinding from an expression."""
50        self.build_and_run_to_bkpt()
51
52        # Run test with varying one thread timeouts to also test the halting
53        # logic in the IgnoreBreakpoints = False case
54        self.do_unwind_test(self.thread, self.fun_bkpt, 1000)
55        self.do_unwind_test(self.thread, self.fun_bkpt, 100000)
56
57    def do_unwind_test(self, thread, bkpt, timeout):
58        #
59        # Use Python API to evaluate expressions while stopped in a stack frame.
60        #
61        main_frame = thread.GetFrameAtIndex(0)
62
63        options = lldb.SBExpressionOptions()
64        options.SetIgnoreBreakpoints(False)
65        options.SetUnwindOnError(False)
66        options.SetOneThreadTimeoutInMicroSeconds(timeout)
67
68        val = main_frame.EvaluateExpression("a_function_to_call()", options)
69
70        self.assertTrue(val.GetError().Fail(), "We did not complete the execution.")
71        error_str = val.GetError().GetCString()
72        self.assertIn(
73            "Expression execution hit a breakpoint: breakpoint",
74            error_str,
75            "And the reason was right.",
76        )
77
78        thread = lldbutil.get_one_thread_stopped_at_breakpoint(self.process(), bkpt)
79        self.assertTrue(thread.IsValid(), "We are indeed stopped at our breakpoint")
80
81        # Now unwind the expression, and make sure we got back to where we
82        # started.
83        self.assertSuccess(
84            thread.UnwindInnermostExpression(), "We succeeded in unwinding"
85        )
86
87        cur_frame = thread.GetFrameAtIndex(0)
88        self.assertTrue(cur_frame.IsEqual(main_frame), "We got back to the main frame.")
89