mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-22 17:23:06 +00:00
drgn.helpers.linux.mm: add simple PageFlag() getters
There are a bunch of page flag getters in the kernel like PageUptodate(), PageLocked(), etc., that kernel developers are accustomed to using. Most of them are simple bit tests. Let's add helpers for all of those. These are generated from include/linux/page-flags.h in the Linux kernel source tree as of Linux v6.0-rc1. More complicated getters that need to do more than a simple flag check (e.g., PageCompound()) will need to be added manually. Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
parent
c0ed1a3203
commit
d14f751475
@ -36,18 +36,526 @@ __all__ = (
|
||||
"virt_to_page",
|
||||
"virt_to_pfn",
|
||||
"virt_to_phys",
|
||||
# Generated by scripts/generate_page_flag_getters.py.
|
||||
"PageActive",
|
||||
"PageChecked",
|
||||
"PageDirty",
|
||||
"PageDoubleMap",
|
||||
"PageError",
|
||||
"PageForeign",
|
||||
"PageHWPoison",
|
||||
"PageHasHWPoisoned",
|
||||
"PageIdle",
|
||||
"PageIsolated",
|
||||
"PageLRU",
|
||||
"PageLocked",
|
||||
"PageMappedToDisk",
|
||||
"PageMlocked",
|
||||
"PageOwnerPriv1",
|
||||
"PagePinned",
|
||||
"PagePrivate",
|
||||
"PagePrivate2",
|
||||
"PageReadahead",
|
||||
"PageReclaim",
|
||||
"PageReferenced",
|
||||
"PageReported",
|
||||
"PageReserved",
|
||||
"PageSavePinned",
|
||||
"PageSkipKASanPoison",
|
||||
"PageSlab",
|
||||
"PageSlobFree",
|
||||
"PageSwapBacked",
|
||||
"PageUncached",
|
||||
"PageUnevictable",
|
||||
"PageUptodate",
|
||||
"PageVmemmapSelfHosted",
|
||||
"PageWaiters",
|
||||
"PageWorkingset",
|
||||
"PageWriteback",
|
||||
"PageXenRemapped",
|
||||
"PageYoung",
|
||||
)
|
||||
|
||||
|
||||
def for_each_page(prog: Program) -> Iterator[Object]:
|
||||
def PageActive(page: Object) -> bool:
|
||||
"""
|
||||
Iterate over all pages in the system.
|
||||
Return whether the ``PG_active`` flag is set on a page.
|
||||
|
||||
:return: Iterator of ``struct page *`` objects.
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
vmemmap = prog["vmemmap"]
|
||||
for i in range(prog["min_low_pfn"], prog["max_pfn"]):
|
||||
yield vmemmap + i
|
||||
try:
|
||||
flag = page.prog_["PG_active"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageChecked(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_checked`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_checked"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageDirty(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_dirty`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_dirty"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageDoubleMap(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_double_map`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_double_map"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageError(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_error`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_error"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageForeign(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_foreign`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_foreign"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageHWPoison(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_hwpoison`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_hwpoison"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageHasHWPoisoned(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_has_hwpoisoned`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_has_hwpoisoned"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageIdle(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_idle`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_idle"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageIsolated(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_isolated`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_isolated"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageLRU(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_lru`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_lru"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageLocked(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_locked`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_locked"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageMappedToDisk(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_mappedtodisk`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_mappedtodisk"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageMlocked(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_mlocked`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_mlocked"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageOwnerPriv1(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_owner_priv_1`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_owner_priv_1"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PagePinned(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_pinned`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_pinned"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PagePrivate(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_private`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_private"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PagePrivate2(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_private_2`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_private_2"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageReadahead(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_readahead`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_readahead"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageReclaim(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_reclaim`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_reclaim"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageReferenced(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_referenced`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_referenced"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageReported(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_reported`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_reported"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageReserved(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_reserved`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_reserved"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageSavePinned(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_savepinned`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_savepinned"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageSkipKASanPoison(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_skip_kasan_poison`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_skip_kasan_poison"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageSlab(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_slab`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_slab"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageSlobFree(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_slob_free`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_slob_free"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageSwapBacked(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_swapbacked`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_swapbacked"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageUncached(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_uncached`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_uncached"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageUnevictable(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_unevictable`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_unevictable"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageUptodate(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_uptodate`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_uptodate"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageVmemmapSelfHosted(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_vmemmap_self_hosted`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_vmemmap_self_hosted"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageWaiters(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_waiters`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_waiters"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageWorkingset(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_workingset`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_workingset"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageWriteback(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_writeback`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_writeback"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageXenRemapped(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_xen_remapped`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_xen_remapped"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def PageYoung(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_young`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_young"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
|
||||
|
||||
def decode_page_flags(page: Object) -> str:
|
||||
@ -66,6 +574,17 @@ def decode_page_flags(page: Object) -> str:
|
||||
)
|
||||
|
||||
|
||||
def for_each_page(prog: Program) -> Iterator[Object]:
|
||||
"""
|
||||
Iterate over all pages in the system.
|
||||
|
||||
:return: Iterator of ``struct page *`` objects.
|
||||
"""
|
||||
vmemmap = prog["vmemmap"]
|
||||
for i in range(prog["min_low_pfn"], prog["max_pfn"]):
|
||||
yield vmemmap + i
|
||||
|
||||
|
||||
@overload
|
||||
def PFN_PHYS(pfn: Object) -> Object:
|
||||
"""
|
||||
|
47
scripts/generate_page_flag_getters.py
Executable file
47
scripts/generate_page_flag_getters.py
Executable file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate PageFlag() helpers from include/linux/page-flags.h"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
flags = {
|
||||
# PageUptodate() isn't defined with PAGEFLAG because it needs
|
||||
# additional memory barriers, but other than that it's the same.
|
||||
"Uptodate": "uptodate",
|
||||
}
|
||||
for match in re.finditer(
|
||||
r"\b(?:|__|TEST)PAGEFLAG\s*\(\s*(\w+)(?<!uname)\s*,\s*(\w+)\s*,\s*\w+\s*\)",
|
||||
sys.stdin.read(),
|
||||
):
|
||||
if flags.setdefault(match.group(1), match.group(2)) != match.group(2):
|
||||
sys.exit(f"{match.group('uname')} has multiple lowercase names?")
|
||||
|
||||
print(" # Generated by scripts/generate_page_flag_getters.py.")
|
||||
for uname, lname in sorted(flags.items()):
|
||||
print(f' "Page{uname}",')
|
||||
print(")")
|
||||
print()
|
||||
for uname, lname in sorted(flags.items()):
|
||||
print(
|
||||
f'''
|
||||
def Page{uname}(page: Object) -> bool:
|
||||
"""
|
||||
Return whether the ``PG_{lname}`` flag is set on a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
"""
|
||||
try:
|
||||
flag = page.prog_["PG_{lname}"]
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(page.flags & (1 << flag))
|
||||
'''
|
||||
)
|
@ -14,6 +14,8 @@ from drgn import FaultError
|
||||
from drgn.helpers.linux.mm import (
|
||||
PFN_PHYS,
|
||||
PHYS_PFN,
|
||||
PageSwapBacked,
|
||||
PageWriteback,
|
||||
access_process_vm,
|
||||
access_remote_vm,
|
||||
cmdline,
|
||||
@ -70,6 +72,14 @@ class TestMm(LinuxKernelTestCase):
|
||||
]
|
||||
yield map, address, pfns
|
||||
|
||||
def test_page_flag_getters(self):
|
||||
with self._pages() as (map, _, pfns):
|
||||
page = pfn_to_page(self.prog, pfns[0])
|
||||
# The page flag getters are generated, so just pick a positive case
|
||||
# and a negative case to cover all of them.
|
||||
self.assertTrue(PageSwapBacked(page))
|
||||
self.assertFalse(PageWriteback(page))
|
||||
|
||||
@skip_unless_have_full_mm_support
|
||||
def test_decode_page_flags(self):
|
||||
with self._pages() as (map, _, pfns):
|
||||
|
Loading…
Reference in New Issue
Block a user