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