2 Test that breakpoint by symbol name works correctly with dynamic libs.
5 from __future__ import print_function
12 from lldbsuite.test.decorators import *
13 from lldbsuite.test.lldbtest import *
14 from lldbsuite.test import lldbutil
17 @skipIfWindows # Windows doesn't have dlopen and friends, dynamic libraries work differently
18 class LoadUnloadTestCase(TestBase):
20 mydir = TestBase.compute_mydir(__file__)
22 NO_DEBUG_INFO_TESTCASE = True
25 # Call super's setUp().
28 # Invoke the default build rule.
30 # Find the line number to break for main.cpp.
31 self.line = line_number(
33 '// Set break point at this line for test_lldb_process_load_and_unload_commands().')
34 self.line_d_function = line_number(
35 'd.cpp', '// Find this line number within d_dunction().')
38 lldbutil.mkdir_p(self.getBuildArtifact("hidden"))
39 if not self.platformIsDarwin():
40 if not lldb.remote_platform and "LD_LIBRARY_PATH" in os.environ:
42 "settings set target.env-vars " +
45 os.environ["LD_LIBRARY_PATH"] +
49 if lldb.remote_platform:
50 wd = lldb.remote_platform.GetWorkingDirectory()
52 wd = self.getBuildDir()
54 "settings set target.env-vars " +
59 def copy_shlibs_to_remote(self, hidden_dir=False):
60 """ Copies the shared libs required by this test suite to remote.
61 Does nothing in case of non-remote platforms.
63 if lldb.remote_platform:
65 if self.platformIsDarwin():
68 shlibs = ['libloadunload_a.' + ext, 'libloadunload_b.' + ext,
69 'libloadunload_c.' + ext, 'libloadunload_d.' + ext]
70 wd = lldb.remote_platform.GetWorkingDirectory()
73 err = lldb.remote_platform.Put(
74 lldb.SBFileSpec(self.getBuildArtifact(f)),
75 lldb.SBFileSpec(os.path.join(wd, f)))
78 "Unable copy '%s' to '%s'.\n>>> %s" %
79 (f, wd, err.GetCString()))
81 shlib = 'libloadunload_d.' + ext
82 hidden_dir = os.path.join(wd, 'hidden')
83 hidden_file = os.path.join(hidden_dir, shlib)
84 err = lldb.remote_platform.MakeDirectory(hidden_dir)
87 "Unable to create a directory '%s'." % hidden_dir)
88 err = lldb.remote_platform.Put(
89 lldb.SBFileSpec(os.path.join('hidden', shlib)),
90 lldb.SBFileSpec(hidden_file))
93 "Unable copy 'libloadunload_d.so' to '%s'.\n>>> %s" %
94 (wd, err.GetCString()))
96 # libloadunload_d.so does not appear in the image list because executable
97 # dependencies are resolved relative to the debuggers PWD. Bug?
98 @expectedFailureAll(oslist=["linux"])
99 @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
100 @not_remote_testsuite_ready
101 @skipIfWindows # Windows doesn't have dlopen and friends, dynamic libraries work differently
102 def test_modules_search_paths(self):
103 """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'."""
104 if self.platformIsDarwin():
105 dylibName = 'libloadunload_d.dylib'
107 dylibName = 'libloadunload_d.so'
109 # The directory with the dynamic library we did not link to.
110 new_dir = os.path.join(self.getBuildDir(), "hidden")
112 old_dylib = os.path.join(self.getBuildDir(), dylibName)
113 new_dylib = os.path.join(new_dir, dylibName)
114 exe = self.getBuildArtifact("a.out")
115 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
117 self.expect("target modules list",
119 # self.expect("target modules list -t 3",
120 # patterns = ["%s-[^-]*-[^-]*" % self.getArchitecture()])
121 # Add an image search path substitution pair.
123 "target modules search-paths add %s %s" %
124 (self.getBuildDir(), new_dir))
126 self.expect("target modules search-paths list",
127 substrs=[self.getBuildDir(), new_dir])
130 "target modules search-paths query %s" %
132 "Image search path successfully transformed",
135 # Obliterate traces of libd from the old location.
137 # Inform (DY)LD_LIBRARY_PATH of the new path, too.
138 env_cmd_string = "settings set target.env-vars " + self.dylibPath + "=" + new_dir
140 print("Set environment to: ", env_cmd_string)
141 self.runCmd(env_cmd_string)
142 self.runCmd("settings show target.env-vars")
144 remove_dyld_path_cmd = "settings remove target.env-vars " + self.dylibPath
145 self.addTearDownHook(
146 lambda: self.dbg.HandleCommand(remove_dyld_path_cmd))
151 "target modules list",
152 "LLDB successfully locates the relocated dynamic library",
155 # libloadunload_d.so does not appear in the image list because executable
156 # dependencies are resolved relative to the debuggers PWD. Bug?
157 @expectedFailureAll(oslist=["linux"])
158 @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
159 @expectedFailureAndroid # wrong source file shows up for hidden library
160 @skipIfWindows # Windows doesn't have dlopen and friends, dynamic libraries work differently
161 def test_dyld_library_path(self):
162 """Test (DY)LD_LIBRARY_PATH after moving libd.dylib, which defines d_function, somewhere else."""
163 self.copy_shlibs_to_remote(hidden_dir=True)
165 exe = self.getBuildArtifact("a.out")
166 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
168 # Shut off ANSI color usage so we don't get ANSI escape sequences
169 # mixed in with stop locations.
170 self.dbg.SetUseColor(False)
172 if self.platformIsDarwin():
173 dylibName = 'libloadunload_d.dylib'
174 dsymName = 'libloadunload_d.dylib.dSYM'
176 dylibName = 'libloadunload_d.so'
178 # The directory to relocate the dynamic library and its debugging info.
179 special_dir = "hidden"
180 if lldb.remote_platform:
181 wd = lldb.remote_platform.GetWorkingDirectory()
183 wd = self.getBuildDir()
186 new_dir = os.path.join(wd, special_dir)
187 old_dylib = os.path.join(old_dir, dylibName)
189 remove_dyld_path_cmd = "settings remove target.env-vars " \
191 self.addTearDownHook(
192 lambda: self.dbg.HandleCommand(remove_dyld_path_cmd))
194 # For now we don't track (DY)LD_LIBRARY_PATH, so the old
195 # library will be in the modules list.
196 self.expect("target modules list",
197 substrs=[os.path.basename(old_dylib)],
200 lldbutil.run_break_set_by_file_and_line(
201 self, "d.cpp", self.line_d_function, num_expected_locations=1)
202 # After run, make sure the non-hidden library is picked up.
203 self.expect("run", substrs=["return", "700"])
205 self.runCmd("continue")
207 # Add the hidden directory first in the search path.
208 env_cmd_string = ("settings set target.env-vars %s=%s" %
209 (self.dylibPath, new_dir))
210 if not self.platformIsDarwin():
211 env_cmd_string += ":" + wd
212 self.runCmd(env_cmd_string)
214 # This time, the hidden library should be picked up.
215 self.expect("run", substrs=["return", "12345"])
218 bugnumber="llvm.org/pr25805",
219 hostoslist=["windows"],
221 @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
222 @skipIfWindows # Windows doesn't have dlopen and friends, dynamic libraries work differently
223 def test_lldb_process_load_and_unload_commands(self):
224 """Test that lldb process load/unload command work correctly."""
225 self.copy_shlibs_to_remote()
227 exe = self.getBuildArtifact("a.out")
228 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
230 # Break at main.cpp before the call to dlopen().
231 # Use lldb's process load command to load the dylib, instead.
233 lldbutil.run_break_set_by_file_and_line(
234 self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
236 self.runCmd("run", RUN_SUCCEEDED)
238 ctx = self.platformContext
239 dylibName = ctx.shlib_prefix + 'loadunload_a.' + ctx.shlib_extension
240 localDylibPath = self.getBuildArtifact(dylibName)
241 if lldb.remote_platform:
242 wd = lldb.remote_platform.GetWorkingDirectory()
243 remoteDylibPath = lldbutil.join_remote_paths(wd, dylibName)
245 remoteDylibPath = localDylibPath
247 # Make sure that a_function does not exist at this point.
249 "image lookup -n a_function",
250 "a_function should not exist yet",
253 patterns=["1 match found"])
255 # Use lldb 'process load' to load the dylib.
257 "process load %s --install=%s" % (localDylibPath, remoteDylibPath),
258 "%s loaded correctly" % dylibName,
260 'Loading "%s".*ok' % localDylibPath,
261 'Image [0-9]+ loaded'])
263 # Search for and match the "Image ([0-9]+) loaded" pattern.
264 output = self.res.GetOutput()
265 pattern = re.compile("Image ([0-9]+) loaded")
266 for l in output.split(os.linesep):
268 match = pattern.search(l)
271 index = match.group(1)
273 # Now we should have an entry for a_function.
275 "image lookup -n a_function",
276 "a_function should now exist",
278 "1 match found .*%s" %
281 # Use lldb 'process unload' to unload the dylib.
283 "process unload %s" %
285 "%s unloaded correctly" %
288 "Unloading .* with index %s.*ok" %
291 self.runCmd("process continue")
293 @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
294 def test_load_unload(self):
295 """Test breakpoint by name works correctly with dlopen'ing."""
296 self.copy_shlibs_to_remote()
298 exe = self.getBuildArtifact("a.out")
299 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
301 # Break by function name a_function (not yet loaded).
302 lldbutil.run_break_set_by_symbol(
303 self, "a_function", num_expected_locations=0)
305 self.runCmd("run", RUN_SUCCEEDED)
307 # The stop reason of the thread should be breakpoint and at a_function.
308 self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
311 'stop reason = breakpoint'])
313 # The breakpoint should have a hit count of 1.
314 self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
315 substrs=[' resolved, hit count = 1'])
317 # Issue the 'contnue' command. We should stop agaian at a_function.
318 # The stop reason of the thread should be breakpoint and at a_function.
319 self.runCmd("continue")
321 # rdar://problem/8508987
322 # The a_function breakpoint should be encountered twice.
323 self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
326 'stop reason = breakpoint'])
328 # The breakpoint should have a hit count of 2.
329 self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
330 substrs=[' resolved, hit count = 2'])
332 @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
333 @skipIfWindows # Windows doesn't have dlopen and friends, dynamic libraries work differently
334 def test_step_over_load(self):
335 """Test stepping over code that loads a shared library works correctly."""
336 self.copy_shlibs_to_remote()
338 exe = self.getBuildArtifact("a.out")
339 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
341 # Break by function name a_function (not yet loaded).
342 lldbutil.run_break_set_by_file_and_line(
343 self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
345 self.runCmd("run", RUN_SUCCEEDED)
347 # The stop reason of the thread should be breakpoint and at a_function.
348 self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
350 'stop reason = breakpoint'])
354 "Stepping over function that loads library")
356 # The stop reason should be step end.
357 self.expect("thread list", "step over succeeded.",
359 'stop reason = step over'])
361 # We can't find a breakpoint location for d_init before launching because
362 # executable dependencies are resolved relative to the debuggers PWD. Bug?
363 @expectedFailureAll(oslist=["linux"])
364 @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
365 @skipIfWindows # Windows doesn't have dlopen and friends, dynamic libraries work differently
366 def test_static_init_during_load(self):
367 """Test that we can set breakpoints correctly in static initializers"""
368 self.copy_shlibs_to_remote()
370 exe = self.getBuildArtifact("a.out")
371 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
373 a_init_bp_num = lldbutil.run_break_set_by_symbol(
374 self, "a_init", num_expected_locations=0)
375 b_init_bp_num = lldbutil.run_break_set_by_symbol(
376 self, "b_init", num_expected_locations=0)
377 d_init_bp_num = lldbutil.run_break_set_by_symbol(
378 self, "d_init", num_expected_locations=1)
380 self.runCmd("run", RUN_SUCCEEDED)
382 self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
385 'stop reason = breakpoint %d' % d_init_bp_num])
387 self.runCmd("continue")
388 self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
391 'stop reason = breakpoint %d' % b_init_bp_num])
392 self.expect("thread backtrace",
397 self.runCmd("continue")
398 self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
401 'stop reason = breakpoint %d' % a_init_bp_num])
402 self.expect("thread backtrace",