1"""
2Test breakpoint conditions with 'breakpoint modify -c <expr> id'.
3"""
4
5import os, time
6import re
7import unittest2
8import lldb, lldbutil
9from lldbtest import *
10
11class BreakpointConditionsTestCase(TestBase):
12
13    mydir = os.path.join("functionalities", "breakpoint", "breakpoint_conditions")
14
15    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
16    @dsym_test
17    def test_breakpoint_condition_with_dsym_and_run_command(self):
18        """Exercise breakpoint condition with 'breakpoint modify -c <expr> id'."""
19        self.buildDsym()
20        self.breakpoint_conditions()
21
22    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
23    @dsym_test
24    def test_breakpoint_condition_inline_with_dsym_and_run_command(self):
25        """Exercise breakpoint condition inline with 'breakpoint set'."""
26        self.buildDsym()
27        self.breakpoint_conditions(inline=True)
28
29    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
30    @python_api_test
31    @dsym_test
32    def test_breakpoint_condition_with_dsym_and_python_api(self):
33        """Use Python APIs to set breakpoint conditions."""
34        self.buildDsym()
35        self.breakpoint_conditions_python()
36
37    @dwarf_test
38    def test_breakpoint_condition_with_dwarf_and_run_command(self):
39        """Exercise breakpoint condition with 'breakpoint modify -c <expr> id'."""
40        self.buildDwarf()
41        self.breakpoint_conditions()
42
43    @dwarf_test
44    def test_breakpoint_condition_inline_with_dwarf_and_run_command(self):
45        """Exercise breakpoint condition inline with 'breakpoint set'."""
46        self.buildDwarf()
47        self.breakpoint_conditions(inline=True)
48
49    @python_api_test
50    @dwarf_test
51    def test_breakpoint_condition_with_dwarf_and_python_api(self):
52        """Use Python APIs to set breakpoint conditions."""
53        self.buildDwarf()
54        self.breakpoint_conditions_python()
55
56    def setUp(self):
57        # Call super's setUp().
58        TestBase.setUp(self)
59        # Find the line number to of function 'c'.
60        self.line1 = line_number('main.c', '// Find the line number of function "c" here.')
61        self.line2 = line_number('main.c', "// Find the line number of c's parent call here.")
62
63    def breakpoint_conditions(self, inline=False):
64        """Exercise breakpoint condition with 'breakpoint modify -c <expr> id'."""
65        exe = os.path.join(os.getcwd(), "a.out")
66        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
67
68        if inline:
69            # Create a breakpoint by function name 'c' and set the condition.
70            lldbutil.run_break_set_by_symbol (self, "c", extra_options="-c 'val == 3'", num_expected_locations=1, sym_exact=True)
71        else:
72            # Create a breakpoint by function name 'c'.
73            lldbutil.run_break_set_by_symbol (self, "c", num_expected_locations=1, sym_exact=True)
74
75            # And set a condition on the breakpoint to stop on when 'val == 3'.
76            self.runCmd("breakpoint modify -c 'val == 3' 1")
77
78        # Now run the program.
79        self.runCmd("run", RUN_SUCCEEDED)
80
81        # The process should be stopped at this point.
82        self.expect("process status", PROCESS_STOPPED,
83            patterns = ['Process .* stopped'])
84
85        # 'frame variable --show-types val' should return 3 due to breakpoint condition.
86        self.expect("frame variable --show-types val", VARIABLES_DISPLAYED_CORRECTLY,
87            startstr = '(int) val = 3')
88
89        # Also check the hit count, which should be 3, by design.
90        self.expect("breakpoint list -f", BREAKPOINT_HIT_THRICE,
91            substrs = ["resolved = 1",
92                       "Condition: val == 3",
93                       "hit count = 3"])
94
95        # The frame #0 should correspond to main.c:36, the executable statement
96        # in function name 'c'.  And the parent frame should point to main.c:24.
97        self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT_CONDITION,
98            #substrs = ["stop reason = breakpoint"],
99            patterns = ["frame #0.*main.c:%d" % self.line1,
100                        "frame #1.*main.c:%d" % self.line2])
101
102        # Test that "breakpoint modify -c ''" clears the condition for the last
103        # created breakpoint, so that when the breakpoint hits, val == 1.
104        self.runCmd("process kill")
105        self.runCmd("breakpoint modify -c ''")
106        self.expect("breakpoint list -f", BREAKPOINT_STATE_CORRECT, matching=False,
107            substrs = ["Condition:"])
108
109        # Now run the program again.
110        self.runCmd("run", RUN_SUCCEEDED)
111
112        # The process should be stopped at this point.
113        self.expect("process status", PROCESS_STOPPED,
114            patterns = ['Process .* stopped'])
115
116        # 'frame variable --show-types val' should return 1 since it is the first breakpoint hit.
117        self.expect("frame variable --show-types val", VARIABLES_DISPLAYED_CORRECTLY,
118            startstr = '(int) val = 1')
119
120        self.runCmd("process kill")
121        self.runCmd("breakpoint disable")
122
123        self.runCmd("breakpoint set -p Loop")
124        self.runCmd("breakpoint modify -c ($eax&&i)")
125        self.runCmd("run")
126
127        self.expect("process status", PROCESS_STOPPED,
128            patterns = ['Process .* stopped'])
129
130        self.runCmd("continue")
131
132        self.expect("process status", PROCESS_EXITED,
133            patterns = ['Process .* exited'])
134
135    def breakpoint_conditions_python(self):
136        """Use Python APIs to set breakpoint conditions."""
137        exe = os.path.join(os.getcwd(), "a.out")
138
139        # Create a target by the debugger.
140        target = self.dbg.CreateTarget(exe)
141        self.assertTrue(target, VALID_TARGET)
142
143        # Now create a breakpoint on main.c by name 'c'.
144        breakpoint = target.BreakpointCreateByName('c', 'a.out')
145        #print "breakpoint:", breakpoint
146        self.assertTrue(breakpoint and
147                        breakpoint.GetNumLocations() == 1,
148                        VALID_BREAKPOINT)
149
150        # We didn't associate a thread index with the breakpoint, so it should be invalid.
151        self.assertTrue(breakpoint.GetThreadIndex() == lldb.UINT32_MAX,
152                        "The thread index should be invalid")
153        # The thread name should be invalid, too.
154        self.assertTrue(breakpoint.GetThreadName() is None,
155                        "The thread name should be invalid")
156
157        # Let's set the thread index for this breakpoint and verify that it is,
158        # indeed, being set correctly.
159        breakpoint.SetThreadIndex(1) # There's only one thread for the process.
160        self.assertTrue(breakpoint.GetThreadIndex() == 1,
161                        "The thread index has been set correctly")
162
163        # Get the breakpoint location from breakpoint after we verified that,
164        # indeed, it has one location.
165        location = breakpoint.GetLocationAtIndex(0)
166        self.assertTrue(location and
167                        location.IsEnabled(),
168                        VALID_BREAKPOINT_LOCATION)
169
170        # Set the condition on the breakpoint location.
171        location.SetCondition('val == 3')
172        self.expect(location.GetCondition(), exe=False,
173            startstr = 'val == 3')
174
175        # Now launch the process, and do not stop at entry point.
176        process = target.LaunchSimple(None, None, os.getcwd())
177        self.assertTrue(process, PROCESS_IS_VALID)
178
179        # Frame #0 should be on self.line1 and the break condition should hold.
180        from lldbutil import get_stopped_thread
181        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
182        self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition")
183        frame0 = thread.GetFrameAtIndex(0)
184        var = frame0.FindValue('val', lldb.eValueTypeVariableArgument)
185        self.assertTrue(frame0.GetLineEntry().GetLine() == self.line1 and
186                        var.GetValue() == '3')
187
188        # The hit count for the breakpoint should be 3.
189        self.assertTrue(breakpoint.GetHitCount() == 3)
190
191        process.Continue()
192
193
194if __name__ == '__main__':
195    import atexit
196    lldb.SBDebugger.Initialize()
197    atexit.register(lambda: lldb.SBDebugger.Terminate())
198    unittest2.main()
199