xref: /llvm-project/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py (revision 9f0b5f9a39ea6e70c98c69a720d7e4f5d3800bf6)
1"""
2Test lldb breakpoint command add/list/delete.
3"""
4
5
6
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11import side_effect
12
13
14class BreakpointCommandTestCase(TestBase):
15
16    NO_DEBUG_INFO_TESTCASE = True
17    mydir = TestBase.compute_mydir(__file__)
18
19    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
20    def test_breakpoint_command_sequence(self):
21        """Test a sequence of breakpoint command add, list, and delete."""
22        self.build()
23        self.breakpoint_command_sequence()
24
25    @skipIf(oslist=["windows"], bugnumber="llvm.org/pr44431")
26    def test_script_parameters(self):
27        """Test a sequence of breakpoint command add, list, and delete."""
28        self.build()
29        self.breakpoint_command_script_parameters()
30
31    def test_commands_on_creation(self):
32        self.build()
33        self.breakpoint_commands_on_creation()
34
35    def setUp(self):
36        # Call super's setUp().
37        TestBase.setUp(self)
38        # Find the line number to break inside main().
39        self.line = line_number('main.c', '// Set break point at this line.')
40        # disable "There is a running process, kill it and restart?" prompt
41        self.runCmd("settings set auto-confirm true")
42        self.addTearDownHook(
43            lambda: self.runCmd("settings clear auto-confirm"))
44
45    def test_delete_all_breakpoints(self):
46        """Test that deleting all breakpoints works."""
47        self.build()
48        exe = self.getBuildArtifact("a.out")
49        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
50
51        lldbutil.run_break_set_by_symbol(self, "main")
52        lldbutil.run_break_set_by_file_and_line(
53            self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
54
55        self.runCmd("run", RUN_SUCCEEDED)
56
57        self.runCmd("breakpoint delete")
58        self.runCmd("process continue")
59        self.expect("process status", PROCESS_STOPPED,
60                    patterns=['Process .* exited with status = 0'])
61
62
63    def breakpoint_command_sequence(self):
64        """Test a sequence of breakpoint command add, list, and delete."""
65        exe = self.getBuildArtifact("a.out")
66        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
67
68        # Add three breakpoints on the same line.  The first time we don't specify the file,
69        # since the default file is the one containing main:
70        lldbutil.run_break_set_by_file_and_line(
71            self, None, self.line, num_expected_locations=1, loc_exact=True)
72        lldbutil.run_break_set_by_file_and_line(
73            self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
74        lldbutil.run_break_set_by_file_and_line(
75            self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
76        # Breakpoint 4 - set at the same location as breakpoint 1 to test
77        # setting breakpoint commands on two breakpoints at a time
78        lldbutil.run_break_set_by_file_and_line(
79            self, None, self.line, num_expected_locations=1, loc_exact=True)
80        # Make sure relative path source breakpoints work as expected. We test
81        # with partial paths with and without "./" prefixes.
82        lldbutil.run_break_set_by_file_and_line(
83            self, "./main.c", self.line,
84            num_expected_locations=1, loc_exact=True)
85        lldbutil.run_break_set_by_file_and_line(
86            self, "breakpoint_command/main.c", self.line,
87            num_expected_locations=1, loc_exact=True)
88        lldbutil.run_break_set_by_file_and_line(
89            self, "./breakpoint_command/main.c", self.line,
90            num_expected_locations=1, loc_exact=True)
91        lldbutil.run_break_set_by_file_and_line(
92            self, "breakpoint/breakpoint_command/main.c", self.line,
93            num_expected_locations=1, loc_exact=True)
94        lldbutil.run_break_set_by_file_and_line(
95            self, "./breakpoint/breakpoint_command/main.c", self.line,
96            num_expected_locations=1, loc_exact=True)
97        # Test relative breakpoints with incorrect paths and make sure we get
98        # no breakpoint locations
99        lldbutil.run_break_set_by_file_and_line(
100            self, "invalid/main.c", self.line,
101            num_expected_locations=0, loc_exact=True)
102        lldbutil.run_break_set_by_file_and_line(
103            self, "./invalid/main.c", self.line,
104            num_expected_locations=0, loc_exact=True)
105        # Now add callbacks for the breakpoints just created.
106        self.runCmd(
107            "breakpoint command add -s command -o 'frame variable --show-types --scope' 1 4")
108        self.runCmd(
109            "breakpoint command add -s python -o 'import side_effect; side_effect.one_liner = \"one liner was here\"' 2")
110
111        import side_effect
112        self.runCmd("command script import --allow-reload ./bktptcmd.py")
113
114        self.runCmd(
115            "breakpoint command add --python-function bktptcmd.function 3")
116
117        # Check that the breakpoint commands are correctly set.
118
119        # The breakpoint list now only contains breakpoint 1.
120        self.expect(
121            "breakpoint list", "Breakpoints 1 & 2 created", substrs=[
122                "2: file = 'main.c', line = %d, exact_match = 0, locations = 1" %
123                self.line], patterns=[
124                "1: file = '.*main.c', line = %d, exact_match = 0, locations = 1" %
125                self.line])
126
127        self.expect(
128            "breakpoint list -f",
129            "Breakpoints 1 & 2 created",
130            substrs=[
131                "2: file = 'main.c', line = %d, exact_match = 0, locations = 1" %
132                self.line],
133            patterns=[
134                "1: file = '.*main.c', line = %d, exact_match = 0, locations = 1" %
135                self.line,
136                "1.1: .+at main.c:%d:?[0-9]*, .+unresolved, hit count = 0" %
137                self.line,
138                "2.1: .+at main.c:%d:?[0-9]*, .+unresolved, hit count = 0" %
139                self.line])
140
141        self.expect("breakpoint command list 1", "Breakpoint 1 command ok",
142                    substrs=["Breakpoint commands:",
143                             "frame variable --show-types --scope"])
144        self.expect("breakpoint command list 2", "Breakpoint 2 command ok",
145                    substrs=["Breakpoint commands (Python):",
146                             "import side_effect",
147                             "side_effect.one_liner"])
148        self.expect("breakpoint command list 3", "Breakpoint 3 command ok",
149                    substrs=["Breakpoint commands (Python):",
150                             "bktptcmd.function(frame, bp_loc, internal_dict)"])
151
152        self.expect("breakpoint command list 4", "Breakpoint 4 command ok",
153                    substrs=["Breakpoint commands:",
154                             "frame variable --show-types --scope"])
155
156        self.runCmd("breakpoint delete 4")
157
158        # Next lets try some other breakpoint kinds.  First break with a regular expression
159        # and then specify only one file.  The first time we should get two locations,
160        # the second time only one:
161
162        lldbutil.run_break_set_by_regexp(
163            self, r"._MyFunction", num_expected_locations=2)
164
165        lldbutil.run_break_set_by_regexp(
166            self,
167            r"._MyFunction",
168            extra_options="-f a.c",
169            num_expected_locations=1)
170
171        lldbutil.run_break_set_by_regexp(
172            self,
173            r"._MyFunction",
174            extra_options="-f a.c -f b.c",
175            num_expected_locations=2)
176
177        # Now try a source regex breakpoint:
178        lldbutil.run_break_set_by_source_regexp(
179            self,
180            r"is about to return [12]0",
181            extra_options="-f a.c -f b.c",
182            num_expected_locations=2)
183
184        lldbutil.run_break_set_by_source_regexp(
185            self,
186            r"is about to return [12]0",
187            extra_options="-f a.c",
188            num_expected_locations=1)
189
190        # Reset our canary variables and run the program.
191        side_effect.one_liner = None
192        side_effect.bktptcmd = None
193        self.runCmd("run", RUN_SUCCEEDED)
194
195        # Check the value of canary variables.
196        self.assertEquals("one liner was here", side_effect.one_liner)
197        self.assertEquals("function was here", side_effect.bktptcmd)
198
199        # Finish the program.
200        self.runCmd("process continue")
201
202        # Remove the breakpoint command associated with breakpoint 1.
203        self.runCmd("breakpoint command delete 1")
204
205        # Remove breakpoint 2.
206        self.runCmd("breakpoint delete 2")
207
208        self.expect(
209            "breakpoint command list 1",
210            startstr="Breakpoint 1 does not have an associated command.")
211        self.expect(
212            "breakpoint command list 2",
213            error=True,
214            startstr="error: '2' is not a currently valid breakpoint ID.")
215
216        # The breakpoint list now only contains breakpoint 1.
217        self.expect(
218            "breakpoint list -f",
219            "Breakpoint 1 exists",
220            patterns=[
221                "1: file = '.*main.c', line = %d, exact_match = 0, locations = 1, resolved = 1" %
222                self.line,
223                "hit count = 1"])
224
225        # Not breakpoint 2.
226        self.expect(
227            "breakpoint list -f",
228            "No more breakpoint 2",
229            matching=False,
230            substrs=[
231                "2: file = 'main.c', line = %d, exact_match = 0, locations = 1, resolved = 1" %
232                self.line])
233
234        # Run the program again, with breakpoint 1 remaining.
235        self.runCmd("run", RUN_SUCCEEDED)
236
237        # We should be stopped again due to breakpoint 1.
238
239        # The stop reason of the thread should be breakpoint.
240        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
241                    substrs=['stopped',
242                             'stop reason = breakpoint'])
243
244        # The breakpoint should have a hit count of 2.
245        lldbutil.check_breakpoint(self, bpno = 1, expected_hit_count = 2)
246
247    def breakpoint_command_script_parameters(self):
248        """Test that the frame and breakpoint location are being properly passed to the script breakpoint command function."""
249        exe = self.getBuildArtifact("a.out")
250        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
251
252        # Add a breakpoint.
253        lldbutil.run_break_set_by_file_and_line(
254            self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
255
256        # Now add callbacks for the breakpoints just created.
257        self.runCmd("breakpoint command add -s python -o 'import side_effect; side_effect.frame = str(frame); side_effect.bp_loc = str(bp_loc)' 1")
258
259        # Reset canary variables and run.
260        side_effect.frame = None
261        side_effect.bp_loc = None
262        self.runCmd("run", RUN_SUCCEEDED)
263
264        self.expect(side_effect.frame, exe=False, startstr="frame #0:")
265        self.expect(side_effect.bp_loc, exe=False,
266                patterns=["1.* where = .*main .* resolved,( hardware,)? hit count = 1"])
267
268    def breakpoint_commands_on_creation(self):
269        """Test that setting breakpoint commands when creating the breakpoint works"""
270        target = self.createTestTarget()
271
272        # Add a breakpoint.
273        lldbutil.run_break_set_by_file_and_line(
274            self, "main.c", self.line, num_expected_locations=1, loc_exact=True,
275            extra_options='-C bt -C "thread list" -C continue')
276
277        bkpt = target.FindBreakpointByID(1)
278        self.assertTrue(bkpt.IsValid(), "Couldn't find breakpoint 1")
279        com_list = lldb.SBStringList()
280        bkpt.GetCommandLineCommands(com_list)
281        self.assertEqual(com_list.GetSize(), 3, "Got the wrong number of commands")
282        self.assertEqual(com_list.GetStringAtIndex(0), "bt", "First bt")
283        self.assertEqual(com_list.GetStringAtIndex(1), "thread list", "Next thread list")
284        self.assertEqual(com_list.GetStringAtIndex(2), "continue", "Last continue")
285
286    def test_breakpoint_delete_disabled(self):
287        """Test 'break delete --disabled' works"""
288        self.build()
289        target = self.createTestTarget()
290
291        bp_1 = target.BreakpointCreateByName("main")
292        bp_2 = target.BreakpointCreateByName("not_here")
293        bp_3 = target.BreakpointCreateByName("main")
294        bp_3.AddName("DeleteMeNot")
295
296        bp_1.SetEnabled(False)
297        bp_3.SetEnabled(False)
298
299        bp_id_1 = bp_1.GetID()
300        bp_id_2 = bp_2.GetID()
301        bp_id_3 = bp_3.GetID()
302
303        self.runCmd("breakpoint delete --disabled DeleteMeNot")
304
305        bp_1 = target.FindBreakpointByID(bp_id_1)
306        self.assertFalse(bp_1.IsValid(), "Didn't delete disabled breakpoint 1")
307
308        bp_2 = target.FindBreakpointByID(bp_id_2)
309        self.assertTrue(bp_2.IsValid(), "Deleted enabled breakpoint 2")
310
311        bp_3 = target.FindBreakpointByID(bp_id_3)
312        self.assertTrue(bp_3.IsValid(), "DeleteMeNot didn't protect disabled breakpoint 3")
313
314        # Reset the first breakpoint, disable it, and do this again with no protected name:
315        bp_1 = target.BreakpointCreateByName("main")
316
317        bp_1.SetEnabled(False)
318
319        bp_id_1 = bp_1.GetID()
320
321        self.runCmd("breakpoint delete --disabled")
322
323        bp_1 = target.FindBreakpointByID(bp_id_1)
324        self.assertFalse(bp_1.IsValid(), "Didn't delete disabled breakpoint 1")
325
326        bp_2 = target.FindBreakpointByID(bp_id_2)
327        self.assertTrue(bp_2.IsValid(), "Deleted enabled breakpoint 2")
328
329        bp_3 = target.FindBreakpointByID(bp_id_3)
330        self.assertFalse(bp_3.IsValid(), "Didn't delete disabled breakpoint 3")
331