1"""
2Test some target commands: create, list, select, variable.
3"""
4
5import os
6import stat
7import tempfile
8
9import lldb
10from lldbsuite.test.decorators import *
11from lldbsuite.test.lldbtest import *
12from lldbsuite.test import lldbutil
13
14
15class targetCommandTestCase(TestBase):
16
17    def setUp(self):
18        # Call super's setUp().
19        TestBase.setUp(self)
20        # Find the line numbers for our breakpoints.
21        self.line_b = line_number('b.c', '// Set break point at this line.')
22        self.line_c = line_number('c.c', '// Set break point at this line.')
23
24    def buildB(self):
25        db = {'C_SOURCES': 'b.c', 'EXE': self.getBuildArtifact('b.out')}
26        self.build(dictionary=db)
27        self.addTearDownCleanup(dictionary=db)
28
29    def buildAll(self):
30        da = {'C_SOURCES': 'a.c', 'EXE': self.getBuildArtifact('a.out')}
31        self.build(dictionary=da)
32        self.addTearDownCleanup(dictionary=da)
33
34        self.buildB()
35
36        dc = {'C_SOURCES': 'c.c', 'EXE': self.getBuildArtifact('c.out')}
37        self.build(dictionary=dc)
38        self.addTearDownCleanup(dictionary=dc)
39
40    def test_target_command(self):
41        """Test some target commands: create, list, select."""
42        self.buildAll()
43        self.do_target_command()
44
45    @expectedFailureDarwin(archs=["arm64", "arm64e"]) # <rdar://problem/37773624>
46    def test_target_variable_command(self):
47        """Test 'target variable' command before and after starting the inferior."""
48        d = {'C_SOURCES': 'globals.c', 'EXE': self.getBuildArtifact('globals')}
49        self.build(dictionary=d)
50        self.addTearDownCleanup(dictionary=d)
51
52        self.do_target_variable_command('globals')
53
54    @expectedFailureDarwin(archs=["arm64", "arm64e"]) # <rdar://problem/37773624>
55    def test_target_variable_command_no_fail(self):
56        """Test 'target variable' command before and after starting the inferior."""
57        d = {'C_SOURCES': 'globals.c', 'EXE': self.getBuildArtifact('globals')}
58        self.build(dictionary=d)
59        self.addTearDownCleanup(dictionary=d)
60
61        self.do_target_variable_command_no_fail('globals')
62
63    def do_target_command(self):
64        """Exercise 'target create', 'target list', 'target select' commands."""
65        exe_a = self.getBuildArtifact("a.out")
66        exe_b = self.getBuildArtifact("b.out")
67        exe_c = self.getBuildArtifact("c.out")
68
69        self.runCmd("target list")
70        output = self.res.GetOutput()
71        if output.startswith("No targets"):
72            # We start from index 0.
73            base = 0
74        else:
75            # Find the largest index of the existing list.
76            import re
77            pattern = re.compile("target #(\d+):")
78            for line in reversed(output.split(os.linesep)):
79                match = pattern.search(line)
80                if match:
81                    # We will start from (index + 1) ....
82                    base = int(match.group(1), 10) + 1
83                    self.trace("base is:", base)
84                    break
85
86        self.runCmd("target create " + exe_a, CURRENT_EXECUTABLE_SET)
87        self.runCmd("run", RUN_SUCCEEDED)
88
89        self.runCmd("target create " + exe_b, CURRENT_EXECUTABLE_SET)
90        lldbutil.run_break_set_by_file_and_line(
91            self, 'b.c', self.line_b, num_expected_locations=1, loc_exact=True)
92        self.runCmd("run", RUN_SUCCEEDED)
93
94        self.runCmd("target create " + exe_c, CURRENT_EXECUTABLE_SET)
95        lldbutil.run_break_set_by_file_and_line(
96            self, 'c.c', self.line_c, num_expected_locations=1, loc_exact=True)
97        self.runCmd("run", RUN_SUCCEEDED)
98
99        self.runCmd("target list")
100
101        self.runCmd("target select %d" % base)
102        self.runCmd("thread backtrace")
103
104        self.runCmd("target select %d" % (base + 2))
105        self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
106                    substrs=['stop reason = breakpoint' ,'c.c:%d' % self.line_c
107                             ])
108
109        self.runCmd("target select %d" % (base + 1))
110        self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
111                    substrs=['stop reason = breakpoint', 'b.c:%d' % self.line_b
112                             ])
113
114        self.runCmd("target list")
115
116    @no_debug_info_test
117    def test_target_create_invalid_arch(self):
118        exe = self.getBuildArtifact("a.out")
119        self.expect("target create {} --arch doesntexist".format(exe), error=True,
120                    patterns=["error: invalid triple 'doesntexist'"])
121
122    @no_debug_info_test
123    def test_target_create_platform(self):
124        self.buildB()
125        exe = self.getBuildArtifact("b.out")
126        self.expect("target create {} --platform host".format(exe))
127
128    @no_debug_info_test
129    def test_target_create_unsupported_platform(self):
130        yaml = os.path.join(self.getSourceDir(), "bogus.yaml")
131        exe = self.getBuildArtifact("bogus")
132        self.yaml2obj(yaml, exe)
133        self.expect("target create {}".format(exe), error=True,
134                    patterns=['error: no matching platforms found for this file'])
135
136    @no_debug_info_test
137    def test_target_create_invalid_platform(self):
138        self.buildB()
139        exe = self.getBuildArtifact("b.out")
140        self.expect("target create {} --platform doesntexist".format(exe), error=True,
141                    patterns=['error: unable to find a plug-in for the platform named "doesntexist"'])
142
143    def do_target_variable_command(self, exe_name):
144        """Exercise 'target variable' command before and after starting the inferior."""
145        self.runCmd("file " + self.getBuildArtifact(exe_name),
146                    CURRENT_EXECUTABLE_SET)
147
148        self.expect(
149            "target variable my_global_char",
150            VARIABLES_DISPLAYED_CORRECTLY,
151            substrs=[
152                "my_global_char",
153                "'X'"])
154        self.expect(
155            "target variable my_global_str",
156            VARIABLES_DISPLAYED_CORRECTLY,
157            substrs=[
158                'my_global_str',
159                '"abc"'])
160        self.expect(
161            "target variable my_static_int",
162            VARIABLES_DISPLAYED_CORRECTLY,
163            substrs=[
164                'my_static_int',
165                '228'])
166        self.expect("target variable my_global_str_ptr", matching=False,
167                    substrs=['"abc"'])
168        self.expect("target variable *my_global_str_ptr", matching=True,
169                    substrs=['"abc"'])
170        self.expect(
171            "target variable *my_global_str",
172            VARIABLES_DISPLAYED_CORRECTLY,
173            substrs=['a'])
174
175        self.runCmd("b main")
176        self.runCmd("run")
177
178        self.expect(
179            "target variable my_global_str",
180            VARIABLES_DISPLAYED_CORRECTLY,
181            substrs=[
182                'my_global_str',
183                '"abc"'])
184        self.expect(
185            "target variable my_static_int",
186            VARIABLES_DISPLAYED_CORRECTLY,
187            substrs=[
188                'my_static_int',
189                '228'])
190        self.expect("target variable my_global_str_ptr", matching=False,
191                    substrs=['"abc"'])
192        self.expect("target variable *my_global_str_ptr", matching=True,
193                    substrs=['"abc"'])
194        self.expect(
195            "target variable *my_global_str",
196            VARIABLES_DISPLAYED_CORRECTLY,
197            substrs=['a'])
198        self.expect(
199            "target variable my_global_char",
200            VARIABLES_DISPLAYED_CORRECTLY,
201            substrs=[
202                "my_global_char",
203                "'X'"])
204
205        self.runCmd("c")
206
207        self.expect(
208            "target variable my_global_str",
209            VARIABLES_DISPLAYED_CORRECTLY,
210            substrs=[
211                'my_global_str',
212                '"abc"'])
213        self.expect(
214            "target variable my_static_int",
215            VARIABLES_DISPLAYED_CORRECTLY,
216            substrs=[
217                'my_static_int',
218                '228'])
219        self.expect("target variable my_global_str_ptr", matching=False,
220                    substrs=['"abc"'])
221        self.expect("target variable *my_global_str_ptr", matching=True,
222                    substrs=['"abc"'])
223        self.expect(
224            "target variable *my_global_str",
225            VARIABLES_DISPLAYED_CORRECTLY,
226            substrs=['a'])
227        self.expect(
228            "target variable my_global_char",
229            VARIABLES_DISPLAYED_CORRECTLY,
230            substrs=[
231                "my_global_char",
232                "'X'"])
233
234    def do_target_variable_command_no_fail(self, exe_name):
235        """Exercise 'target variable' command before and after starting the inferior."""
236        self.runCmd("file " + self.getBuildArtifact(exe_name),
237                    CURRENT_EXECUTABLE_SET)
238
239        self.expect(
240            "target variable my_global_char",
241            VARIABLES_DISPLAYED_CORRECTLY,
242            substrs=[
243                "my_global_char",
244                "'X'"])
245        self.expect(
246            "target variable my_global_str",
247            VARIABLES_DISPLAYED_CORRECTLY,
248            substrs=[
249                'my_global_str',
250                '"abc"'])
251        self.expect(
252            "target variable my_static_int",
253            VARIABLES_DISPLAYED_CORRECTLY,
254            substrs=[
255                'my_static_int',
256                '228'])
257        self.expect("target variable my_global_str_ptr", matching=False,
258                    substrs=['"abc"'])
259        self.expect("target variable *my_global_str_ptr", matching=True,
260                    substrs=['"abc"'])
261        self.expect(
262            "target variable *my_global_str",
263            VARIABLES_DISPLAYED_CORRECTLY,
264            substrs=['a'])
265
266        self.runCmd("b main")
267        self.runCmd("run")
268
269        # New feature: you don't need to specify the variable(s) to 'target vaiable'.
270        # It will find all the global and static variables in the current
271        # compile unit.
272        self.expect("target variable",
273                    ordered=False,
274                    substrs=['my_global_char',
275                             'my_static_int',
276                             'my_global_str',
277                             'my_global_str_ptr',
278                             ])
279
280        self.expect(
281            "target variable my_global_str",
282            VARIABLES_DISPLAYED_CORRECTLY,
283            substrs=[
284                'my_global_str',
285                '"abc"'])
286        self.expect(
287            "target variable my_static_int",
288            VARIABLES_DISPLAYED_CORRECTLY,
289            substrs=[
290                'my_static_int',
291                '228'])
292        self.expect("target variable my_global_str_ptr", matching=False,
293                    substrs=['"abc"'])
294        self.expect("target variable *my_global_str_ptr", matching=True,
295                    substrs=['"abc"'])
296        self.expect(
297            "target variable *my_global_str",
298            VARIABLES_DISPLAYED_CORRECTLY,
299            substrs=['a'])
300        self.expect(
301            "target variable my_global_char",
302            VARIABLES_DISPLAYED_CORRECTLY,
303            substrs=[
304                "my_global_char",
305                "'X'"])
306
307    @no_debug_info_test
308    def test_target_stop_hook_disable_enable(self):
309        self.buildB()
310        self.runCmd("file " + self.getBuildArtifact("b.out"), CURRENT_EXECUTABLE_SET)
311
312        self.expect("target stop-hook disable 1", error=True, substrs=['unknown stop hook id: "1"'])
313        self.expect("target stop-hook disable blub", error=True, substrs=['invalid stop hook id: "blub"'])
314        self.expect("target stop-hook enable 1", error=True, substrs=['unknown stop hook id: "1"'])
315        self.expect("target stop-hook enable blub", error=True, substrs=['invalid stop hook id: "blub"'])
316
317    @no_debug_info_test
318    def test_target_stop_hook_delete(self):
319        self.buildB()
320        self.runCmd("file " + self.getBuildArtifact("b.out"), CURRENT_EXECUTABLE_SET)
321
322        self.expect("target stop-hook delete 1", error=True, substrs=['unknown stop hook id: "1"'])
323        self.expect("target stop-hook delete blub", error=True, substrs=['invalid stop hook id: "blub"'])
324
325    @no_debug_info_test
326    def test_target_list_args(self):
327        self.expect("target list blub", error=True,
328                    substrs=["'target list' doesn't take any arguments"])
329
330    @no_debug_info_test
331    def test_target_select_no_index(self):
332        self.expect("target select", error=True,
333                    substrs=["'target select' takes a single argument: a target index"])
334
335    @no_debug_info_test
336    def test_target_select_invalid_index(self):
337        self.runCmd("target delete --all")
338        self.expect("target select 0", error=True,
339                    substrs=["index 0 is out of range since there are no active targets"])
340        self.buildB()
341        self.runCmd("file " + self.getBuildArtifact("b.out"), CURRENT_EXECUTABLE_SET)
342        self.expect("target select 1", error=True,
343                    substrs=["index 1 is out of range, valid target indexes are 0 - 0"])
344
345
346    @no_debug_info_test
347    def test_target_create_multiple_args(self):
348        self.expect("target create a b", error=True,
349                    substrs=["'target create' takes exactly one executable path"])
350
351    @skipIfWindowsAndNonEnglish
352    @no_debug_info_test
353    def test_target_create_nonexistent_core_file(self):
354        self.expect("target create -c doesntexist", error=True,
355                    patterns=["Cannot open 'doesntexist'", ": (No such file or directory|The system cannot find the file specified)"])
356
357    # Write only files don't seem to be supported on Windows.
358    @skipIfWindows
359    @no_debug_info_test
360    def test_target_create_unreadable_core_file(self):
361        tf = tempfile.NamedTemporaryFile()
362        os.chmod(tf.name, stat.S_IWRITE)
363        self.expect("target create -c '" + tf.name + "'", error=True,
364                    substrs=["Cannot open '", "': Permission denied"])
365
366    @skipIfWindowsAndNonEnglish
367    @no_debug_info_test
368    def test_target_create_nonexistent_sym_file(self):
369        self.expect("target create -s doesntexist doesntexisteither", error=True,
370                    patterns=["Cannot open '", ": (No such file or directory|The system cannot find the file specified)"])
371
372    @skipIfWindows
373    @no_debug_info_test
374    def test_target_create_invalid_core_file(self):
375        invalid_core_path = os.path.join(self.getSourceDir(), "invalid_core_file")
376        self.expect("target create -c '" + invalid_core_path + "'", error=True,
377                    substrs=["Unable to find process plug-in for core file '"])
378
379
380    # Write only files don't seem to be supported on Windows.
381    @skipIfWindows
382    @no_debug_info_test
383    def test_target_create_unreadable_sym_file(self):
384        tf = tempfile.NamedTemporaryFile()
385        os.chmod(tf.name, stat.S_IWRITE)
386        self.expect("target create -s '" + tf.name + "' no_exe", error=True,
387                    substrs=["Cannot open '", "': Permission denied"])
388
389    @no_debug_info_test
390    def test_target_delete_all(self):
391        self.buildAll()
392        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
393        self.runCmd("file " + self.getBuildArtifact("b.out"), CURRENT_EXECUTABLE_SET)
394        self.expect("target delete --all")
395        self.expect("target list", substrs=["No targets."])
396
397    @no_debug_info_test
398    def test_target_delete_by_index(self):
399        self.buildAll()
400        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
401        self.runCmd("file " + self.getBuildArtifact("b.out"), CURRENT_EXECUTABLE_SET)
402        self.runCmd("file " + self.getBuildArtifact("c.out"), CURRENT_EXECUTABLE_SET)
403        self.expect("target delete 3", error=True,
404                    substrs=["target index 3 is out of range, valid target indexes are 0 - 2"])
405
406        self.runCmd("target delete 1")
407        self.expect("target list", matching=False, substrs=["b.out"])
408        self.runCmd("target delete 1")
409        self.expect("target list", matching=False, substrs=["c.out"])
410
411        self.expect("target delete 1", error=True,
412                    substrs=["target index 1 is out of range, the only valid index is 0"])
413
414        self.runCmd("target delete 0")
415        self.expect("target list", matching=False, substrs=["a.out"])
416
417        self.expect("target delete 0", error=True, substrs=["no targets to delete"])
418        self.expect("target delete 1", error=True, substrs=["no targets to delete"])
419
420    @no_debug_info_test
421    def test_target_delete_by_index_multiple(self):
422        self.buildAll()
423        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
424        self.runCmd("file " + self.getBuildArtifact("b.out"), CURRENT_EXECUTABLE_SET)
425        self.runCmd("file " + self.getBuildArtifact("c.out"), CURRENT_EXECUTABLE_SET)
426
427        self.expect("target delete 0 1 2 3", error=True,
428                    substrs=["target index 3 is out of range, valid target indexes are 0 - 2"])
429        self.expect("target list", substrs=["a.out", "b.out", "c.out"])
430
431        self.runCmd("target delete 0 1 2")
432        self.expect("target list", matching=False, substrs=["a.out", "c.out"])
433
434    @no_debug_info_test
435    def test_target_delete_selected(self):
436        self.buildAll()
437        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
438        self.runCmd("file " + self.getBuildArtifact("b.out"), CURRENT_EXECUTABLE_SET)
439        self.runCmd("file " + self.getBuildArtifact("c.out"), CURRENT_EXECUTABLE_SET)
440        self.runCmd("target select 1")
441        self.runCmd("target delete")
442        self.expect("target list", matching=False, substrs=["b.out"])
443        self.runCmd("target delete")
444        self.runCmd("target delete")
445        self.expect("target list", substrs=["No targets."])
446        self.expect("target delete", error=True, substrs=["no target is currently selected"])
447
448    @no_debug_info_test
449    def test_target_modules_search_paths_clear(self):
450        self.buildB()
451        self.runCmd("file " + self.getBuildArtifact("b.out"), CURRENT_EXECUTABLE_SET)
452        self.runCmd("target modules search-paths add foo bar")
453        self.runCmd("target modules search-paths add foz baz")
454        self.runCmd("target modules search-paths clear")
455        self.expect("target list", matching=False, substrs=["bar", "baz"])
456
457    @no_debug_info_test
458    def test_target_modules_search_paths_query(self):
459        self.buildB()
460        self.runCmd("file " + self.getBuildArtifact("b.out"), CURRENT_EXECUTABLE_SET)
461        self.runCmd("target modules search-paths add foo bar")
462        self.expect("target modules search-paths query foo", substrs=["bar"])
463        # Query something that doesn't exist.
464        self.expect("target modules search-paths query faz", substrs=["faz"])
465
466        # Invalid arguments.
467        self.expect("target modules search-paths query faz baz", error=True,
468                    substrs=["query requires one argument"])
469
470    @no_debug_info_test
471    @expectedFailureAll(oslist=["freebsd"],
472                        bugnumber="github.com/llvm/llvm-project/issues/56079")
473    def test_target_modules_type(self):
474        self.buildB()
475        self.runCmd("file " + self.getBuildArtifact("b.out"),
476                    CURRENT_EXECUTABLE_SET)
477        self.expect("target modules lookup --type int",
478                    substrs=["1 match found", 'name = "int"'])
479