Home | History | Annotate | Download | only in process
      1 """
      2 Test SBProcess APIs, including ReadMemory(), WriteMemory(), and others.
      3 """
      4 
      5 import os, time
      6 import unittest2
      7 import lldb
      8 from lldbutil import get_stopped_thread, state_type_to_str
      9 from lldbtest import *
     10 
     11 class 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 
    339 if __name__ == '__main__':
    340     import atexit
    341     lldb.SBDebugger.Initialize()
    342     atexit.register(lambda: lldb.SBDebugger.Terminate())
    343     unittest2.main()
    344