xref: /llvm-project/lldb/test/API/commands/memory/read/TestMemoryRead.py (revision 80fcecb13c388ff087a27a4b0e7ca3dd8c98eaa4)
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