199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtTest the 'memory region' command.
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprecht
699451b44SJordan Rupprecht
799451b44SJordan Rupprechtimport lldb
899451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
999451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1099451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
1199451b44SJordan Rupprecht
1299451b44SJordan Rupprecht
1399451b44SJordan Rupprechtclass MemoryCommandRegion(TestBase):
1499451b44SJordan Rupprecht
1599451b44SJordan Rupprecht    NO_DEBUG_INFO_TESTCASE = True
1699451b44SJordan Rupprecht
1799451b44SJordan Rupprecht    def setUp(self):
1899451b44SJordan Rupprecht        TestBase.setUp(self)
1999451b44SJordan Rupprecht        # Find the line number to break for main.c.
2099451b44SJordan Rupprecht        self.line = line_number(
2199451b44SJordan Rupprecht            'main.cpp',
2299451b44SJordan Rupprecht            '// Run here before printing memory regions')
2399451b44SJordan Rupprecht
2413e1cf80SDavid Spickett    def test_help(self):
2513e1cf80SDavid Spickett        """ Test that help shows you must have one of address or --all, not both."""
2613e1cf80SDavid Spickett        self.expect("help memory region",
2713e1cf80SDavid Spickett            substrs=["memory region <address-expression>",
2813e1cf80SDavid Spickett                     "memory region -a"])
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(
3699451b44SJordan Rupprecht            self, "main.cpp", self.line, num_expected_locations=-1, loc_exact=True)
3799451b44SJordan Rupprecht
3899451b44SJordan Rupprecht        self.runCmd("run", RUN_SUCCEEDED)
3999451b44SJordan Rupprecht
401ca8a978SDavid Spickett    def test_command(self):
411ca8a978SDavid Spickett        self.setup_program()
421ca8a978SDavid Spickett
4399451b44SJordan Rupprecht        interp = self.dbg.GetCommandInterpreter()
4499451b44SJordan Rupprecht        result = lldb.SBCommandReturnObject()
4599451b44SJordan Rupprecht
4699451b44SJordan Rupprecht        # Test that the first 'memory region' command prints the usage.
4799451b44SJordan Rupprecht        interp.HandleCommand("memory region", result)
4899451b44SJordan Rupprecht        self.assertFalse(result.Succeeded())
4913e1cf80SDavid Spickett        self.assertEqual(result.GetError(),
5013e1cf80SDavid Spickett                    "error: 'memory region' takes one argument or \"--all\" option:\n"
5113e1cf80SDavid Spickett                    "Usage: memory region <address-expression> (or --all)\n")
5213e1cf80SDavid Spickett
5313e1cf80SDavid Spickett        # We allow --all or an address argument, not both
5413e1cf80SDavid Spickett        interp.HandleCommand("memory region --all 0", result)
5513e1cf80SDavid Spickett        self.assertFalse(result.Succeeded())
5613e1cf80SDavid Spickett        self.assertRegexpMatches(result.GetError(),
5713e1cf80SDavid Spickett                "The \"--all\" option cannot be used when an address argument is given")
5899451b44SJordan Rupprecht
5971cf97e9SDavid Spickett        # Test that when the address fails to parse, we show an error and do not continue
6071cf97e9SDavid Spickett        interp.HandleCommand("memory region not_an_address", result)
6171cf97e9SDavid Spickett        self.assertFalse(result.Succeeded())
6271cf97e9SDavid Spickett        self.assertEqual(result.GetError(),
6371cf97e9SDavid Spickett                "error: invalid address argument \"not_an_address\": address expression \"not_an_address\" evaluation failed\n")
6471cf97e9SDavid Spickett
6513e1cf80SDavid Spickett        # Accumulate the results to compare with the --all output
6613e1cf80SDavid Spickett        all_regions = ""
6713e1cf80SDavid Spickett
6899451b44SJordan Rupprecht        # Now let's print the memory region starting at 0 which should always work.
6999451b44SJordan Rupprecht        interp.HandleCommand("memory region 0x0", result)
7099451b44SJordan Rupprecht        self.assertTrue(result.Succeeded())
7199451b44SJordan Rupprecht        self.assertRegexpMatches(result.GetOutput(), "\\[0x0+-")
7213e1cf80SDavid Spickett        all_regions += result.GetOutput()
7399451b44SJordan Rupprecht
7499451b44SJordan Rupprecht        # Keep printing memory regions until we printed all of them.
7599451b44SJordan Rupprecht        while True:
7699451b44SJordan Rupprecht            interp.HandleCommand("memory region", result)
7799451b44SJordan Rupprecht            if not result.Succeeded():
7899451b44SJordan Rupprecht                break
7913e1cf80SDavid Spickett            all_regions += result.GetOutput()
8099451b44SJordan Rupprecht
8199451b44SJordan Rupprecht        # Now that we reached the end, 'memory region' should again print the usage.
8299451b44SJordan Rupprecht        interp.HandleCommand("memory region", result)
8399451b44SJordan Rupprecht        self.assertFalse(result.Succeeded())
8413e1cf80SDavid Spickett        self.assertRegexpMatches(result.GetError(), "Usage: memory region <address\-expression> \(or \-\-all\)")
8513e1cf80SDavid Spickett
8613e1cf80SDavid Spickett        # --all should match what repeating the command gives you
8713e1cf80SDavid Spickett        interp.HandleCommand("memory region --all", result)
8813e1cf80SDavid Spickett        self.assertTrue(result.Succeeded())
8913e1cf80SDavid Spickett        self.assertEqual(result.GetOutput(), all_regions)
901ca8a978SDavid Spickett
91*f3d43ecaSDavid Spickett    def test_no_overlapping_regions(self):
921ca8a978SDavid Spickett        # In the past on Windows we were recording AllocationBase as the base address
931ca8a978SDavid Spickett        # of the current region, not BaseAddress. So if a range of pages was split
941ca8a978SDavid Spickett        # into regions you would see several regions with the same base address.
951ca8a978SDavid Spickett        # This checks that this no longer happens (and it shouldn't happen on any
961ca8a978SDavid Spickett        # other OS either).
971ca8a978SDavid Spickett        self.setup_program()
981ca8a978SDavid Spickett
991ca8a978SDavid Spickett        regions = self.process().GetMemoryRegions()
1001ca8a978SDavid Spickett        num_regions = regions.GetSize()
1011ca8a978SDavid Spickett
1021ca8a978SDavid Spickett        if num_regions:
1031ca8a978SDavid Spickett            region = lldb.SBMemoryRegionInfo()
1041ca8a978SDavid Spickett            regions.GetMemoryRegionAtIndex(0, region)
1051ca8a978SDavid Spickett            previous_base = region.GetRegionBase()
1061ca8a978SDavid Spickett            previous_end = region.GetRegionEnd()
1071ca8a978SDavid Spickett
1081ca8a978SDavid Spickett            for idx in range(1, regions.GetSize()):
1091ca8a978SDavid Spickett                regions.GetMemoryRegionAtIndex(idx, region)
1101ca8a978SDavid Spickett
1111ca8a978SDavid Spickett                # Check that it does not overlap the previous region.
1121ca8a978SDavid Spickett                # This could happen if we got the base addresses or size wrong.
1131ca8a978SDavid Spickett                # Also catches the base addresses being the same.
1141ca8a978SDavid Spickett                region_base = region.GetRegionBase()
1151ca8a978SDavid Spickett                region_end = region.GetRegionEnd()
1161ca8a978SDavid Spickett
117*f3d43ecaSDavid Spickett                self.assertFalse(
118*f3d43ecaSDavid Spickett                    (region_base < previous_end) and (previous_base < region_end),
1191ca8a978SDavid Spickett                    "Unexpected overlapping memory region found.")
1201ca8a978SDavid Spickett
1211ca8a978SDavid Spickett                previous_base = region_base
1221ca8a978SDavid Spickett                previous_end = region_end