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