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