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