TestLoadUnload.py revision abb3302051246273eb92cca203c9a1b9d9736e05
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 *
10
11class LoadUnloadTestCase(TestBase):
12
13    mydir = os.path.join("functionalities", "load_unload")
14
15    def setUp(self):
16        # Call super's setUp().
17        TestBase.setUp(self)
18        # Find the line number to break for main.cpp.
19        self.line = line_number('main.c',
20                                '// Set break point at this line for test_lldb_process_load_and_unload_commands().')
21        self.line_d_function = line_number('d.c',
22                                           '// Find this line number within d_dunction().')
23
24    @unittest2.expectedFailure
25    def test_modules_search_paths(self):
26        """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'."""
27
28        # Invoke the default build rule.
29        self.buildDefault()
30
31        if sys.platform.startswith("darwin"):
32            dylibName = 'libd.dylib'
33
34        # The directory with the the dynamic library we did not link to.
35        new_dir = os.path.join(os.getcwd(), "hidden")
36
37        old_dylib = os.path.join(os.getcwd(), dylibName)
38        new_dylib = os.path.join(new_dir, dylibName)
39
40        exe = os.path.join(os.getcwd(), "a.out")
41        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
42
43        self.expect("target modules list",
44            substrs = [old_dylib])
45        self.expect("target modules list -t 3",
46            patterns = ["%s-[^-]*-[^-]*" % self.getArchitecture()])
47        self.runCmd("target modules search-paths add %s %s" % (os.getcwd(), new_dir))
48
49        self.expect("target modules search-paths list",
50            substrs = [os.getcwd(), new_dir])
51
52        # Add teardown hook to clear image-search-paths after the test.
53        self.addTearDownHook(lambda: self.runCmd("target modules search-paths clear"))
54        self.expect("target modules list", "LLDB successfully locates the relocated dynamic library",
55            substrs = [new_dylib])
56
57
58    def test_dyld_library_path(self):
59        """Test DYLD_LIBRARY_PATH after moving libd.dylib, which defines d_function, somewhere else."""
60
61        # Invoke the default build rule.
62        self.buildDefault()
63
64        exe = os.path.join(os.getcwd(), "a.out")
65        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
66
67        if sys.platform.startswith("darwin"):
68            dylibName = 'libd.dylib'
69            dsymName = 'libd.dylib.dSYM'
70            dylibPath = 'DYLD_LIBRARY_PATH'
71
72        # The directory to relocate the dynamic library and its debugging info.
73        new_dir = os.path.join(os.getcwd(), "hidden")
74
75        old_dylib = os.path.join(os.getcwd(), dylibName)
76        new_dylib = os.path.join(new_dir, dylibName)
77        old_dSYM = os.path.join(os.getcwd(), dsymName)
78        new_dSYM = os.path.join(new_dir, dsymName)
79
80        #system(["ls", "-lR", "."])
81
82        # Try running with the DYLD_LIBRARY_PATH environment variable set, make sure
83        # we pick up the hidden dylib.
84
85        env_cmd_string = "settings set target.env-vars " + dylibPath + "=" + new_dir
86        if self.TraceOn():
87            print "Set environment to: ", env_cmd_string
88        self.runCmd(env_cmd_string)
89        self.runCmd("settings show target.env-vars")
90
91        remove_dyld_path_cmd = "settings remove target.env-vars " + dylibPath
92        self.addTearDownHook(lambda: self.runCmd(remove_dyld_path_cmd))
93
94        self.expect("breakpoint set -f d.c -l %d" % self.line_d_function,
95                    BREAKPOINT_CREATED,
96                    startstr = "Breakpoint created: 1: file ='d.c', line = %d" %
97                        self.line_d_function)
98        # For now we don't track DYLD_LIBRARY_PATH, so the old library will be in
99        # the modules list.
100        self.expect("target modules list",
101            substrs = [old_dylib],
102            matching=True)
103
104        self.runCmd("run")
105        self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
106            patterns = ["frame #0.*d_function.*at d.c:%d" % self.line_d_function])
107
108        # After run, make sure the hidden library is present, and the one we didn't
109        # load is not.
110        self.expect("target modules list",
111            substrs = [new_dylib])
112        self.expect("target modules list",
113            substrs = [old_dylib],
114            matching=False)
115
116    def test_lldb_process_load_and_unload_commands(self):
117        """Test that lldb process load/unload command work correctly."""
118
119        # Invoke the default build rule.
120        self.buildDefault()
121
122        exe = os.path.join(os.getcwd(), "a.out")
123        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
124
125        # Break at main.c before the call to dlopen().
126        # Use lldb's process load command to load the dylib, instead.
127
128        self.expect("breakpoint set -f main.c -l %d" % self.line,
129                    BREAKPOINT_CREATED,
130            startstr = "Breakpoint created: 1: file ='main.c', line = %d" %
131                        self.line)
132
133        self.runCmd("run", RUN_SUCCEEDED)
134
135        # Make sure that a_function does not exist at this point.
136        self.expect("image lookup -n a_function", "a_function should not exist yet",
137                    error=True, matching=False,
138            patterns = ["1 match found .* %s" % self.mydir])
139
140        # Use lldb 'process load' to load the dylib.
141        self.expect("process load liba.dylib", "liba.dylib loaded correctly",
142            patterns = ['Loading "liba.dylib".*ok',
143                        'Image [0-9]+ loaded'])
144
145        # Search for and match the "Image ([0-9]+) loaded" pattern.
146        output = self.res.GetOutput()
147        pattern = re.compile("Image ([0-9]+) loaded")
148        for l in output.split(os.linesep):
149            #print "l:", l
150            match = pattern.search(l)
151            if match:
152                break
153        index = match.group(1)
154
155        # Now we should have an entry for a_function.
156        self.expect("image lookup -n a_function", "a_function should now exist",
157            patterns = ["1 match found .*%s" % self.mydir])
158
159        # Use lldb 'process unload' to unload the dylib.
160        self.expect("process unload %s" % index, "liba.dylib unloaded correctly",
161            patterns = ["Unloading .* with index %s.*ok" % index])
162
163        self.runCmd("process continue")
164
165    def test_load_unload(self):
166        """Test breakpoint by name works correctly with dlopen'ing."""
167
168        # Invoke the default build rule.
169        self.buildDefault()
170
171        exe = os.path.join(os.getcwd(), "a.out")
172        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
173
174        # Break by function name a_function (not yet loaded).
175        self.expect("breakpoint set -n a_function", BREAKPOINT_CREATED,
176            startstr = "Breakpoint created: 1: name = 'a_function', locations = 0 (pending)")
177
178        self.runCmd("run", RUN_SUCCEEDED)
179
180        # The stop reason of the thread should be breakpoint and at a_function.
181        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
182            substrs = ['stopped',
183                       'a_function',
184                       'stop reason = breakpoint'])
185
186        # The breakpoint should have a hit count of 1.
187        self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
188            substrs = [' resolved, hit count = 1'])
189
190        # Issue the 'contnue' command.  We should stop agaian at a_function.
191        # The stop reason of the thread should be breakpoint and at a_function.
192        self.runCmd("continue")
193
194        # rdar://problem/8508987
195        # The a_function breakpoint should be encountered twice.
196        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
197            substrs = ['stopped',
198                       'a_function',
199                       'stop reason = breakpoint'])
200
201        # The breakpoint should have a hit count of 2.
202        self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
203            substrs = [' resolved, hit count = 2'])
204
205
206if __name__ == '__main__':
207    import atexit
208    lldb.SBDebugger.Initialize()
209    atexit.register(lambda: lldb.SBDebugger.Terminate())
210    unittest2.main()
211