1 """ 2 Test SBTarget APIs. 3 """ 4 5 import os, time 6 import re 7 import unittest2 8 import lldb, lldbutil 9 from lldbtest import * 10 11 class TargetAPITestCase(TestBase): 12 13 mydir = os.path.join("python_api", "target") 14 15 @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") 16 @python_api_test 17 @dsym_test 18 def test_find_global_variables_with_dsym(self): 19 """Exercise SBTaget.FindGlobalVariables() API.""" 20 d = {'EXE': 'a.out'} 21 self.buildDsym(dictionary=d) 22 self.setTearDownCleanup(dictionary=d) 23 self.find_global_variables('a.out') 24 25 #rdar://problem/9700873 26 # Find global variable value fails for dwarf if inferior not started 27 # (Was CrashTracer: [USER] 1 crash in Python at _lldb.so: lldb_private::MemoryCache::Read + 94) 28 # 29 # It does not segfaults now. But for dwarf, the variable value is None if 30 # the inferior process does not exist yet. The radar has been updated. 31 #@unittest232.skip("segmentation fault -- skipping") 32 @python_api_test 33 @dwarf_test 34 def test_find_global_variables_with_dwarf(self): 35 """Exercise SBTarget.FindGlobalVariables() API.""" 36 d = {'EXE': 'b.out'} 37 self.buildDwarf(dictionary=d) 38 self.setTearDownCleanup(dictionary=d) 39 self.find_global_variables('b.out') 40 41 @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") 42 @python_api_test 43 @dsym_test 44 def test_find_functions_with_dsym(self): 45 """Exercise SBTaget.FindFunctions() API.""" 46 d = {'EXE': 'a.out'} 47 self.buildDsym(dictionary=d) 48 self.setTearDownCleanup(dictionary=d) 49 self.find_functions('a.out') 50 51 @python_api_test 52 @dwarf_test 53 def test_find_functions_with_dwarf(self): 54 """Exercise SBTarget.FindFunctions() API.""" 55 d = {'EXE': 'b.out'} 56 self.buildDwarf(dictionary=d) 57 self.setTearDownCleanup(dictionary=d) 58 self.find_functions('b.out') 59 60 @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") 61 @python_api_test 62 @dsym_test 63 def test_get_description_with_dsym(self): 64 """Exercise SBTaget.GetDescription() API.""" 65 self.buildDsym() 66 self.get_description() 67 68 @python_api_test 69 @dwarf_test 70 def test_get_description_with_dwarf(self): 71 """Exercise SBTarget.GetDescription() API.""" 72 self.buildDwarf() 73 self.get_description() 74 75 @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") 76 @python_api_test 77 @dsym_test 78 def test_launch_new_process_and_redirect_stdout_with_dsym(self): 79 """Exercise SBTaget.Launch() API.""" 80 self.buildDsym() 81 self.launch_new_process_and_redirect_stdout() 82 83 @python_api_test 84 @dwarf_test 85 def test_launch_new_process_and_redirect_stdout_with_dwarf(self): 86 """Exercise SBTarget.Launch() API.""" 87 self.buildDwarf() 88 self.launch_new_process_and_redirect_stdout() 89 90 @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") 91 @python_api_test 92 @dsym_test 93 def test_resolve_symbol_context_with_address_with_dsym(self): 94 """Exercise SBTaget.ResolveSymbolContextForAddress() API.""" 95 self.buildDsym() 96 self.resolve_symbol_context_with_address() 97 98 @python_api_test 99 @dwarf_test 100 def test_resolve_symbol_context_with_address_with_dwarf(self): 101 """Exercise SBTarget.ResolveSymbolContextForAddress() API.""" 102 self.buildDwarf() 103 self.resolve_symbol_context_with_address() 104 105 def setUp(self): 106 # Call super's setUp(). 107 TestBase.setUp(self) 108 # Find the line number to of function 'c'. 109 self.line1 = line_number('main.c', '// Find the line number for breakpoint 1 here.') 110 self.line2 = line_number('main.c', '// Find the line number for breakpoint 2 here.') 111 112 def find_global_variables(self, exe_name): 113 """Exercise SBTaget.FindGlobalVariables() API.""" 114 exe = os.path.join(os.getcwd(), exe_name) 115 116 # Create a target by the debugger. 117 target = self.dbg.CreateTarget(exe) 118 self.assertTrue(target, VALID_TARGET) 119 120 #rdar://problem/9700873 121 # Find global variable value fails for dwarf if inferior not started 122 # (Was CrashTracer: [USER] 1 crash in Python at _lldb.so: lldb_private::MemoryCache::Read + 94) 123 # 124 # Remove the lines to create a breakpoint and to start the inferior 125 # which are workarounds for the dwarf case. 126 127 breakpoint = target.BreakpointCreateByLocation('main.c', self.line1) 128 self.assertTrue(breakpoint, VALID_BREAKPOINT) 129 130 # Now launch the process, and do not stop at entry point. 131 process = target.LaunchSimple(None, None, os.getcwd()) 132 self.assertTrue(process, PROCESS_IS_VALID) 133 # Make sure we hit our breakpoint: 134 thread_list = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint) 135 self.assertTrue (len(thread_list) == 1) 136 137 value_list = target.FindGlobalVariables('my_global_var_of_char_type', 3) 138 self.assertTrue(value_list.GetSize() == 1) 139 my_global_var = value_list.GetValueAtIndex(0) 140 self.DebugSBValue(my_global_var) 141 self.assertTrue(my_global_var) 142 self.expect(my_global_var.GetName(), exe=False, 143 startstr = "my_global_var_of_char_type") 144 self.expect(my_global_var.GetTypeName(), exe=False, 145 startstr = "char") 146 self.expect(my_global_var.GetValue(), exe=False, 147 startstr = "'X'") 148 149 # While we are at it, let's also exercise the similar SBModule.FindGlobalVariables() API. 150 for m in target.module_iter(): 151 if m.GetFileSpec().GetDirectory() == os.getcwd() and m.GetFileSpec().GetFilename() == exe_name: 152 value_list = m.FindGlobalVariables(target, 'my_global_var_of_char_type', 3) 153 self.assertTrue(value_list.GetSize() == 1) 154 self.assertTrue(value_list.GetValueAtIndex(0).GetValue() == "'X'") 155 break 156 157 def find_functions(self, exe_name): 158 """Exercise SBTaget.FindFunctions() API.""" 159 exe = os.path.join(os.getcwd(), exe_name) 160 161 # Create a target by the debugger. 162 target = self.dbg.CreateTarget(exe) 163 self.assertTrue(target, VALID_TARGET) 164 165 list = target.FindFunctions('c', lldb.eFunctionNameTypeAuto) 166 self.assertTrue(list.GetSize() == 1) 167 168 for sc in list: 169 self.assertTrue(sc.GetModule().GetFileSpec().GetFilename() == exe_name) 170 self.assertTrue(sc.GetSymbol().GetName() == 'c') 171 172 def get_description(self): 173 """Exercise SBTaget.GetDescription() API.""" 174 exe = os.path.join(os.getcwd(), "a.out") 175 176 # Create a target by the debugger. 177 target = self.dbg.CreateTarget(exe) 178 self.assertTrue(target, VALID_TARGET) 179 180 from lldbutil import get_description 181 182 # get_description() allows no option to mean lldb.eDescriptionLevelBrief. 183 desc = get_description(target) 184 #desc = get_description(target, option=lldb.eDescriptionLevelBrief) 185 if not desc: 186 self.fail("SBTarget.GetDescription() failed") 187 self.expect(desc, exe=False, 188 substrs = ['a.out']) 189 self.expect(desc, exe=False, matching=False, 190 substrs = ['Target', 'Module', 'Breakpoint']) 191 192 desc = get_description(target, option=lldb.eDescriptionLevelFull) 193 if not desc: 194 self.fail("SBTarget.GetDescription() failed") 195 self.expect(desc, exe=False, 196 substrs = ['a.out', 'Target', 'Module', 'Breakpoint']) 197 198 199 def launch_new_process_and_redirect_stdout(self): 200 """Exercise SBTaget.Launch() API with redirected stdout.""" 201 exe = os.path.join(os.getcwd(), "a.out") 202 203 # Create a target by the debugger. 204 target = self.dbg.CreateTarget(exe) 205 self.assertTrue(target, VALID_TARGET) 206 207 # Add an extra twist of stopping the inferior in a breakpoint, and then continue till it's done. 208 # We should still see the entire stdout redirected once the process is finished. 209 line = line_number('main.c', '// a(3) -> c(3)') 210 breakpoint = target.BreakpointCreateByLocation('main.c', line) 211 212 # Now launch the process, do not stop at entry point, and redirect stdout to "stdout.txt" file. 213 # The inferior should run to completion after "process.Continue()" call. 214 error = lldb.SBError() 215 process = target.Launch (self.dbg.GetListener(), None, None, None, "stdout.txt", None, None, 0, False, error) 216 process.Continue() 217 #self.runCmd("process status") 218 219 # The 'stdout.txt' file should now exist. 220 self.assertTrue(os.path.isfile("stdout.txt"), 221 "'stdout.txt' exists due to redirected stdout via SBTarget.Launch() API.") 222 223 # Read the output file produced by running the program. 224 with open('stdout.txt', 'r') as f: 225 output = f.read() 226 227 # Let's delete the 'stdout.txt' file as a cleanup step. 228 try: 229 os.remove("stdout.txt") 230 pass 231 except OSError: 232 pass 233 234 self.expect(output, exe=False, 235 substrs = ["a(1)", "b(2)", "a(3)"]) 236 237 238 def resolve_symbol_context_with_address(self): 239 """Exercise SBTaget.ResolveSymbolContextForAddress() API.""" 240 exe = os.path.join(os.getcwd(), "a.out") 241 242 # Create a target by the debugger. 243 target = self.dbg.CreateTarget(exe) 244 self.assertTrue(target, VALID_TARGET) 245 246 # Now create the two breakpoints inside function 'a'. 247 breakpoint1 = target.BreakpointCreateByLocation('main.c', self.line1) 248 breakpoint2 = target.BreakpointCreateByLocation('main.c', self.line2) 249 #print "breakpoint1:", breakpoint1 250 #print "breakpoint2:", breakpoint2 251 self.assertTrue(breakpoint1 and 252 breakpoint1.GetNumLocations() == 1, 253 VALID_BREAKPOINT) 254 self.assertTrue(breakpoint2 and 255 breakpoint2.GetNumLocations() == 1, 256 VALID_BREAKPOINT) 257 258 # Now launch the process, and do not stop at entry point. 259 process = target.LaunchSimple(None, None, os.getcwd()) 260 self.assertTrue(process, PROCESS_IS_VALID) 261 262 # Frame #0 should be on self.line1. 263 self.assertTrue(process.GetState() == lldb.eStateStopped) 264 thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) 265 self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition") 266 #self.runCmd("process status") 267 frame0 = thread.GetFrameAtIndex(0) 268 lineEntry = frame0.GetLineEntry() 269 self.assertTrue(lineEntry.GetLine() == self.line1) 270 271 address1 = lineEntry.GetStartAddress() 272 273 # Continue the inferior, the breakpoint 2 should be hit. 274 process.Continue() 275 self.assertTrue(process.GetState() == lldb.eStateStopped) 276 thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) 277 self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition") 278 #self.runCmd("process status") 279 frame0 = thread.GetFrameAtIndex(0) 280 lineEntry = frame0.GetLineEntry() 281 self.assertTrue(lineEntry.GetLine() == self.line2) 282 283 address2 = lineEntry.GetStartAddress() 284 285 #print "address1:", address1 286 #print "address2:", address2 287 288 # Now call SBTarget.ResolveSymbolContextForAddress() with the addresses from our line entry. 289 context1 = target.ResolveSymbolContextForAddress(address1, lldb.eSymbolContextEverything) 290 context2 = target.ResolveSymbolContextForAddress(address2, lldb.eSymbolContextEverything) 291 292 self.assertTrue(context1 and context2) 293 #print "context1:", context1 294 #print "context2:", context2 295 296 # Verify that the context point to the same function 'a'. 297 symbol1 = context1.GetSymbol() 298 symbol2 = context2.GetSymbol() 299 self.assertTrue(symbol1 and symbol2) 300 #print "symbol1:", symbol1 301 #print "symbol2:", symbol2 302 303 from lldbutil import get_description 304 desc1 = get_description(symbol1) 305 desc2 = get_description(symbol2) 306 self.assertTrue(desc1 and desc2 and desc1 == desc2, 307 "The two addresses should resolve to the same symbol") 308 309 310 if __name__ == '__main__': 311 import atexit 312 lldb.SBDebugger.Initialize() 313 atexit.register(lambda: lldb.SBDebugger.Terminate()) 314 unittest2.main() 315