xref: /llvm-project/lldb/test/API/functionalities/memory-region/TestMemoryRegion.py (revision 737bc9f76a14b955bdfeb3811ce6c9156572be9f)
199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtTest the 'memory region' command.
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprechtimport lldb
699451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
799451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
899451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
9ee582001SDavid Spickettfrom lldbsuite.test.gdbclientutils import MockGDBServerResponder
10ee582001SDavid Spickettfrom lldbsuite.test.lldbgdbclient import GDBRemoteTestBase
1199451b44SJordan Rupprecht
1299451b44SJordan Rupprecht
1399451b44SJordan Rupprechtclass MemoryCommandRegion(TestBase):
1499451b44SJordan Rupprecht    NO_DEBUG_INFO_TESTCASE = True
1599451b44SJordan Rupprecht
1699451b44SJordan Rupprecht    def setUp(self):
1799451b44SJordan Rupprecht        TestBase.setUp(self)
1899451b44SJordan Rupprecht        # Find the line number to break for main.c.
1999451b44SJordan Rupprecht        self.line = line_number(
202238dcc3SJonas Devlieghere            "main.cpp", "// Run here before printing memory regions"
212238dcc3SJonas Devlieghere        )
2299451b44SJordan Rupprecht
2313e1cf80SDavid Spickett    def test_help(self):
2413e1cf80SDavid Spickett        """Test that help shows you must have one of address or --all, not both."""
252238dcc3SJonas Devlieghere        self.expect(
262238dcc3SJonas Devlieghere            "help memory region",
272238dcc3SJonas Devlieghere            substrs=["memory region <address-expression>", "memory region -a"],
282238dcc3SJonas Devlieghere        )
2913e1cf80SDavid Spickett
301ca8a978SDavid Spickett    def setup_program(self):
3199451b44SJordan Rupprecht        self.build()
3299451b44SJordan Rupprecht
3399451b44SJordan Rupprecht        # Set breakpoint in main and run
3499451b44SJordan Rupprecht        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
3599451b44SJordan Rupprecht        lldbutil.run_break_set_by_file_and_line(
362238dcc3SJonas Devlieghere            self, "main.cpp", self.line, num_expected_locations=-1, loc_exact=True
372238dcc3SJonas Devlieghere        )
3899451b44SJordan Rupprecht
3999451b44SJordan Rupprecht        self.runCmd("run", RUN_SUCCEEDED)
4099451b44SJordan Rupprecht
4136a461b8SJim Ingham    # This test and the next build a large result string in such a way that
4236a461b8SJim Ingham    # when run under ASAN the test always times out.  Most of the time is in the asan
430c86fbb5SJim Ingham    # checker under PyUnicode_Append.
440c86fbb5SJim Ingham    # This seems to be a worst-case scenario for ASAN performance.
450c86fbb5SJim Ingham    @skipIfAsan
461ca8a978SDavid Spickett    def test_command(self):
471ca8a978SDavid Spickett        self.setup_program()
481ca8a978SDavid Spickett
4999451b44SJordan Rupprecht        interp = self.dbg.GetCommandInterpreter()
5099451b44SJordan Rupprecht        result = lldb.SBCommandReturnObject()
5199451b44SJordan Rupprecht
5299451b44SJordan Rupprecht        # Test that the first 'memory region' command prints the usage.
5399451b44SJordan Rupprecht        interp.HandleCommand("memory region", result)
5499451b44SJordan Rupprecht        self.assertFalse(result.Succeeded())
552238dcc3SJonas Devlieghere        self.assertEqual(
562238dcc3SJonas Devlieghere            result.GetError(),
5713e1cf80SDavid Spickett            "error: 'memory region' takes one argument or \"--all\" option:\n"
582238dcc3SJonas Devlieghere            "Usage: memory region <address-expression> (or --all)\n",
592238dcc3SJonas Devlieghere        )
6013e1cf80SDavid Spickett
6113e1cf80SDavid Spickett        # We allow --all or an address argument, not both
6213e1cf80SDavid Spickett        interp.HandleCommand("memory region --all 0", result)
6313e1cf80SDavid Spickett        self.assertFalse(result.Succeeded())
64*737bc9f7SJonas Devlieghere        self.assertRegex(
652238dcc3SJonas Devlieghere            result.GetError(),
662238dcc3SJonas Devlieghere            'The "--all" option cannot be used when an address argument is given',
672238dcc3SJonas Devlieghere        )
6899451b44SJordan Rupprecht
6971cf97e9SDavid Spickett        # Test that when the address fails to parse, we show an error and do not continue
7071cf97e9SDavid Spickett        interp.HandleCommand("memory region not_an_address", result)
7171cf97e9SDavid Spickett        self.assertFalse(result.Succeeded())
722238dcc3SJonas Devlieghere        self.assertEqual(
732238dcc3SJonas Devlieghere            result.GetError(),
742238dcc3SJonas Devlieghere            'error: invalid address argument "not_an_address": address expression "not_an_address" evaluation failed\n',
752238dcc3SJonas Devlieghere        )
7671cf97e9SDavid Spickett
7713e1cf80SDavid Spickett        # Accumulate the results to compare with the --all output
7813e1cf80SDavid Spickett        all_regions = ""
7913e1cf80SDavid Spickett
8099451b44SJordan Rupprecht        # Now let's print the memory region starting at 0 which should always work.
8199451b44SJordan Rupprecht        interp.HandleCommand("memory region 0x0", result)
8299451b44SJordan Rupprecht        self.assertTrue(result.Succeeded())
83*737bc9f7SJonas Devlieghere        self.assertRegex(result.GetOutput(), "\\[0x0+-")
8413e1cf80SDavid Spickett        all_regions += result.GetOutput()
8599451b44SJordan Rupprecht
8699451b44SJordan Rupprecht        # Keep printing memory regions until we printed all of them.
8799451b44SJordan Rupprecht        while True:
8899451b44SJordan Rupprecht            interp.HandleCommand("memory region", result)
8999451b44SJordan Rupprecht            if not result.Succeeded():
9099451b44SJordan Rupprecht                break
9113e1cf80SDavid Spickett            all_regions += result.GetOutput()
9299451b44SJordan Rupprecht
9399451b44SJordan Rupprecht        # Now that we reached the end, 'memory region' should again print the usage.
9499451b44SJordan Rupprecht        interp.HandleCommand("memory region", result)
9599451b44SJordan Rupprecht        self.assertFalse(result.Succeeded())
96*737bc9f7SJonas Devlieghere        self.assertRegex(
972238dcc3SJonas Devlieghere            result.GetError(),
982238dcc3SJonas Devlieghere            "Usage: memory region <address\-expression> \(or \-\-all\)",
992238dcc3SJonas Devlieghere        )
10013e1cf80SDavid Spickett
10113e1cf80SDavid Spickett        # --all should match what repeating the command gives you
10213e1cf80SDavid Spickett        interp.HandleCommand("memory region --all", result)
10313e1cf80SDavid Spickett        self.assertTrue(result.Succeeded())
10413e1cf80SDavid Spickett        self.assertEqual(result.GetOutput(), all_regions)
1051ca8a978SDavid Spickett
10636a461b8SJim Ingham    @skipIfAsan
107f3d43ecaSDavid Spickett    def test_no_overlapping_regions(self):
1081ca8a978SDavid Spickett        # In the past on Windows we were recording AllocationBase as the base address
1091ca8a978SDavid Spickett        # of the current region, not BaseAddress. So if a range of pages was split
1101ca8a978SDavid Spickett        # into regions you would see several regions with the same base address.
1111ca8a978SDavid Spickett        # This checks that this no longer happens (and it shouldn't happen on any
1121ca8a978SDavid Spickett        # other OS either).
1131ca8a978SDavid Spickett        self.setup_program()
1141ca8a978SDavid Spickett
1151ca8a978SDavid Spickett        regions = self.process().GetMemoryRegions()
1161ca8a978SDavid Spickett        num_regions = regions.GetSize()
1171ca8a978SDavid Spickett
1181ca8a978SDavid Spickett        if num_regions:
1191ca8a978SDavid Spickett            region = lldb.SBMemoryRegionInfo()
1201ca8a978SDavid Spickett            regions.GetMemoryRegionAtIndex(0, region)
1211ca8a978SDavid Spickett            previous_base = region.GetRegionBase()
1221ca8a978SDavid Spickett            previous_end = region.GetRegionEnd()
1231ca8a978SDavid Spickett
1241ca8a978SDavid Spickett            for idx in range(1, regions.GetSize()):
1251ca8a978SDavid Spickett                regions.GetMemoryRegionAtIndex(idx, region)
1261ca8a978SDavid Spickett
1271ca8a978SDavid Spickett                # Check that it does not overlap the previous region.
1281ca8a978SDavid Spickett                # This could happen if we got the base addresses or size wrong.
1291ca8a978SDavid Spickett                # Also catches the base addresses being the same.
1301ca8a978SDavid Spickett                region_base = region.GetRegionBase()
1311ca8a978SDavid Spickett                region_end = region.GetRegionEnd()
1321ca8a978SDavid Spickett
133f3d43ecaSDavid Spickett                self.assertFalse(
134f3d43ecaSDavid Spickett                    (region_base < previous_end) and (previous_base < region_end),
1352238dcc3SJonas Devlieghere                    "Unexpected overlapping memory region found.",
1362238dcc3SJonas Devlieghere                )
1371ca8a978SDavid Spickett
1381ca8a978SDavid Spickett                previous_base = region_base
1391ca8a978SDavid Spickett                previous_end = region_end
140ee582001SDavid Spickett
1412238dcc3SJonas Devlieghere
142ee582001SDavid Spickettclass MemoryCommandRegionAll(GDBRemoteTestBase):
143ee582001SDavid Spickett    NO_DEBUG_INFO_TESTCASE = True
144ee582001SDavid Spickett
145ee582001SDavid Spickett    def test_all_error(self):
146ee582001SDavid Spickett        # The --all option should keep looping until the end of the memory range.
147ee582001SDavid Spickett        # If there is an error it should be reported as if you were just asking
148ee582001SDavid Spickett        # for one region. In this case the error is the remote not supporting
149ee582001SDavid Spickett        # qMemoryRegionInfo.
150ee582001SDavid Spickett        # (a region being unmapped is not an error, we just get a result
151ee582001SDavid Spickett        # describing an unmapped range)
152ee582001SDavid Spickett        class MyResponder(MockGDBServerResponder):
153ee582001SDavid Spickett            def qMemoryRegionInfo(self, addr):
154ee582001SDavid Spickett                # Empty string means unsupported.
155ee582001SDavid Spickett                return ""
156ee582001SDavid Spickett
157ee582001SDavid Spickett        self.server.responder = MyResponder()
1582238dcc3SJonas Devlieghere        target = self.dbg.CreateTarget("")
159ee582001SDavid Spickett        if self.TraceOn():
160ee582001SDavid Spickett            self.runCmd("log enable gdb-remote packets")
1612238dcc3SJonas Devlieghere            self.addTearDownHook(lambda: self.runCmd("log disable gdb-remote packets"))
162ee582001SDavid Spickett
163ee582001SDavid Spickett        process = self.connect(target)
1642238dcc3SJonas Devlieghere        lldbutil.expect_state_changes(
1652238dcc3SJonas Devlieghere            self, self.dbg.GetListener(), process, [lldb.eStateStopped]
1662238dcc3SJonas Devlieghere        )
167ee582001SDavid Spickett
168ee582001SDavid Spickett        interp = self.dbg.GetCommandInterpreter()
169ee582001SDavid Spickett        result = lldb.SBCommandReturnObject()
170ee582001SDavid Spickett        interp.HandleCommand("memory region --all ", result)
171ee582001SDavid Spickett        self.assertFalse(result.Succeeded())
1722238dcc3SJonas Devlieghere        self.assertEqual(
1732238dcc3SJonas Devlieghere            result.GetError(), "error: qMemoryRegionInfo is not supported\n"
1742238dcc3SJonas Devlieghere        )
175c831cea5SDavid Spickett
176c831cea5SDavid Spickett    @skipIfAsan
177c831cea5SDavid Spickett    def test_all_no_abi_plugin(self):
178c831cea5SDavid Spickett        # There are two conditions for breaking the all loop. Either we get to
179c831cea5SDavid Spickett        # LLDB_INVALID_ADDRESS, or the ABI plugin tells us we have got beyond
180c831cea5SDavid Spickett        # the mappable range. If we don't have an ABI plugin, the option should still
181c831cea5SDavid Spickett        # work and only check the first condition.
182c831cea5SDavid Spickett
183c831cea5SDavid Spickett        class MyResponder(MockGDBServerResponder):
184c831cea5SDavid Spickett            def qMemoryRegionInfo(self, addr):
185c831cea5SDavid Spickett                if addr == 0:
186c831cea5SDavid Spickett                    return "start:0;size:100000000;"
187c831cea5SDavid Spickett                # Goes until the end of memory.
188c831cea5SDavid Spickett                if addr == 0x100000000:
189c831cea5SDavid Spickett                    return "start:100000000;size:fffffffeffffffff;"
190c831cea5SDavid Spickett
191c831cea5SDavid Spickett        self.server.responder = MyResponder()
1922238dcc3SJonas Devlieghere        target = self.dbg.CreateTarget("")
193c831cea5SDavid Spickett        if self.TraceOn():
194c831cea5SDavid Spickett            self.runCmd("log enable gdb-remote packets")
1952238dcc3SJonas Devlieghere            self.addTearDownHook(lambda: self.runCmd("log disable gdb-remote packets"))
196c831cea5SDavid Spickett
197c831cea5SDavid Spickett        process = self.connect(target)
1982238dcc3SJonas Devlieghere        lldbutil.expect_state_changes(
1992238dcc3SJonas Devlieghere            self, self.dbg.GetListener(), process, [lldb.eStateStopped]
2002238dcc3SJonas Devlieghere        )
201c831cea5SDavid Spickett
202c831cea5SDavid Spickett        interp = self.dbg.GetCommandInterpreter()
203c831cea5SDavid Spickett        result = lldb.SBCommandReturnObject()
204c831cea5SDavid Spickett        interp.HandleCommand("memory region --all ", result)
205c831cea5SDavid Spickett        self.assertTrue(result.Succeeded())
2062238dcc3SJonas Devlieghere        self.assertEqual(
2072238dcc3SJonas Devlieghere            result.GetOutput(),
208c831cea5SDavid Spickett            "[0x0000000000000000-0x0000000100000000) ---\n"
2092238dcc3SJonas Devlieghere            "[0x0000000100000000-0xffffffffffffffff) ---\n",
2102238dcc3SJonas Devlieghere        )
211