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