211 lines · python
1"""2Test the 'memory region' command.3"""4 5import lldb6from lldbsuite.test.decorators import *7from lldbsuite.test.lldbtest import *8from lldbsuite.test import lldbutil9from lldbsuite.test.gdbclientutils import MockGDBServerResponder10from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase11 12 13class MemoryCommandRegion(TestBase):14 NO_DEBUG_INFO_TESTCASE = True15 16 def setUp(self):17 TestBase.setUp(self)18 # Find the line number to break for main.c.19 self.line = line_number(20 "main.cpp", "// Run here before printing memory regions"21 )22 23 def test_help(self):24 """Test that help shows you must have one of address or --all, not both."""25 self.expect(26 "help memory region",27 substrs=["memory region <address-expression>", "memory region -a"],28 )29 30 def setup_program(self):31 self.build()32 33 # Set breakpoint in main and run34 self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)35 lldbutil.run_break_set_by_file_and_line(36 self, "main.cpp", self.line, num_expected_locations=-1, loc_exact=True37 )38 39 self.runCmd("run", RUN_SUCCEEDED)40 41 # This test and the next build a large result string in such a way that42 # when run under ASAN the test always times out. Most of the time is in the asan43 # checker under PyUnicode_Append.44 # This seems to be a worst-case scenario for ASAN performance.45 @skipIfAsan46 def test_command(self):47 self.setup_program()48 49 interp = self.dbg.GetCommandInterpreter()50 result = lldb.SBCommandReturnObject()51 52 # Test that the first 'memory region' command prints the usage.53 interp.HandleCommand("memory region", result)54 self.assertFalse(result.Succeeded())55 self.assertEqual(56 result.GetError(),57 "error: 'memory region' takes one argument or \"--all\" option:\n"58 "Usage: memory region <address-expression> (or --all)\n",59 )60 61 # We allow --all or an address argument, not both62 interp.HandleCommand("memory region --all 0", result)63 self.assertFalse(result.Succeeded())64 self.assertRegex(65 result.GetError(),66 'The "--all" option cannot be used when an address argument is given',67 )68 69 # Test that when the address fails to parse, we show an error and do not continue70 interp.HandleCommand("memory region not_an_address", result)71 self.assertFalse(result.Succeeded())72 self.assertEqual(73 result.GetError(),74 'error: invalid address argument "not_an_address": address expression "not_an_address" evaluation failed\n',75 )76 77 # Accumulate the results to compare with the --all output78 all_regions = ""79 80 # Now let's print the memory region starting at 0 which should always work.81 interp.HandleCommand("memory region 0x0", result)82 self.assertTrue(result.Succeeded())83 self.assertRegex(result.GetOutput(), "\\[0x0+-")84 all_regions += result.GetOutput()85 86 # Keep printing memory regions until we printed all of them.87 while True:88 interp.HandleCommand("memory region", result)89 if not result.Succeeded():90 break91 all_regions += result.GetOutput()92 93 # Now that we reached the end, 'memory region' should again print the usage.94 interp.HandleCommand("memory region", result)95 self.assertFalse(result.Succeeded())96 self.assertRegex(97 result.GetError(),98 r"Usage: memory region <address\-expression> \(or \-\-all\)",99 )100 101 # --all should match what repeating the command gives you102 interp.HandleCommand("memory region --all", result)103 self.assertTrue(result.Succeeded())104 self.assertEqual(result.GetOutput(), all_regions)105 106 @skipIfAsan107 def test_no_overlapping_regions(self):108 # In the past on Windows we were recording AllocationBase as the base address109 # of the current region, not BaseAddress. So if a range of pages was split110 # into regions you would see several regions with the same base address.111 # This checks that this no longer happens (and it shouldn't happen on any112 # other OS either).113 self.setup_program()114 115 regions = self.process().GetMemoryRegions()116 num_regions = regions.GetSize()117 118 if num_regions:119 region = lldb.SBMemoryRegionInfo()120 regions.GetMemoryRegionAtIndex(0, region)121 previous_base = region.GetRegionBase()122 previous_end = region.GetRegionEnd()123 124 for idx in range(1, regions.GetSize()):125 regions.GetMemoryRegionAtIndex(idx, region)126 127 # Check that it does not overlap the previous region.128 # This could happen if we got the base addresses or size wrong.129 # Also catches the base addresses being the same.130 region_base = region.GetRegionBase()131 region_end = region.GetRegionEnd()132 133 self.assertFalse(134 (region_base < previous_end) and (previous_base < region_end),135 "Unexpected overlapping memory region found.",136 )137 138 previous_base = region_base139 previous_end = region_end140 141 142class MemoryCommandRegionAll(GDBRemoteTestBase):143 NO_DEBUG_INFO_TESTCASE = True144 145 def test_all_error(self):146 # The --all option should keep looping until the end of the memory range.147 # If there is an error it should be reported as if you were just asking148 # for one region. In this case the error is the remote not supporting149 # qMemoryRegionInfo.150 # (a region being unmapped is not an error, we just get a result151 # describing an unmapped range)152 class MyResponder(MockGDBServerResponder):153 def qMemoryRegionInfo(self, addr):154 # Empty string means unsupported.155 return ""156 157 self.server.responder = MyResponder()158 target = self.dbg.CreateTarget("")159 if self.TraceOn():160 self.runCmd("log enable gdb-remote packets")161 self.addTearDownHook(lambda: self.runCmd("log disable gdb-remote packets"))162 163 process = self.connect(target)164 lldbutil.expect_state_changes(165 self, self.dbg.GetListener(), process, [lldb.eStateStopped]166 )167 168 interp = self.dbg.GetCommandInterpreter()169 result = lldb.SBCommandReturnObject()170 interp.HandleCommand("memory region --all ", result)171 self.assertFalse(result.Succeeded())172 self.assertEqual(173 result.GetError(), "error: qMemoryRegionInfo is not supported\n"174 )175 176 @skipIfAsan177 def test_all_no_abi_plugin(self):178 # There are two conditions for breaking the all loop. Either we get to179 # LLDB_INVALID_ADDRESS, or the ABI plugin tells us we have got beyond180 # the mappable range. If we don't have an ABI plugin, the option should still181 # work and only check the first condition.182 183 class MyResponder(MockGDBServerResponder):184 def qMemoryRegionInfo(self, addr):185 if addr == 0:186 return "start:0;size:100000000;"187 # Goes until the end of memory.188 if addr == 0x100000000:189 return "start:100000000;size:fffffffeffffffff;"190 191 self.server.responder = MyResponder()192 target = self.dbg.CreateTarget("")193 if self.TraceOn():194 self.runCmd("log enable gdb-remote packets")195 self.addTearDownHook(lambda: self.runCmd("log disable gdb-remote packets"))196 197 process = self.connect(target)198 lldbutil.expect_state_changes(199 self, self.dbg.GetListener(), process, [lldb.eStateStopped]200 )201 202 interp = self.dbg.GetCommandInterpreter()203 result = lldb.SBCommandReturnObject()204 interp.HandleCommand("memory region --all ", result)205 self.assertTrue(result.Succeeded())206 self.assertEqual(207 result.GetOutput(),208 "[0x0000000000000000-0x0000000100000000) ---\n"209 "[0x0000000100000000-0xffffffffffffffff) ---\n",210 )211