2 Test conditionally break on a function and inspect its variables.
6 from lldbsuite
.test
.decorators
import *
7 from lldbsuite
.test
.lldbtest
import *
8 from lldbsuite
.test
import lldbutil
10 # rdar://problem/8532131
11 # lldb not able to digest the clang-generated debug info correctly with respect to function name
13 # This class currently fails for clang as well as llvm-gcc.
16 class ConditionalBreakTestCase(TestBase
):
17 @add_test_categories(["pyapi"])
18 def test_with_python(self
):
19 """Exercise some thread and frame APIs to break if c() is called by a()."""
21 self
.do_conditional_break()
23 def test_with_command(self
):
24 """Simulate a user using lldb commands to break on c() if called from a()."""
26 self
.simulate_conditional_break_by_user()
28 def do_conditional_break(self
):
29 """Exercise some thread and frame APIs to break if c() is called by a()."""
30 exe
= self
.getBuildArtifact("a.out")
32 target
= self
.dbg
.CreateTarget(exe
)
33 self
.assertTrue(target
, VALID_TARGET
)
35 breakpoint
= target
.BreakpointCreateByName("c", exe
)
36 self
.assertTrue(breakpoint
, VALID_BREAKPOINT
)
38 # Now launch the process, and do not stop at entry point.
39 process
= target
.LaunchSimple(None, None, self
.get_process_working_directory())
41 self
.assertTrue(process
, PROCESS_IS_VALID
)
43 # The stop reason of the thread should be breakpoint.
45 process
.GetState(), lldb
.eStateStopped
, STOPPED_DUE_TO_BREAKPOINT
48 # Find the line number where a's parent frame function is c.
50 "main.c", "// Find the line number where c's parent frame is a here."
53 # Suppose we are only interested in the call scenario where c()'s
54 # immediate caller is a() and we want to find out the value passed from
57 # The 10 in range(10) is just an arbitrary number, which means we would
58 # like to try for at most 10 times.
62 thread
= lldbutil
.get_one_thread_stopped_at_breakpoint(process
, breakpoint
)
64 thread
, "Expected one thread to be stopped at the breakpoint"
67 if thread
.GetNumFrames() >= 2:
68 frame0
= thread
.GetFrameAtIndex(0)
69 name0
= frame0
.GetFunction().GetName()
70 frame1
= thread
.GetFrameAtIndex(1)
71 name1
= frame1
.GetFunction().GetName()
72 # lldbutil.print_stacktrace(thread)
73 self
.assertEqual(name0
, "c", "Break on function c()")
75 # By design, we know that a() calls c() only from main.c:27.
76 # In reality, similar logic can be used to find out the call
79 frame1
.GetLineEntry().GetLine(),
81 "Immediate caller a() at main.c:%d" % line
,
84 # And the local variable 'val' should have a value of (int)
86 val
= frame1
.FindVariable("val")
87 self
.assertEqual("int", val
.GetTypeName())
88 self
.assertEqual("3", val
.GetValue())
93 def simulate_conditional_break_by_user(self
):
94 """Simulate a user using lldb commands to break on c() if called from a()."""
96 # Sourcing .lldb in the current working directory, which sets the main
97 # executable, sets the breakpoint on c(), and adds the callback for the
98 # breakpoint such that lldb only stops when the caller of c() is a().
99 # the "my" package that defines the date() function.
101 print("About to source .lldb")
103 if not self
.TraceOn():
106 # Separate out the "file " + self.getBuildArtifact("a.out") command from .lldb file, for the sake of
108 self
.runCmd("file " + self
.getBuildArtifact("a.out"))
109 self
.runCmd("command source .lldb")
111 self
.runCmd("break list")
114 print("About to run.")
115 self
.runCmd("run", RUN_SUCCEEDED
)
117 self
.runCmd("break list")
120 print("Done running")
122 # The stop reason of the thread should be breakpoint.
125 STOPPED_DUE_TO_BREAKPOINT
,
126 substrs
=["stopped", "stop reason = breakpoint"],
129 # The frame info for frame #0 points to a.out`c and its immediate caller
130 # (frame #1) points to a.out`a.
132 self
.expect("frame info", "We should stop at c()", substrs
=["a.out`c"])
134 # Select our parent frame as the current frame.
135 self
.runCmd("frame select 1")
137 "frame info", "The immediate caller should be a()", substrs
=["a.out`a"]