1""" 2Test SBProcess APIs, including ReadMemory(), WriteMemory(), and others. 3""" 4 5import os, time 6import unittest2 7import lldb 8from lldbutil import get_stopped_thread, state_type_to_str 9from lldbtest import * 10 11class ProcessAPITestCase(TestBase): 12 13 mydir = os.path.join("python_api", "process") 14 15 @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") 16 @python_api_test 17 @dsym_test 18 def test_read_memory_with_dsym(self): 19 """Test Python SBProcess.ReadMemory() API.""" 20 self.buildDsym() 21 self.read_memory() 22 23 @python_api_test 24 @dwarf_test 25 def test_read_memory_with_dwarf(self): 26 """Test Python SBProcess.ReadMemory() API.""" 27 self.buildDwarf() 28 self.read_memory() 29 30 @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") 31 @python_api_test 32 @dsym_test 33 def test_write_memory_with_dsym(self): 34 """Test Python SBProcess.WriteMemory() API.""" 35 self.buildDsym() 36 self.write_memory() 37 38 @python_api_test 39 @dwarf_test 40 def test_write_memory_with_dwarf(self): 41 """Test Python SBProcess.WriteMemory() API.""" 42 self.buildDwarf() 43 self.write_memory() 44 45 @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") 46 @python_api_test 47 @dsym_test 48 def test_access_my_int_with_dsym(self): 49 """Test access 'my_int' using Python SBProcess.GetByteOrder() and other APIs.""" 50 self.buildDsym() 51 self.access_my_int() 52 53 @python_api_test 54 @dwarf_test 55 def test_access_my_int_with_dwarf(self): 56 """Test access 'my_int' using Python SBProcess.GetByteOrder() and other APIs.""" 57 self.buildDwarf() 58 self.access_my_int() 59 60 @python_api_test 61 def test_remote_launch(self): 62 """Test SBProcess.RemoteLaunch() API with a process not in eStateConnected, and it should fail.""" 63 self.buildDefault() 64 self.remote_launch_should_fail() 65 66 @python_api_test 67 def test_get_num_supported_hardware_watchpoints(self): 68 """Test SBProcess.GetNumSupportedHardwareWatchpoints() API with a process.""" 69 self.buildDefault() 70 self.get_num_supported_hardware_watchpoints() 71 72 def setUp(self): 73 # Call super's setUp(). 74 TestBase.setUp(self) 75 # Find the line number to break inside main(). 76 self.line = line_number("main.cpp", "// Set break point at this line and check variable 'my_char'.") 77 78 def read_memory(self): 79 """Test Python SBProcess.ReadMemory() API.""" 80 exe = os.path.join(os.getcwd(), "a.out") 81 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 82 83 target = self.dbg.CreateTarget(exe) 84 self.assertTrue(target, VALID_TARGET) 85 86 breakpoint = target.BreakpointCreateByLocation("main.cpp", self.line) 87 self.assertTrue(breakpoint, VALID_BREAKPOINT) 88 89 # Launch the process, and do not stop at the entry point. 90 process = target.LaunchSimple(None, None, os.getcwd()) 91 92 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 93 self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint") 94 frame = thread.GetFrameAtIndex(0) 95 96 # Get the SBValue for the global variable 'my_char'. 97 val = frame.FindValue("my_char", lldb.eValueTypeVariableGlobal) 98 self.DebugSBValue(val) 99 100 # Due to the typemap magic (see lldb.swig), we pass in 1 to ReadMemory and 101 # expect to get a Python string as the result object! 102 error = lldb.SBError() 103 self.assertFalse(val.TypeIsPointerType()) 104 content = process.ReadMemory(val.AddressOf().GetValueAsUnsigned(), 1, error) 105 if not error.Success(): 106 self.fail("SBProcess.ReadMemory() failed") 107 if self.TraceOn(): 108 print "memory content:", content 109 110 self.expect(content, "Result from SBProcess.ReadMemory() matches our expected output: 'x'", 111 exe=False, 112 startstr = 'x') 113 114 # Read (char *)my_char_ptr. 115 val = frame.FindValue("my_char_ptr", lldb.eValueTypeVariableGlobal) 116 self.DebugSBValue(val) 117 cstring = process.ReadCStringFromMemory(val.GetValueAsUnsigned(), 256, error) 118 if not error.Success(): 119 self.fail("SBProcess.ReadCStringFromMemory() failed") 120 if self.TraceOn(): 121 print "cstring read is:", cstring 122 123 self.expect(cstring, "Result from SBProcess.ReadCStringFromMemory() matches our expected output", 124 exe=False, 125 startstr = 'Does it work?') 126 127 # Get the SBValue for the global variable 'my_cstring'. 128 val = frame.FindValue("my_cstring", lldb.eValueTypeVariableGlobal) 129 self.DebugSBValue(val) 130 131 # Due to the typemap magic (see lldb.swig), we pass in 256 to read at most 256 bytes 132 # from the address, and expect to get a Python string as the result object! 133 self.assertFalse(val.TypeIsPointerType()) 134 cstring = process.ReadCStringFromMemory(val.AddressOf().GetValueAsUnsigned(), 256, error) 135 if not error.Success(): 136 self.fail("SBProcess.ReadCStringFromMemory() failed") 137 if self.TraceOn(): 138 print "cstring read is:", cstring 139 140 self.expect(cstring, "Result from SBProcess.ReadCStringFromMemory() matches our expected output", 141 exe=False, 142 startstr = 'lldb.SBProcess.ReadCStringFromMemory() works!') 143 144 # Get the SBValue for the global variable 'my_uint32'. 145 val = frame.FindValue("my_uint32", lldb.eValueTypeVariableGlobal) 146 self.DebugSBValue(val) 147 148 # Due to the typemap magic (see lldb.swig), we pass in 4 to read 4 bytes 149 # from the address, and expect to get an int as the result! 150 self.assertFalse(val.TypeIsPointerType()) 151 my_uint32 = process.ReadUnsignedFromMemory(val.AddressOf().GetValueAsUnsigned(), 4, error) 152 if not error.Success(): 153 self.fail("SBProcess.ReadCStringFromMemory() failed") 154 if self.TraceOn(): 155 print "uint32 read is:", my_uint32 156 157 if my_uint32 != 12345: 158 self.fail("Result from SBProcess.ReadUnsignedFromMemory() does not match our expected output") 159 160 def write_memory(self): 161 """Test Python SBProcess.WriteMemory() API.""" 162 exe = os.path.join(os.getcwd(), "a.out") 163 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 164 165 target = self.dbg.CreateTarget(exe) 166 self.assertTrue(target, VALID_TARGET) 167 168 breakpoint = target.BreakpointCreateByLocation("main.cpp", self.line) 169 self.assertTrue(breakpoint, VALID_BREAKPOINT) 170 171 # Launch the process, and do not stop at the entry point. 172 process = target.LaunchSimple(None, None, os.getcwd()) 173 174 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 175 self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint") 176 frame = thread.GetFrameAtIndex(0) 177 178 # Get the SBValue for the global variable 'my_char'. 179 val = frame.FindValue("my_char", lldb.eValueTypeVariableGlobal) 180 self.DebugSBValue(val) 181 182 # If the variable does not have a load address, there's no sense continuing. 183 if not val.GetLocation().startswith("0x"): 184 return 185 186 # OK, let's get the hex location of the variable. 187 location = int(val.GetLocation(), 16) 188 189 # The program logic makes the 'my_char' variable to have memory content as 'x'. 190 # But we want to use the WriteMemory() API to assign 'a' to the variable. 191 192 # Now use WriteMemory() API to write 'a' into the global variable. 193 error = lldb.SBError() 194 result = process.WriteMemory(location, 'a', error) 195 if not error.Success() or result != 1: 196 self.fail("SBProcess.WriteMemory() failed") 197 198 # Read from the memory location. This time it should be 'a'. 199 # Due to the typemap magic (see lldb.swig), we pass in 1 to ReadMemory and 200 # expect to get a Python string as the result object! 201 content = process.ReadMemory(location, 1, error) 202 if not error.Success(): 203 self.fail("SBProcess.ReadMemory() failed") 204 if self.TraceOn(): 205 print "memory content:", content 206 207 self.expect(content, "Result from SBProcess.ReadMemory() matches our expected output: 'a'", 208 exe=False, 209 startstr = 'a') 210 211 def access_my_int(self): 212 """Test access 'my_int' using Python SBProcess.GetByteOrder() and other APIs.""" 213 exe = os.path.join(os.getcwd(), "a.out") 214 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 215 216 target = self.dbg.CreateTarget(exe) 217 self.assertTrue(target, VALID_TARGET) 218 219 breakpoint = target.BreakpointCreateByLocation("main.cpp", self.line) 220 self.assertTrue(breakpoint, VALID_BREAKPOINT) 221 222 # Launch the process, and do not stop at the entry point. 223 process = target.LaunchSimple(None, None, os.getcwd()) 224 225 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 226 self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint") 227 frame = thread.GetFrameAtIndex(0) 228 229 # Get the SBValue for the global variable 'my_int'. 230 val = frame.FindValue("my_int", lldb.eValueTypeVariableGlobal) 231 self.DebugSBValue(val) 232 233 # If the variable does not have a load address, there's no sense continuing. 234 if not val.GetLocation().startswith("0x"): 235 return 236 237 # OK, let's get the hex location of the variable. 238 location = int(val.GetLocation(), 16) 239 240 # Note that the canonical from of the bytearray is little endian. 241 from lldbutil import int_to_bytearray, bytearray_to_int 242 243 byteSize = val.GetByteSize() 244 bytes = int_to_bytearray(256, byteSize) 245 246 byteOrder = process.GetByteOrder() 247 if byteOrder == lldb.eByteOrderBig: 248 bytes.reverse() 249 elif byteOrder == lldb.eByteOrderLittle: 250 pass 251 else: 252 # Neither big endian nor little endian? Return for now. 253 # Add more logic here if we want to handle other types. 254 return 255 256 # The program logic makes the 'my_int' variable to have int type and value of 0. 257 # But we want to use the WriteMemory() API to assign 256 to the variable. 258 259 # Now use WriteMemory() API to write 256 into the global variable. 260 new_value = str(bytes) 261 error = lldb.SBError() 262 result = process.WriteMemory(location, new_value, error) 263 if not error.Success() or result != byteSize: 264 self.fail("SBProcess.WriteMemory() failed") 265 266 # Make sure that the val we got originally updates itself to notice the change: 267 self.expect(val.GetValue(), 268 "SBProcess.ReadMemory() successfully writes (int)256 to the memory location for 'my_int'", 269 exe=False, 270 startstr = '256') 271 272 # And for grins, get the SBValue for the global variable 'my_int' again, to make sure that also tracks the new value: 273 val = frame.FindValue("my_int", lldb.eValueTypeVariableGlobal) 274 self.expect(val.GetValue(), 275 "SBProcess.ReadMemory() successfully writes (int)256 to the memory location for 'my_int'", 276 exe=False, 277 startstr = '256') 278 279 # Now read the memory content. The bytearray should have (byte)1 as the second element. 280 content = process.ReadMemory(location, byteSize, error) 281 if not error.Success(): 282 self.fail("SBProcess.ReadMemory() failed") 283 284 # Use "ascii" as the encoding because each element of 'content' is in the range [0..255]. 285 new_bytes = bytearray(content, "ascii") 286 287 # The bytearray_to_int utility function expects a little endian bytearray. 288 if byteOrder == lldb.eByteOrderBig: 289 new_bytes.reverse() 290 291 new_value = bytearray_to_int(new_bytes, byteSize) 292 if new_value != 256: 293 self.fail("Memory content read from 'my_int' does not match (int)256") 294 295 # Dump the memory content.... 296 if self.TraceOn(): 297 for i in new_bytes: 298 print "byte:", i 299 300 def remote_launch_should_fail(self): 301 """Test SBProcess.RemoteLaunch() API with a process not in eStateConnected, and it should fail.""" 302 exe = os.path.join(os.getcwd(), "a.out") 303 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 304 305 target = self.dbg.CreateTarget(exe) 306 self.assertTrue(target, VALID_TARGET) 307 308 # Launch the process, and do not stop at the entry point. 309 process = target.LaunchSimple(None, None, os.getcwd()) 310 311 if self.TraceOn(): 312 print "process state:", state_type_to_str(process.GetState()) 313 self.assertTrue(process.GetState() != lldb.eStateConnected) 314 315 error = lldb.SBError() 316 success = process.RemoteLaunch(None, None, None, None, None, None, 0, False, error) 317 self.assertTrue(not success, "RemoteLaunch() should fail for process state != eStateConnected") 318 319 def get_num_supported_hardware_watchpoints(self): 320 """Test SBProcess.GetNumSupportedHardwareWatchpoints() API with a process.""" 321 exe = os.path.join(os.getcwd(), "a.out") 322 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 323 324 target = self.dbg.CreateTarget(exe) 325 self.assertTrue(target, VALID_TARGET) 326 327 breakpoint = target.BreakpointCreateByLocation("main.cpp", self.line) 328 self.assertTrue(breakpoint, VALID_BREAKPOINT) 329 330 # Launch the process, and do not stop at the entry point. 331 process = target.LaunchSimple(None, None, os.getcwd()) 332 333 error = lldb.SBError(); 334 num = process.GetNumSupportedHardwareWatchpoints(error) 335 if self.TraceOn() and error.Success(): 336 print "Number of supported hardware watchpoints: %d" % num 337 338 339if __name__ == '__main__': 340 import atexit 341 lldb.SBDebugger.Initialize() 342 atexit.register(lambda: lldb.SBDebugger.Terminate()) 343 unittest2.main() 344