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