Skip to content

Commit ca1b77f

Browse files
DavidSpickettmahesh-attarde
authored andcommitted
[lldb][test] Refactor and expand TestMemoryRegionDirtyPages.py (llvm#156035)
This started as me being annoyed that I got loads of this when inspecting memory regions on Mac: Modified memory (dirty) page list provided, 0 entries. So I thought I should test the existing behaviour, which led me to refactor the existing test to run the same checks on all regions. In the process I realised that the output is not wrong. There is a difference between knowing that no pages are dirty and not knowing anything about dirty pages. We print that there are 0 entries so the user knows that difference. The test case now checks "memory region" output as well as API use. There were also some checks only run on certain regions, like page size, which now run for all of them.
1 parent d7e683f commit ca1b77f

File tree

1 file changed

+80
-38
lines changed

1 file changed

+80
-38
lines changed

lldb/test/API/functionalities/gdb_remote_client/TestMemoryRegionDirtyPages.py

Lines changed: 80 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,60 +5,102 @@
55
from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase
66

77

8+
class TestRegion(object):
9+
def __init__(self, start_addr, size, dirty_pages):
10+
self.start_addr = start_addr
11+
self.size = size
12+
self.dirty_pages = dirty_pages
13+
14+
def as_packet(self):
15+
dirty_pages = ""
16+
if self.dirty_pages is not None:
17+
dirty_pages = (
18+
"dirty-pages:"
19+
+ ",".join([format(a, "x") for a in self.dirty_pages])
20+
+ ";"
21+
)
22+
return f"start:{self.start_addr:x};size:{self.size};permissions:r;{dirty_pages}"
23+
24+
def expected_command_output(self):
25+
if self.dirty_pages is None:
26+
return [
27+
"Modified memory (dirty) page list provided",
28+
"Dirty pages:",
29+
], False
30+
31+
expected = [
32+
f"Modified memory (dirty) page list provided, {len(self.dirty_pages)} entries."
33+
]
34+
if self.dirty_pages:
35+
expected.append(
36+
"Dirty pages: "
37+
+ ", ".join([format(a, "#x") for a in self.dirty_pages])
38+
+ "."
39+
)
40+
return expected, True
41+
42+
843
class TestMemoryRegionDirtyPages(GDBRemoteTestBase):
944
@skipIfXmlSupportMissing
1045
def test(self):
46+
test_regions = [
47+
# A memory region where we don't know anything about dirty pages
48+
TestRegion(0, 0x100000000, None),
49+
# A memory region with dirty page information -- and zero dirty pages
50+
TestRegion(0x100000000, 4000, []),
51+
# A memory region with one dirty page
52+
TestRegion(0x100004000, 4000, [0x100004000]),
53+
# A memory region with multple dirty pages
54+
TestRegion(
55+
0x1000A2000,
56+
5000,
57+
[0x1000A2000, 0x1000A3000, 0x1000A4000, 0x1000A5000, 0x1000A6000],
58+
),
59+
]
60+
1161
class MyResponder(MockGDBServerResponder):
1262
def qHostInfo(self):
1363
return "ptrsize:8;endian:little;vm-page-size:4096;"
1464

1565
def qMemoryRegionInfo(self, addr):
16-
if addr == 0:
17-
return "start:0;size:100000000;"
18-
if addr == 0x100000000:
19-
return "start:100000000;size:4000;permissions:rx;dirty-pages:;"
20-
if addr == 0x100004000:
21-
return (
22-
"start:100004000;size:4000;permissions:r;dirty-pages:100004000;"
23-
)
24-
if addr == 0x1000A2000:
25-
return "start:1000a2000;size:5000;permissions:r;dirty-pages:1000a2000,1000a3000,1000a4000,1000a5000,1000a6000;"
66+
for region in test_regions:
67+
if region.start_addr == addr:
68+
return region.as_packet()
2669

2770
self.server.responder = MyResponder()
2871
target = self.dbg.CreateTarget("")
2972
if self.TraceOn():
3073
self.runCmd("log enable gdb-remote packets")
3174
self.addTearDownHook(lambda: self.runCmd("log disable gdb-remote packets"))
75+
3276
process = self.connect(target)
77+
lldbutil.expect_state_changes(
78+
self, self.dbg.GetListener(), process, [lldb.eStateStopped]
79+
)
3380

34-
# A memory region where we don't know anything about dirty pages
35-
region = lldb.SBMemoryRegionInfo()
36-
err = process.GetMemoryRegionInfo(0, region)
37-
self.assertSuccess(err)
38-
self.assertFalse(region.HasDirtyMemoryPageList())
39-
self.assertEqual(region.GetNumDirtyPages(), 0)
40-
region.Clear()
81+
for test_region in test_regions:
82+
region = lldb.SBMemoryRegionInfo()
83+
err = process.GetMemoryRegionInfo(test_region.start_addr, region)
84+
self.assertSuccess(err)
85+
self.assertEqual(region.GetPageSize(), 4096)
4186

42-
# A memory region with dirty page information -- and zero dirty pages
43-
err = process.GetMemoryRegionInfo(0x100000000, region)
44-
self.assertSuccess(err)
45-
self.assertTrue(region.HasDirtyMemoryPageList())
46-
self.assertEqual(region.GetNumDirtyPages(), 0)
47-
self.assertEqual(region.GetPageSize(), 4096)
48-
region.Clear()
87+
if test_region.dirty_pages is None:
88+
self.assertFalse(region.HasDirtyMemoryPageList())
89+
self.assertEqual(0, region.GetNumDirtyPages())
90+
else:
91+
self.assertTrue(region.HasDirtyMemoryPageList())
92+
self.assertEqual(
93+
len(test_region.dirty_pages), region.GetNumDirtyPages()
94+
)
4995

50-
# A memory region with one dirty page
51-
err = process.GetMemoryRegionInfo(0x100004000, region)
52-
self.assertSuccess(err)
53-
self.assertTrue(region.HasDirtyMemoryPageList())
54-
self.assertEqual(region.GetNumDirtyPages(), 1)
55-
self.assertEqual(region.GetDirtyPageAddressAtIndex(0), 0x100004000)
56-
region.Clear()
96+
for i, expected_dirty_page in enumerate(test_region.dirty_pages):
97+
self.assertEqual(
98+
expected_dirty_page, region.GetDirtyPageAddressAtIndex(i)
99+
)
57100

58-
# A memory region with multple dirty pages
59-
err = process.GetMemoryRegionInfo(0x1000A2000, region)
60-
self.assertSuccess(err)
61-
self.assertTrue(region.HasDirtyMemoryPageList())
62-
self.assertEqual(region.GetNumDirtyPages(), 5)
63-
self.assertEqual(region.GetDirtyPageAddressAtIndex(4), 0x1000A6000)
64-
region.Clear()
101+
substrs, matching = test_region.expected_command_output()
102+
self.expect(
103+
f"memory region 0x{test_region.start_addr:x}",
104+
substrs=substrs,
105+
matching=matching,
106+
)

0 commit comments

Comments
 (0)