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