1"""
2Test lldb breakpoint command add/list/delete.
3"""
4
5import os, time
6import unittest2
7import lldb
8from lldbtest import *
9import lldbutil
10
11class BreakpointCommandTestCase(TestBase):
12
13    mydir = os.path.join("functionalities", "breakpoint", "breakpoint_command")
14
15    @classmethod
16    def classCleanup(cls):
17        """Cleanup the test byproduct of breakpoint_command_sequence(self)."""
18        cls.RemoveTempFile("output.txt")
19        cls.RemoveTempFile("output2.txt")
20
21    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
22    @dsym_test
23    def test_with_dsym(self):
24        """Test a sequence of breakpoint command add, list, and delete."""
25        self.buildDsym()
26        self.breakpoint_command_sequence()
27        self.breakpoint_command_script_parameters ()
28
29    @dwarf_test
30    def test_with_dwarf(self):
31        """Test a sequence of breakpoint command add, list, and delete."""
32        self.buildDwarf()
33        self.breakpoint_command_sequence()
34        self.breakpoint_command_script_parameters ()
35
36    def setUp(self):
37        # Call super's setUp().
38        TestBase.setUp(self)
39        # Find the line number to break inside main().
40        self.line = line_number('main.c', '// Set break point at this line.')
41        # disable "There is a running process, kill it and restart?" prompt
42        self.runCmd("settings set auto-confirm true")
43        self.addTearDownHook(lambda: self.runCmd("settings clear auto-confirm"))
44
45    def breakpoint_command_sequence(self):
46        """Test a sequence of breakpoint command add, list, and delete."""
47        exe = os.path.join(os.getcwd(), "a.out")
48        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
49
50        # Add three breakpoints on the same line.  The first time we don't specify the file,
51        # since the default file is the one containing main:
52        lldbutil.run_break_set_by_file_and_line (self, None, self.line, num_expected_locations=1, loc_exact=True)
53        lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
54        lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
55
56        # Now add callbacks for the breakpoints just created.
57        self.runCmd("breakpoint command add -s command -o 'frame variable --show-types --scope' 1")
58        self.runCmd("breakpoint command add -s python -o 'here = open(\"output.txt\", \"w\"); print >> here, \"lldb\"; here.close()' 2")
59        self.runCmd("breakpoint command add --python-function bktptcmd.function 3")
60
61        # Check that the breakpoint commands are correctly set.
62
63        # The breakpoint list now only contains breakpoint 1.
64        self.expect("breakpoint list", "Breakpoints 1 & 2 created",
65            substrs = ["2: file = 'main.c', line = %d, locations = 1" % self.line],
66            patterns = ["1: file = '.*main.c', line = %d, locations = 1" % self.line] )
67
68        self.expect("breakpoint list -f", "Breakpoints 1 & 2 created",
69            substrs = ["2: file = 'main.c', line = %d, locations = 1" % self.line],
70            patterns = ["1: file = '.*main.c', line = %d, locations = 1" % self.line,
71                        "1.1: .+at main.c:%d, .+unresolved, hit count = 0" % self.line,
72                        "2.1: .+at main.c:%d, .+unresolved, hit count = 0" % self.line])
73
74        self.expect("breakpoint command list 1", "Breakpoint 1 command ok",
75            substrs = ["Breakpoint commands:",
76                          "frame variable --show-types --scope"])
77        self.expect("breakpoint command list 2", "Breakpoint 2 command ok",
78            substrs = ["Breakpoint commands:",
79                          "here = open",
80                          "print >> here",
81                          "here.close()"])
82        self.expect("breakpoint command list 3", "Breakpoint 3 command ok",
83            substrs = ["Breakpoint commands:",
84                          "bktptcmd.function(frame, bp_loc, internal_dict)"])
85
86        self.runCmd("command script import --allow-reload ./bktptcmd.py")
87
88        # Next lets try some other breakpoint kinds.  First break with a regular expression
89        # and then specify only one file.  The first time we should get two locations,
90        # the second time only one:
91
92        lldbutil.run_break_set_by_regexp (self, r"._MyFunction", num_expected_locations=2)
93
94        lldbutil.run_break_set_by_regexp (self, r"._MyFunction", extra_options="-f a.c", num_expected_locations=1)
95
96        lldbutil.run_break_set_by_regexp (self, r"._MyFunction", extra_options="-f a.c -f b.c", num_expected_locations=2)
97
98        # Now try a source regex breakpoint:
99        lldbutil.run_break_set_by_source_regexp (self, r"is about to return [12]0", extra_options="-f a.c -f b.c", num_expected_locations=2)
100
101        lldbutil.run_break_set_by_source_regexp (self, r"is about to return [12]0", extra_options="-f a.c", num_expected_locations=1)
102
103        # Run the program.  Remove 'output.txt' if it exists.
104        self.RemoveTempFile("output.txt")
105        self.RemoveTempFile("output2.txt")
106        self.runCmd("run", RUN_SUCCEEDED)
107
108        # Check that the file 'output.txt' exists and contains the string "lldb".
109
110        # The 'output.txt' file should now exist.
111        self.assertTrue(os.path.isfile("output.txt"),
112                        "'output.txt' exists due to breakpoint command for breakpoint 2.")
113        self.assertTrue(os.path.isfile("output2.txt"),
114                        "'output2.txt' exists due to breakpoint command for breakpoint 3.")
115
116        # Read the output file produced by running the program.
117        with open('output.txt', 'r') as f:
118            output = f.read()
119
120        self.expect(output, "File 'output.txt' and the content matches", exe=False,
121            startstr = "lldb")
122
123        with open('output2.txt', 'r') as f:
124            output = f.read()
125
126        self.expect(output, "File 'output2.txt' and the content matches", exe=False,
127            startstr = "lldb")
128
129
130        # Finish the program.
131        self.runCmd("process continue")
132
133        # Remove the breakpoint command associated with breakpoint 1.
134        self.runCmd("breakpoint command delete 1")
135
136        # Remove breakpoint 2.
137        self.runCmd("breakpoint delete 2")
138
139        self.expect("breakpoint command list 1",
140            startstr = "Breakpoint 1 does not have an associated command.")
141        self.expect("breakpoint command list 2", error=True,
142            startstr = "error: '2' is not a currently valid breakpoint id.")
143
144        # The breakpoint list now only contains breakpoint 1.
145        self.expect("breakpoint list -f", "Breakpoint 1 exists",
146            patterns = ["1: file = '.*main.c', line = %d, locations = 1, resolved = 1" %
147                        self.line,
148                       "hit count = 1"])
149
150        # Not breakpoint 2.
151        self.expect("breakpoint list -f", "No more breakpoint 2", matching=False,
152            substrs = ["2: file = 'main.c', line = %d, locations = 1, resolved = 1" %
153                        self.line])
154
155        # Run the program again, with breakpoint 1 remaining.
156        self.runCmd("run", RUN_SUCCEEDED)
157
158        # We should be stopped again due to breakpoint 1.
159
160        # The stop reason of the thread should be breakpoint.
161        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
162            substrs = ['stopped',
163                       'stop reason = breakpoint'])
164
165        # The breakpoint should have a hit count of 2.
166        self.expect("breakpoint list -f", BREAKPOINT_HIT_TWICE,
167            substrs = ['resolved, hit count = 2'])
168
169    def breakpoint_command_script_parameters (self):
170        """Test that the frame and breakpoint location are being properly passed to the script breakpoint command function."""
171        exe = os.path.join(os.getcwd(), "a.out")
172        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
173
174        # Add a breakpoint.
175        lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
176
177        # Now add callbacks for the breakpoints just created.
178        self.runCmd("breakpoint command add -s python -o 'here = open(\"output-2.txt\", \"w\"); print >> here, frame; print >> here, bp_loc; here.close()' 1")
179
180        # Remove 'output-2.txt' if it already exists.
181
182        if (os.path.exists('output-2.txt')):
183            os.remove ('output-2.txt')
184
185        # Run program, hit breakpoint, and hopefully write out new version of 'output-2.txt'
186        self.runCmd ("run", RUN_SUCCEEDED)
187
188        # Check that the file 'output.txt' exists and contains the string "lldb".
189
190        # The 'output-2.txt' file should now exist.
191        self.assertTrue(os.path.isfile("output-2.txt"),
192                        "'output-2.txt' exists due to breakpoint command for breakpoint 1.")
193
194        # Read the output file produced by running the program.
195        with open('output-2.txt', 'r') as f:
196            output = f.read()
197
198        self.expect (output, "File 'output-2.txt' and the content matches", exe=False,
199                     startstr = "frame #0:",
200                     patterns = ["1.* where = .*main .* resolved, hit count = 1" ])
201
202        # Now remove 'output-2.txt'
203        os.remove ('output-2.txt')
204
205if __name__ == '__main__':
206    import atexit
207    lldb.SBDebugger.Initialize()
208    atexit.register(lambda: lldb.SBDebugger.Terminate())
209    unittest2.main()
210