xref: /llvm-project/lldb/test/API/functionalities/conditional_break/TestConditionalBreak.py (revision e0a79eeca27b894bca6aa3f5dfdd8f1ac6644381)
199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtTest conditionally break on a function and inspect its variables.
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprechtimport lldb
699451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
799451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
899451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
999451b44SJordan Rupprecht
1099451b44SJordan Rupprecht# rdar://problem/8532131
1199451b44SJordan Rupprecht# lldb not able to digest the clang-generated debug info correctly with respect to function name
1299451b44SJordan Rupprecht#
13*e0a79eecSMichael Buch# This class currently fails for clang.
1499451b44SJordan Rupprecht
1599451b44SJordan Rupprecht
1699451b44SJordan Rupprechtclass ConditionalBreakTestCase(TestBase):
172238dcc3SJonas Devlieghere    @add_test_categories(["pyapi"])
1899451b44SJordan Rupprecht    def test_with_python(self):
1999451b44SJordan Rupprecht        """Exercise some thread and frame APIs to break if c() is called by a()."""
2099451b44SJordan Rupprecht        self.build()
2199451b44SJordan Rupprecht        self.do_conditional_break()
2299451b44SJordan Rupprecht
2399451b44SJordan Rupprecht    def test_with_command(self):
2499451b44SJordan Rupprecht        """Simulate a user using lldb commands to break on c() if called from a()."""
2599451b44SJordan Rupprecht        self.build()
2699451b44SJordan Rupprecht        self.simulate_conditional_break_by_user()
2799451b44SJordan Rupprecht
2899451b44SJordan Rupprecht    def do_conditional_break(self):
2999451b44SJordan Rupprecht        """Exercise some thread and frame APIs to break if c() is called by a()."""
3099451b44SJordan Rupprecht        exe = self.getBuildArtifact("a.out")
3199451b44SJordan Rupprecht
3299451b44SJordan Rupprecht        target = self.dbg.CreateTarget(exe)
3399451b44SJordan Rupprecht        self.assertTrue(target, VALID_TARGET)
3499451b44SJordan Rupprecht
3599451b44SJordan Rupprecht        breakpoint = target.BreakpointCreateByName("c", exe)
3699451b44SJordan Rupprecht        self.assertTrue(breakpoint, VALID_BREAKPOINT)
3799451b44SJordan Rupprecht
3899451b44SJordan Rupprecht        # Now launch the process, and do not stop at entry point.
392238dcc3SJonas Devlieghere        process = target.LaunchSimple(None, None, self.get_process_working_directory())
4099451b44SJordan Rupprecht
4199451b44SJordan Rupprecht        self.assertTrue(process, PROCESS_IS_VALID)
4299451b44SJordan Rupprecht
4399451b44SJordan Rupprecht        # The stop reason of the thread should be breakpoint.
442238dcc3SJonas Devlieghere        self.assertState(
452238dcc3SJonas Devlieghere            process.GetState(), lldb.eStateStopped, STOPPED_DUE_TO_BREAKPOINT
462238dcc3SJonas Devlieghere        )
4799451b44SJordan Rupprecht
4899451b44SJordan Rupprecht        # Find the line number where a's parent frame function is c.
4999451b44SJordan Rupprecht        line = line_number(
502238dcc3SJonas Devlieghere            "main.c", "// Find the line number where c's parent frame is a here."
512238dcc3SJonas Devlieghere        )
5299451b44SJordan Rupprecht
5399451b44SJordan Rupprecht        # Suppose we are only interested in the call scenario where c()'s
5499451b44SJordan Rupprecht        # immediate caller is a() and we want to find out the value passed from
5599451b44SJordan Rupprecht        # a().
5699451b44SJordan Rupprecht        #
5799451b44SJordan Rupprecht        # The 10 in range(10) is just an arbitrary number, which means we would
5899451b44SJordan Rupprecht        # like to try for at most 10 times.
5999451b44SJordan Rupprecht        for j in range(10):
6099451b44SJordan Rupprecht            if self.TraceOn():
6199451b44SJordan Rupprecht                print("j is: ", j)
622238dcc3SJonas Devlieghere            thread = lldbutil.get_one_thread_stopped_at_breakpoint(process, breakpoint)
6399451b44SJordan Rupprecht            self.assertIsNotNone(
642238dcc3SJonas Devlieghere                thread, "Expected one thread to be stopped at the breakpoint"
652238dcc3SJonas Devlieghere            )
6699451b44SJordan Rupprecht
6799451b44SJordan Rupprecht            if thread.GetNumFrames() >= 2:
6899451b44SJordan Rupprecht                frame0 = thread.GetFrameAtIndex(0)
6999451b44SJordan Rupprecht                name0 = frame0.GetFunction().GetName()
7099451b44SJordan Rupprecht                frame1 = thread.GetFrameAtIndex(1)
7199451b44SJordan Rupprecht                name1 = frame1.GetFunction().GetName()
7299451b44SJordan Rupprecht                # lldbutil.print_stacktrace(thread)
73619e2e09SDave Lee                self.assertEqual(name0, "c", "Break on function c()")
742238dcc3SJonas Devlieghere                if name1 == "a":
7599451b44SJordan Rupprecht                    # By design, we know that a() calls c() only from main.c:27.
7699451b44SJordan Rupprecht                    # In reality, similar logic can be used to find out the call
7799451b44SJordan Rupprecht                    # site.
782238dcc3SJonas Devlieghere                    self.assertEqual(
792238dcc3SJonas Devlieghere                        frame1.GetLineEntry().GetLine(),
802238dcc3SJonas Devlieghere                        line,
812238dcc3SJonas Devlieghere                        "Immediate caller a() at main.c:%d" % line,
822238dcc3SJonas Devlieghere                    )
8399451b44SJordan Rupprecht
8499451b44SJordan Rupprecht                    # And the local variable 'val' should have a value of (int)
8599451b44SJordan Rupprecht                    # 3.
8699451b44SJordan Rupprecht                    val = frame1.FindVariable("val")
8799451b44SJordan Rupprecht                    self.assertEqual("int", val.GetTypeName())
8899451b44SJordan Rupprecht                    self.assertEqual("3", val.GetValue())
8999451b44SJordan Rupprecht                    break
9099451b44SJordan Rupprecht
9199451b44SJordan Rupprecht            process.Continue()
9299451b44SJordan Rupprecht
9399451b44SJordan Rupprecht    def simulate_conditional_break_by_user(self):
9499451b44SJordan Rupprecht        """Simulate a user using lldb commands to break on c() if called from a()."""
9599451b44SJordan Rupprecht
9699451b44SJordan Rupprecht        # Sourcing .lldb in the current working directory, which sets the main
9799451b44SJordan Rupprecht        # executable, sets the breakpoint on c(), and adds the callback for the
9899451b44SJordan Rupprecht        # breakpoint such that lldb only stops when the caller of c() is a().
9999451b44SJordan Rupprecht        # the "my" package that defines the date() function.
10099451b44SJordan Rupprecht        if self.TraceOn():
10199451b44SJordan Rupprecht            print("About to source .lldb")
10299451b44SJordan Rupprecht
10399451b44SJordan Rupprecht        if not self.TraceOn():
10499451b44SJordan Rupprecht            self.HideStdout()
10599451b44SJordan Rupprecht
10699451b44SJordan Rupprecht        # Separate out the "file " + self.getBuildArtifact("a.out") command from .lldb file, for the sake of
10799451b44SJordan Rupprecht        # remote testsuite.
10899451b44SJordan Rupprecht        self.runCmd("file " + self.getBuildArtifact("a.out"))
10999451b44SJordan Rupprecht        self.runCmd("command source .lldb")
11099451b44SJordan Rupprecht
11199451b44SJordan Rupprecht        self.runCmd("break list")
11299451b44SJordan Rupprecht
11399451b44SJordan Rupprecht        if self.TraceOn():
11499451b44SJordan Rupprecht            print("About to run.")
11599451b44SJordan Rupprecht        self.runCmd("run", RUN_SUCCEEDED)
11699451b44SJordan Rupprecht
11799451b44SJordan Rupprecht        self.runCmd("break list")
11899451b44SJordan Rupprecht
11999451b44SJordan Rupprecht        if self.TraceOn():
12099451b44SJordan Rupprecht            print("Done running")
12199451b44SJordan Rupprecht
12299451b44SJordan Rupprecht        # The stop reason of the thread should be breakpoint.
1232238dcc3SJonas Devlieghere        self.expect(
1242238dcc3SJonas Devlieghere            "thread list",
1252238dcc3SJonas Devlieghere            STOPPED_DUE_TO_BREAKPOINT,
1262238dcc3SJonas Devlieghere            substrs=["stopped", "stop reason = breakpoint"],
1272238dcc3SJonas Devlieghere        )
12899451b44SJordan Rupprecht
12999451b44SJordan Rupprecht        # The frame info for frame #0 points to a.out`c and its immediate caller
13099451b44SJordan Rupprecht        # (frame #1) points to a.out`a.
13199451b44SJordan Rupprecht
1322238dcc3SJonas Devlieghere        self.expect("frame info", "We should stop at c()", substrs=["a.out`c"])
13399451b44SJordan Rupprecht
13499451b44SJordan Rupprecht        # Select our parent frame as the current frame.
13599451b44SJordan Rupprecht        self.runCmd("frame select 1")
1362238dcc3SJonas Devlieghere        self.expect(
1372238dcc3SJonas Devlieghere            "frame info", "The immediate caller should be a()", substrs=["a.out`a"]
1382238dcc3SJonas Devlieghere        )
139