1""" 2Test the 'memory read' command. 3""" 4 5import lldb 6import lldbsuite.test.lldbutil as lldbutil 7 8from lldbsuite.test.decorators import * 9from lldbsuite.test.lldbtest import * 10 11 12class MemoryReadTestCase(TestBase): 13 NO_DEBUG_INFO_TESTCASE = True 14 15 def build_run_stop(self): 16 self.build() 17 lldbutil.run_to_source_breakpoint( 18 self, "// break here", lldb.SBFileSpec("main.c") 19 ) 20 21 def test_memory_read_c_string(self): 22 """Test that reading memory as a c string respects the size limit given 23 and warns if the null terminator is missing.""" 24 self.build_run_stop() 25 26 # The size here is the size in memory so it includes the null terminator. 27 cmd = 'memory read --format "c-string" --size {} &my_string' 28 29 # Size matches the size of the array. 30 self.expect(cmd.format(8), substrs=['"abcdefg"']) 31 32 # If size would take us past the terminator we stop at the terminator. 33 self.expect(cmd.format(10), substrs=['"abcdefg"']) 34 35 # Size 3 means 2 chars and a terminator. So we print 2 chars but warn because 36 # the third isn't 0 as expected. 37 self.expect(cmd.format(3), substrs=['"ab"']) 38 self.assertRegex( 39 self.res.GetError(), 40 "unable to find a NULL terminated string at 0x[0-9A-Fa-f]+." 41 " Consider increasing the maximum read length.", 42 ) 43 44 def test_memory_read(self): 45 """Test the 'memory read' command with plain and vector formats.""" 46 self.build_run_stop() 47 48 # (lldb) memory read -f d -c 1 `&argc` 49 # 0x7fff5fbff9a0: 1 50 self.runCmd("memory read -f d -c 1 `&argc`") 51 52 # Find the starting address for variable 'argc' to verify later that the 53 # '--format uint32_t[] --size 4 --count 4' option increments the address 54 # correctly. 55 line = self.res.GetOutput().splitlines()[0] 56 items = line.split(":") 57 address = int(items[0], 0) 58 argc = int(items[1], 0) 59 self.assertGreater(address, 0) 60 self.assertEqual(argc, 1) 61 62 # (lldb) memory read --format uint32_t[] --size 4 --count 4 `&argc` 63 # 0x7fff5fbff9a0: {0x00000001} 64 # 0x7fff5fbff9a4: {0x00000000} 65 # 0x7fff5fbff9a8: {0x0ec0bf27} 66 # 0x7fff5fbff9ac: {0x215db505} 67 self.runCmd("memory read --format uint32_t[] --size 4 --count 4 `&argc`") 68 lines = self.res.GetOutput().splitlines() 69 for i in range(4): 70 if i == 0: 71 # Verify that the printout for argc is correct. 72 self.assertEqual(argc, int(lines[i].split(":")[1].strip(" {}"), 0)) 73 addr = int(lines[i].split(":")[0], 0) 74 # Verify that the printout for addr is incremented correctly. 75 self.assertEqual(addr, (address + i * 4)) 76 77 # (lldb) memory read --format char[] --size 7 --count 1 `&my_string` 78 # 0x7fff5fbff990: {abcdefg} 79 self.expect( 80 "memory read --format char[] --size 7 --count 1 `&my_string`", 81 substrs=["abcdefg"], 82 ) 83 84 # (lldb) memory read --format 'hex float' --size 16 `&argc` 85 # 0x7fff5fbff5b0: error: unsupported byte size (16) for hex float 86 # format 87 self.expect( 88 "memory read --format 'hex float' --size 16 `&argc`", 89 substrs=["unsupported byte size (16) for hex float format"], 90 ) 91 92 self.expect( 93 "memory read --format 'float' --count 1 --size 8 `&my_double`", 94 substrs=["1234."], 95 ) 96 97 # (lldb) memory read --format 'float' --count 1 --size 20 `&my_double` 98 # 0x7fff5fbff598: error: unsupported byte size (20) for float format 99 self.expect( 100 "memory read --format 'float' --count 1 --size 20 `&my_double`", 101 substrs=["unsupported byte size (20) for float format"], 102 ) 103 104 self.expect( 105 "memory read --type int --count 5 `&my_ints[0]`", 106 substrs=["(int) 0x", "2", "4", "6", "8", "10"], 107 ) 108 109 self.expect( 110 "memory read --type int --count 5 --format hex `&my_ints[0]`", 111 substrs=["(int) 0x", "0x", "0a"], 112 ) 113 114 self.expect( 115 "memory read --type int --count 5 --offset 5 `&my_ints[0]`", 116 substrs=["(int) 0x", "12", "14", "16", "18", "20"], 117 ) 118 119 # the gdb format specifier and the size in characters for 120 # the returned values including the 0x prefix. 121 variations = [["b", 4], ["h", 6], ["w", 10], ["g", 18]] 122 for v in variations: 123 formatter = v[0] 124 expected_object_length = v[1] 125 self.runCmd("memory read --gdb-format 4%s &my_uint64s" % formatter) 126 lines = self.res.GetOutput().splitlines() 127 objects_read = [] 128 for l in lines: 129 objects_read.extend(l.split(":")[1].split()) 130 # Check that we got back 4 0x0000 etc bytes 131 for o in objects_read: 132 self.assertEqual(len(o), expected_object_length) 133 self.assertEqual(len(objects_read), 4) 134 135 def test_memory_read_file(self): 136 self.build_run_stop() 137 res = lldb.SBCommandReturnObject() 138 self.ci.HandleCommand("memory read -f d -c 1 `&argc`", res) 139 self.assertTrue(res.Succeeded(), "memory read failed:" + res.GetError()) 140 141 # Record golden output. 142 golden_output = res.GetOutput() 143 144 memory_read_file = self.getBuildArtifact("memory-read-output") 145 146 def check_file_content(expected): 147 with open(memory_read_file) as f: 148 lines = f.readlines() 149 lines = [s.strip() for s in lines] 150 expected = [s.strip() for s in expected] 151 self.assertEqual(lines, expected) 152 153 # Sanity check. 154 self.runCmd("memory read -f d -c 1 -o '{}' `&argc`".format(memory_read_file)) 155 check_file_content([golden_output]) 156 157 # Write some garbage to the file. 158 with open(memory_read_file, "w") as f: 159 f.write("some garbage") 160 161 # Make sure the file is truncated when we run the command again. 162 self.runCmd("memory read -f d -c 1 -o '{}' `&argc`".format(memory_read_file)) 163 check_file_content([golden_output]) 164 165 # Make sure the file is appended when we run the command with --append-outfile. 166 self.runCmd( 167 "memory read -f d -c 1 -o '{}' --append-outfile `&argc`".format( 168 memory_read_file 169 ) 170 ) 171 check_file_content([golden_output, golden_output]) 172