• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""
2Test that breakpoint by symbol name works correctly with dynamic libs.
3"""
4
5import os, time
6import re
7import unittest2
8import lldb
9from lldbtest import *
10import lldbutil
11
12class LoadUnloadTestCase(TestBase):
13
14    def getCategories (self):
15        return ['basic_process']
16
17    mydir = os.path.join("functionalities", "load_unload")
18
19    def setUp(self):
20        # Call super's setUp().
21        TestBase.setUp(self)
22        # Find the line number to break for main.cpp.
23        self.line = line_number('main.c',
24                                '// Set break point at this line for test_lldb_process_load_and_unload_commands().')
25        self.line_d_function = line_number('d.c',
26                                           '// Find this line number within d_dunction().')
27
28    @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
29    @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
30    def test_modules_search_paths(self):
31        """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'."""
32
33        # Invoke the default build rule.
34        self.buildDefault()
35
36        if sys.platform.startswith("darwin"):
37            dylibName = 'libd.dylib'
38
39        # The directory with the dynamic library we did not link to.
40        new_dir = os.path.join(os.getcwd(), "hidden")
41
42        old_dylib = os.path.join(os.getcwd(), dylibName)
43        new_dylib = os.path.join(new_dir, dylibName)
44
45        exe = os.path.join(os.getcwd(), "a.out")
46        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
47
48        self.expect("target modules list",
49            substrs = [old_dylib])
50        #self.expect("target modules list -t 3",
51        #    patterns = ["%s-[^-]*-[^-]*" % self.getArchitecture()])
52        # Add an image search path substitution pair.
53        self.runCmd("target modules search-paths add %s %s" % (os.getcwd(), new_dir))
54        # Add teardown hook to clear image-search-paths after the test.
55        # rdar://problem/10501020
56        # Uncomment the following to reproduce 10501020.
57        self.addTearDownHook(lambda: self.runCmd("target modules search-paths clear"))
58
59        self.expect("target modules search-paths list",
60            substrs = [os.getcwd(), new_dir])
61
62        self.expect("target modules search-paths query %s" % os.getcwd(), "Image search path successfully transformed",
63            substrs = [new_dir])
64
65        # Obliterate traces of libd from the old location.
66        os.remove(old_dylib)
67        # Inform dyld of the new path, too.
68        env_cmd_string = "settings set target.env-vars " + self.dylibPath + "=" + new_dir
69        if self.TraceOn():
70            print "Set environment to: ", env_cmd_string
71        self.runCmd(env_cmd_string)
72        self.runCmd("settings show target.env-vars")
73
74        remove_dyld_path_cmd = "settings remove target.env-vars " + self.dylibPath
75        self.addTearDownHook(lambda: self.runCmd(remove_dyld_path_cmd))
76
77        self.runCmd("run")
78
79        self.expect("target modules list", "LLDB successfully locates the relocated dynamic library",
80            substrs = [new_dylib])
81
82    @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
83    @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
84    def test_dyld_library_path(self):
85        """Test DYLD_LIBRARY_PATH after moving libd.dylib, which defines d_function, somewhere else."""
86
87        # Invoke the default build rule.
88        self.buildDefault()
89
90        exe = os.path.join(os.getcwd(), "a.out")
91        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
92
93        if sys.platform.startswith("darwin"):
94            dylibName = 'libd.dylib'
95            dsymName = 'libd.dylib.dSYM'
96
97        # The directory to relocate the dynamic library and its debugging info.
98        special_dir = "hidden"
99        new_dir = os.path.join(os.getcwd(), special_dir)
100
101        old_dylib = os.path.join(os.getcwd(), dylibName)
102        new_dylib = os.path.join(new_dir, dylibName)
103        old_dSYM = os.path.join(os.getcwd(), dsymName)
104        new_dSYM = os.path.join(new_dir, dsymName)
105
106        #system(["ls", "-lR", "."])
107
108        # Try running with the DYLD_LIBRARY_PATH environment variable set, make sure
109        # we pick up the hidden dylib.
110
111        env_cmd_string = "settings set target.env-vars " + self.dylibPath + "=" + new_dir
112        if self.TraceOn():
113            print "Set environment to: ", env_cmd_string
114        self.runCmd(env_cmd_string)
115        self.runCmd("settings show target.env-vars")
116
117        remove_dyld_path_cmd = "settings remove target.env-vars " + self.dylibPath
118        self.addTearDownHook(lambda: self.runCmd(remove_dyld_path_cmd))
119
120        lldbutil.run_break_set_by_file_and_line (self, "d.c", self.line_d_function, num_expected_locations=1, loc_exact=True)
121
122        # For now we don't track DYLD_LIBRARY_PATH, so the old library will be in
123        # the modules list.
124        self.expect("target modules list",
125            substrs = [os.path.basename(old_dylib)],
126            matching=True)
127
128        self.runCmd("run")
129        self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
130            patterns = ["frame #0.*d_function.*at d.c:%d" % self.line_d_function])
131
132        # After run, make sure the hidden library is present, and the one we didn't
133        # load is not.
134        self.expect("target modules list",
135            substrs = [special_dir, os.path.basename(new_dylib)])
136
137    @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
138    @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
139    def test_lldb_process_load_and_unload_commands(self):
140        """Test that lldb process load/unload command work correctly."""
141
142        # Invoke the default build rule.
143        self.buildDefault()
144
145        exe = os.path.join(os.getcwd(), "a.out")
146        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
147
148        # Break at main.c before the call to dlopen().
149        # Use lldb's process load command to load the dylib, instead.
150
151        lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
152
153        self.runCmd("run", RUN_SUCCEEDED)
154
155        # Make sure that a_function does not exist at this point.
156        self.expect("image lookup -n a_function", "a_function should not exist yet",
157                    error=True, matching=False,
158            patterns = ["1 match found .* %s" % self.mydir])
159
160        # Use lldb 'process load' to load the dylib.
161        self.expect("process load liba.dylib", "liba.dylib loaded correctly",
162            patterns = ['Loading "liba.dylib".*ok',
163                        'Image [0-9]+ loaded'])
164
165        # Search for and match the "Image ([0-9]+) loaded" pattern.
166        output = self.res.GetOutput()
167        pattern = re.compile("Image ([0-9]+) loaded")
168        for l in output.split(os.linesep):
169            #print "l:", l
170            match = pattern.search(l)
171            if match:
172                break
173        index = match.group(1)
174
175        # Now we should have an entry for a_function.
176        self.expect("image lookup -n a_function", "a_function should now exist",
177            patterns = ["1 match found .*%s" % self.mydir])
178
179        # Use lldb 'process unload' to unload the dylib.
180        self.expect("process unload %s" % index, "liba.dylib unloaded correctly",
181            patterns = ["Unloading .* with index %s.*ok" % index])
182
183        self.runCmd("process continue")
184
185    @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
186    @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
187    def test_load_unload(self):
188        """Test breakpoint by name works correctly with dlopen'ing."""
189
190        # Invoke the default build rule.
191        self.buildDefault()
192
193        exe = os.path.join(os.getcwd(), "a.out")
194        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
195
196        # Break by function name a_function (not yet loaded).
197        lldbutil.run_break_set_by_symbol (self, "a_function", num_expected_locations=0)
198
199        self.runCmd("run", RUN_SUCCEEDED)
200
201        # The stop reason of the thread should be breakpoint and at a_function.
202        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
203            substrs = ['stopped',
204                       'a_function',
205                       'stop reason = breakpoint'])
206
207        # The breakpoint should have a hit count of 1.
208        self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
209            substrs = [' resolved, hit count = 1'])
210
211        # Issue the 'contnue' command.  We should stop agaian at a_function.
212        # The stop reason of the thread should be breakpoint and at a_function.
213        self.runCmd("continue")
214
215        # rdar://problem/8508987
216        # The a_function breakpoint should be encountered twice.
217        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
218            substrs = ['stopped',
219                       'a_function',
220                       'stop reason = breakpoint'])
221
222        # The breakpoint should have a hit count of 2.
223        self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
224            substrs = [' resolved, hit count = 2'])
225
226    @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support
227    @skipIfLinux # llvm.org/pr14424 - missing linux Makefiles/testcase support
228    def test_step_over_load (self):
229        """Test stepping over code that loads a shared library works correctly."""
230
231        # Invoke the default build rule.
232        self.buildDefault()
233
234        exe = os.path.join(os.getcwd(), "a.out")
235        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
236
237        # Break by function name a_function (not yet loaded).
238        lldbutil.run_break_set_by_file_and_line (self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
239
240        self.runCmd("run", RUN_SUCCEEDED)
241
242        # The stop reason of the thread should be breakpoint and at a_function.
243        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
244            substrs = ['stopped',
245                       'stop reason = breakpoint'])
246
247        self.runCmd("thread step-over", "Stepping over function that loads library")
248
249        # The stop reason should be step end.
250        self.expect("thread list", "step over succeeded.",
251            substrs = ['stopped',
252                      'stop reason = step over'])
253
254if __name__ == '__main__':
255    import atexit
256    lldb.SBDebugger.Initialize()
257    atexit.register(lambda: lldb.SBDebugger.Terminate())
258    unittest2.main()
259