]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py
Vendor import of lldb trunk r321017:
[FreeBSD/FreeBSD.git] / packages / Python / lldbsuite / test / functionalities / load_unload / TestLoadUnload.py
1 """
2 Test that breakpoint by symbol name works correctly with dynamic libs.
3 """
4
5 from __future__ import print_function
6
7
8 import os
9 import time
10 import re
11 import lldb
12 from lldbsuite.test.decorators import *
13 from lldbsuite.test.lldbtest import *
14 from lldbsuite.test import lldbutil
15
16
17 @skipIfWindows  # Windows doesn't have dlopen and friends, dynamic libraries work differently
18 class LoadUnloadTestCase(TestBase):
19
20     mydir = TestBase.compute_mydir(__file__)
21
22     def setUp(self):
23         # Call super's setUp().
24         TestBase.setUp(self)
25         # Find the line number to break for main.cpp.
26         self.line = line_number(
27             'main.cpp',
28             '// Set break point at this line for test_lldb_process_load_and_unload_commands().')
29         self.line_d_function = line_number(
30             'd.cpp', '// Find this line number within d_dunction().')
31         if not self.platformIsDarwin():
32             if not lldb.remote_platform and "LD_LIBRARY_PATH" in os.environ:
33                 self.runCmd(
34                     "settings set target.env-vars " +
35                     self.dylibPath +
36                     "=" +
37                     os.environ["LD_LIBRARY_PATH"] +
38                     ":" +
39                     os.getcwd())
40             else:
41                 if lldb.remote_platform:
42                     wd = lldb.remote_platform.GetWorkingDirectory()
43                 else:
44                     wd = os.getcwd()
45                 self.runCmd(
46                     "settings set target.env-vars " +
47                     self.dylibPath +
48                     "=" +
49                     wd)
50
51     def copy_shlibs_to_remote(self, hidden_dir=False):
52         """ Copies the shared libs required by this test suite to remote.
53         Does nothing in case of non-remote platforms.
54         """
55         if lldb.remote_platform:
56             ext = 'so'
57             if self.platformIsDarwin():
58                 ext = 'dylib'
59
60             shlibs = ['libloadunload_a.' + ext, 'libloadunload_b.' + ext,
61                       'libloadunload_c.' + ext, 'libloadunload_d.' + ext]
62             wd = lldb.remote_platform.GetWorkingDirectory()
63             cwd = os.getcwd()
64             for f in shlibs:
65                 err = lldb.remote_platform.Put(
66                     lldb.SBFileSpec(os.path.join(cwd, f)),
67                     lldb.SBFileSpec(os.path.join(wd, f)))
68                 if err.Fail():
69                     raise RuntimeError(
70                         "Unable copy '%s' to '%s'.\n>>> %s" %
71                         (f, wd, err.GetCString()))
72             if hidden_dir:
73                 shlib = 'libloadunload_d.' + ext
74                 hidden_dir = os.path.join(wd, 'hidden')
75                 hidden_file = os.path.join(hidden_dir, shlib)
76                 err = lldb.remote_platform.MakeDirectory(hidden_dir)
77                 if err.Fail():
78                     raise RuntimeError(
79                         "Unable to create a directory '%s'." % hidden_dir)
80                 err = lldb.remote_platform.Put(
81                     lldb.SBFileSpec(os.path.join(cwd, 'hidden', shlib)),
82                     lldb.SBFileSpec(hidden_file))
83                 if err.Fail():
84                     raise RuntimeError(
85                         "Unable copy 'libloadunload_d.so' to '%s'.\n>>> %s" %
86                         (wd, err.GetCString()))
87
88     @skipIfFreeBSD  # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
89     @not_remote_testsuite_ready
90     @skipIfWindows  # Windows doesn't have dlopen and friends, dynamic libraries work differently
91     def test_modules_search_paths(self):
92         """Test target modules list after loading a different copy of the library libd.dylib, and verifies that it works with 'target modules search-paths add'."""
93
94         # Invoke the default build rule.
95         self.build()
96
97         if self.platformIsDarwin():
98             dylibName = 'libloadunload_d.dylib'
99         else:
100             dylibName = 'libloadunload_d.so'
101
102         # The directory with the dynamic library we did not link to.
103         new_dir = os.path.join(os.getcwd(), "hidden")
104
105         old_dylib = os.path.join(os.getcwd(), dylibName)
106         new_dylib = os.path.join(new_dir, dylibName)
107
108         exe = os.path.join(os.getcwd(), "a.out")
109         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
110
111         self.expect("target modules list",
112                     substrs=[old_dylib])
113         # self.expect("target modules list -t 3",
114         #    patterns = ["%s-[^-]*-[^-]*" % self.getArchitecture()])
115         # Add an image search path substitution pair.
116         self.runCmd(
117             "target modules search-paths add %s %s" %
118             (os.getcwd(), new_dir))
119
120         self.expect("target modules search-paths list",
121                     substrs=[os.getcwd(), new_dir])
122
123         self.expect(
124             "target modules search-paths query %s" %
125             os.getcwd(),
126             "Image search path successfully transformed",
127             substrs=[new_dir])
128
129         # Obliterate traces of libd from the old location.
130         os.remove(old_dylib)
131         # Inform (DY)LD_LIBRARY_PATH of the new path, too.
132         env_cmd_string = "settings set target.env-vars " + self.dylibPath + "=" + new_dir
133         if self.TraceOn():
134             print("Set environment to: ", env_cmd_string)
135         self.runCmd(env_cmd_string)
136         self.runCmd("settings show target.env-vars")
137
138         remove_dyld_path_cmd = "settings remove target.env-vars " + self.dylibPath
139         self.addTearDownHook(
140             lambda: self.dbg.HandleCommand(remove_dyld_path_cmd))
141
142         self.runCmd("run")
143
144         self.expect(
145             "target modules list",
146             "LLDB successfully locates the relocated dynamic library",
147             substrs=[new_dylib])
148
149     @skipIfFreeBSD  # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
150     @expectedFailureAndroid  # wrong source file shows up for hidden library
151     @skipIfWindows  # Windows doesn't have dlopen and friends, dynamic libraries work differently
152     def test_dyld_library_path(self):
153         """Test (DY)LD_LIBRARY_PATH after moving libd.dylib, which defines d_function, somewhere else."""
154
155         # Invoke the default build rule.
156         self.build()
157         self.copy_shlibs_to_remote(hidden_dir=True)
158
159         exe = os.path.join(os.getcwd(), "a.out")
160         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
161
162         # Shut off ANSI color usage so we don't get ANSI escape sequences
163         # mixed in with stop locations.
164         self.dbg.SetUseColor(False)
165
166         if self.platformIsDarwin():
167             dylibName = 'libloadunload_d.dylib'
168             dsymName = 'libloadunload_d.dylib.dSYM'
169         else:
170             dylibName = 'libloadunload_d.so'
171
172         # The directory to relocate the dynamic library and its debugging info.
173         special_dir = "hidden"
174         if lldb.remote_platform:
175             wd = lldb.remote_platform.GetWorkingDirectory()
176         else:
177             wd = os.getcwd()
178
179         old_dir = wd
180         new_dir = os.path.join(wd, special_dir)
181         old_dylib = os.path.join(old_dir, dylibName)
182
183         remove_dyld_path_cmd = "settings remove target.env-vars " + self.dylibPath
184         self.addTearDownHook(
185             lambda: self.dbg.HandleCommand(remove_dyld_path_cmd))
186
187         # For now we don't track (DY)LD_LIBRARY_PATH, so the old library will be in
188         # the modules list.
189         self.expect("target modules list",
190                     substrs=[os.path.basename(old_dylib)],
191                     matching=True)
192
193         lldbutil.run_break_set_by_file_and_line(
194             self, "d.cpp", self.line_d_function, num_expected_locations=1)
195         # After run, make sure the non-hidden library is picked up.
196         self.expect("run", substrs=["return", "700"])
197
198         self.runCmd("continue")
199
200         # Add the hidden directory first in the search path.
201         env_cmd_string = ("settings set target.env-vars %s=%s" %
202                           (self.dylibPath, new_dir))
203         if not self.platformIsDarwin():
204             env_cmd_string += ":" + wd
205         self.runCmd(env_cmd_string)
206
207         # This time, the hidden library should be picked up.
208         self.expect("run", substrs=["return", "12345"])
209
210     @expectedFailureAll(
211         bugnumber="llvm.org/pr25805",
212         hostoslist=["windows"],
213         compiler="gcc",
214         archs=["i386"],
215         triple='.*-android')
216     @skipIfFreeBSD  # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
217     @skipIfWindows  # Windows doesn't have dlopen and friends, dynamic libraries work differently
218     def test_lldb_process_load_and_unload_commands(self):
219         """Test that lldb process load/unload command work correctly."""
220
221         # Invoke the default build rule.
222         self.build()
223         self.copy_shlibs_to_remote()
224
225         exe = os.path.join(os.getcwd(), "a.out")
226         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
227
228         # Break at main.cpp before the call to dlopen().
229         # Use lldb's process load command to load the dylib, instead.
230
231         lldbutil.run_break_set_by_file_and_line(
232             self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
233
234         self.runCmd("run", RUN_SUCCEEDED)
235
236         if lldb.remote_platform:
237             shlib_dir = lldb.remote_platform.GetWorkingDirectory()
238         else:
239             shlib_dir = self.mydir
240
241         if self.platformIsDarwin():
242             dylibName = 'libloadunload_a.dylib'
243         else:
244             dylibName = 'libloadunload_a.so'
245
246         # Make sure that a_function does not exist at this point.
247         self.expect(
248             "image lookup -n a_function",
249             "a_function should not exist yet",
250             error=True,
251             matching=False,
252             patterns=["1 match found"])
253
254         # Use lldb 'process load' to load the dylib.
255         self.expect(
256             "process load %s --install" %
257             dylibName,
258             "%s loaded correctly" %
259             dylibName,
260             patterns=[
261                 'Loading "%s".*ok' %
262                 dylibName,
263                 'Image [0-9]+ loaded'])
264
265         # Search for and match the "Image ([0-9]+) loaded" pattern.
266         output = self.res.GetOutput()
267         pattern = re.compile("Image ([0-9]+) loaded")
268         for l in output.split(os.linesep):
269             #print("l:", l)
270             match = pattern.search(l)
271             if match:
272                 break
273         index = match.group(1)
274
275         # Now we should have an entry for a_function.
276         self.expect(
277             "image lookup -n a_function",
278             "a_function should now exist",
279             patterns=[
280                 "1 match found .*%s" %
281                 dylibName])
282
283         # Use lldb 'process unload' to unload the dylib.
284         self.expect(
285             "process unload %s" %
286             index,
287             "%s unloaded correctly" %
288             dylibName,
289             patterns=[
290                 "Unloading .* with index %s.*ok" %
291                 index])
292
293         self.runCmd("process continue")
294
295     @skipIfFreeBSD  # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
296     def test_load_unload(self):
297         """Test breakpoint by name works correctly with dlopen'ing."""
298
299         # Invoke the default build rule.
300         self.build()
301         self.copy_shlibs_to_remote()
302
303         exe = os.path.join(os.getcwd(), "a.out")
304         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
305
306         # Break by function name a_function (not yet loaded).
307         lldbutil.run_break_set_by_symbol(
308             self, "a_function", num_expected_locations=0)
309
310         self.runCmd("run", RUN_SUCCEEDED)
311
312         # The stop reason of the thread should be breakpoint and at a_function.
313         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
314                     substrs=['stopped',
315                              'a_function',
316                              'stop reason = breakpoint'])
317
318         # The breakpoint should have a hit count of 1.
319         self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
320                     substrs=[' resolved, hit count = 1'])
321
322         # Issue the 'contnue' command.  We should stop agaian at a_function.
323         # The stop reason of the thread should be breakpoint and at a_function.
324         self.runCmd("continue")
325
326         # rdar://problem/8508987
327         # The a_function breakpoint should be encountered twice.
328         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
329                     substrs=['stopped',
330                              'a_function',
331                              'stop reason = breakpoint'])
332
333         # The breakpoint should have a hit count of 2.
334         self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
335                     substrs=[' resolved, hit count = 2'])
336
337     @skipIfFreeBSD  # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
338     @skipIfWindows  # Windows doesn't have dlopen and friends, dynamic libraries work differently
339     def test_step_over_load(self):
340         """Test stepping over code that loads a shared library works correctly."""
341
342         # Invoke the default build rule.
343         self.build()
344         self.copy_shlibs_to_remote()
345
346         exe = os.path.join(os.getcwd(), "a.out")
347         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
348
349         # Break by function name a_function (not yet loaded).
350         lldbutil.run_break_set_by_file_and_line(
351             self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
352
353         self.runCmd("run", RUN_SUCCEEDED)
354
355         # The stop reason of the thread should be breakpoint and at a_function.
356         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
357                     substrs=['stopped',
358                              'stop reason = breakpoint'])
359
360         self.runCmd(
361             "thread step-over",
362             "Stepping over function that loads library")
363
364         # The stop reason should be step end.
365         self.expect("thread list", "step over succeeded.",
366                     substrs=['stopped',
367                              'stop reason = step over'])
368
369     @skipIfFreeBSD  # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
370     @skipIfWindows  # Windows doesn't have dlopen and friends, dynamic libraries work differently
371     @unittest2.expectedFailure("llvm.org/pr25806")
372     def test_static_init_during_load(self):
373         """Test that we can set breakpoints correctly in static initializers"""
374
375         self.build()
376         self.copy_shlibs_to_remote()
377
378         exe = os.path.join(os.getcwd(), "a.out")
379         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
380
381         a_init_bp_num = lldbutil.run_break_set_by_symbol(
382             self, "a_init", num_expected_locations=0)
383         b_init_bp_num = lldbutil.run_break_set_by_symbol(
384             self, "b_init", num_expected_locations=0)
385         d_init_bp_num = lldbutil.run_break_set_by_symbol(
386             self, "d_init", num_expected_locations=1)
387
388         self.runCmd("run", RUN_SUCCEEDED)
389
390         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
391                     substrs=['stopped',
392                              'd_init',
393                              'stop reason = breakpoint %d' % d_init_bp_num])
394
395         self.runCmd("continue")
396         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
397                     substrs=['stopped',
398                              'a_init',
399                              'stop reason = breakpoint %d' % a_init_bp_num])
400         self.expect("thread backtrace",
401                     substrs=['a_init',
402                              'dlopen',
403                              'main'])
404
405         self.runCmd("continue")
406         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
407                     substrs=['stopped',
408                              'b_init',
409                              'stop reason = breakpoint %d' % b_init_bp_num])
410         self.expect("thread backtrace",
411                     substrs=['b_init',
412                              'dlopen',
413                              'main'])