210 lines · python
1"""2Test lldb-dap memory support3"""4 5from base64 import b64decode6import dap_server7from lldbsuite.test.decorators import *8from lldbsuite.test.lldbtest import *9from lldbsuite.test import lldbutil10import lldbdap_testcase11import os12 13 14class TestDAP_memory(lldbdap_testcase.DAPTestCaseBase):15 @skipIfWindows16 def test_memory_refs_variables(self):17 """18 Tests memory references for evaluate19 """20 program = self.getBuildArtifact("a.out")21 self.build_and_launch(program)22 source = "main.cpp"23 self.source_path = os.path.join(os.getcwd(), source)24 self.set_source_breakpoints(25 source,26 [line_number(source, "// Breakpoint")],27 )28 self.continue_to_next_stop()29 30 locals = {l["name"]: l for l in self.dap_server.get_local_variables()}31 32 # Pointers should have memory-references33 self.assertIn("memoryReference", locals["rawptr"].keys())34 # Non-pointers should also have memory-references35 self.assertIn("memoryReference", locals["not_a_ptr"].keys())36 37 @skipIfWindows38 def test_memory_refs_evaluate(self):39 """40 Tests memory references for evaluate41 """42 program = self.getBuildArtifact("a.out")43 self.build_and_launch(program)44 source = "main.cpp"45 self.source_path = os.path.join(os.getcwd(), source)46 self.set_source_breakpoints(47 source,48 [line_number(source, "// Breakpoint")],49 )50 self.continue_to_next_stop()51 52 self.assertIn(53 "memoryReference",54 self.dap_server.request_evaluate("rawptr")["body"].keys(),55 )56 57 @skipIfWindows58 def test_memory_refs_set_variable(self):59 """60 Tests memory references for `setVariable`61 """62 program = self.getBuildArtifact("a.out")63 self.build_and_launch(program)64 source = "main.cpp"65 self.source_path = os.path.join(os.getcwd(), source)66 self.set_source_breakpoints(67 source,68 [line_number(source, "// Breakpoint")],69 )70 self.continue_to_next_stop()71 72 ptr_value = self.get_local_as_int("rawptr")73 self.assertIn(74 "memoryReference",75 self.set_local("rawptr", ptr_value + 2)["body"].keys(),76 )77 78 @skipIfWindows79 def test_readMemory(self):80 """81 Tests the 'readMemory' request82 """83 program = self.getBuildArtifact("a.out")84 self.build_and_launch(program)85 source = "main.cpp"86 self.source_path = os.path.join(os.getcwd(), source)87 self.set_source_breakpoints(88 source,89 [line_number(source, "// Breakpoint")],90 )91 self.continue_to_next_stop()92 93 ptr_deref = self.dap_server.request_evaluate("*rawptr")["body"]94 memref = ptr_deref["memoryReference"]95 96 # We can read the complete string97 mem = self.dap_server.request_readMemory(memref, 0, 5)["body"]98 self.assertEqual(b64decode(mem["data"]), b"dead\0")99 100 # We can read large chunks, potentially returning partial results101 mem = self.dap_server.request_readMemory(memref, 0, 4096)["body"]102 self.assertEqual(b64decode(mem["data"])[0:5], b"dead\0")103 104 # Use an offset105 mem = self.dap_server.request_readMemory(memref, 2, 3)["body"]106 self.assertEqual(b64decode(mem["data"]), b"ad\0")107 108 # Reads of size 0 are successful109 # VS Code sends those in order to check if a `memoryReference` can actually be dereferenced.110 mem = self.dap_server.request_readMemory(memref, 0, 0)111 self.assertEqual(mem["success"], True)112 self.assertNotIn(113 "data", mem["body"], f"expects no data key in response: {mem!r}"114 )115 116 # Reads at offset 0x0 return unreadable bytes117 bytes_to_read = 6118 mem = self.dap_server.request_readMemory("0x0", 0, bytes_to_read)119 self.assertEqual(mem["body"]["unreadableBytes"], bytes_to_read)120 121 # Reads with invalid address fails.122 mem = self.dap_server.request_readMemory("-3204", 0, 10)123 self.assertFalse(mem["success"], "expect fail on reading memory.")124 125 self.continue_to_exit()126 127 # Flakey on 32-bit Arm Linux.128 @skipIf(oslist=["linux"], archs=["arm$"])129 def test_writeMemory(self):130 """131 Tests the 'writeMemory' request132 """133 program = self.getBuildArtifact("a.out")134 self.build_and_launch(program)135 source = "main.cpp"136 self.source_path = os.path.join(os.getcwd(), source)137 self.set_source_breakpoints(138 source,139 [line_number(source, "// Breakpoint")],140 )141 self.continue_to_next_stop()142 143 # Get the 'not_a_ptr' writable variable reference address.144 ptr_deref = self.dap_server.request_evaluate("not_a_ptr")["body"]145 memref = ptr_deref["memoryReference"]146 147 # Write the decimal value 50 (0x32 in hexadecimal) to memory.148 # This corresponds to the ASCII character '2' and encodes to Base64 as "Mg==".149 mem_response = self.writeMemory(memref, 50, 0, True)150 self.assertEqual(mem_response["success"], True)151 self.assertEqual(mem_response["body"]["bytesWritten"], 1)152 153 # Read back the modified memory and verify that the written data matches154 # the expected result.155 mem_response = self.dap_server.request_readMemory(memref, 0, 1)156 self.assertEqual(mem_response["success"], True)157 self.assertEqual(mem_response["body"]["data"], "Mg==")158 159 # Write the decimal value 100 (0x64 in hexadecimal) to memory.160 # This corresponds to the ASCII character 'd' and encodes to Base64 as "ZA==".161 # allowPartial=False162 mem_response = self.writeMemory(memref, 100, 0, False)163 self.assertEqual(mem_response["success"], True)164 self.assertEqual(mem_response["body"]["bytesWritten"], 1)165 166 # Read back the modified memory and verify that the written data matches167 # the expected result.168 mem_response = self.dap_server.request_readMemory(memref, 0, 1)169 self.assertEqual(mem_response["success"], True)170 self.assertEqual(mem_response["body"]["data"], "ZA==")171 172 # Memory write failed for 0x0.173 mem_response = self.writeMemory("0x0", 50, 0, True)174 self.assertEqual(mem_response["success"], False)175 176 # Malformed memory reference.177 mem_response = self.writeMemory("12345", 50, 0, True)178 self.assertEqual(mem_response["success"], False)179 180 ptr_deref = self.dap_server.request_evaluate("nonWritable")["body"]181 memref = ptr_deref["memoryReference"]182 183 # Writing to non-writable region should return an appropriate error.184 mem_response = self.writeMemory(memref, 50, 0, False)185 self.assertEqual(mem_response["success"], False)186 self.assertRegex(187 mem_response["body"]["error"]["format"],188 r"Memory " + memref + " region is not writable",189 )190 191 # Trying to write empty value; data=""192 mem_response = self.writeMemory(memref)193 self.assertEqual(mem_response["success"], False)194 self.assertRegex(195 mem_response["body"]["error"]["format"],196 r"Data cannot be empty value. Provide valid data",197 )198 199 # Verify that large memory writes fail if the range spans non-writable200 # or non -contiguous regions.201 data = bytes([0xFF] * 8192)202 mem_response = self.writeMemory(203 memref, int.from_bytes(data, byteorder="little"), 0, False204 )205 self.assertEqual(mem_response["success"], False)206 self.assertRegex(207 mem_response["body"]["error"]["format"],208 r"Memory " + memref + " region is not writable",209 )210