mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-22 17:23:06 +00:00
drgn.helpers.linux.mm: add physical address conversion helpers
Add helpers for converting physical addresses to and from virtual addresses, PFNs, and struct pages. Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
parent
4ea0476caf
commit
0f9b123254
@ -18,6 +18,8 @@ from drgn import IntegerLike, Object, Program, cast
|
||||
from drgn.helpers import decode_enum_type_flags
|
||||
|
||||
__all__ = (
|
||||
"PFN_PHYS",
|
||||
"PHYS_PFN",
|
||||
"access_process_vm",
|
||||
"access_remote_vm",
|
||||
"cmdline",
|
||||
@ -25,11 +27,15 @@ __all__ = (
|
||||
"environ",
|
||||
"for_each_page",
|
||||
"page_to_pfn",
|
||||
"page_to_phys",
|
||||
"page_to_virt",
|
||||
"pfn_to_page",
|
||||
"pfn_to_virt",
|
||||
"phys_to_page",
|
||||
"phys_to_virt",
|
||||
"virt_to_page",
|
||||
"virt_to_pfn",
|
||||
"virt_to_phys",
|
||||
)
|
||||
|
||||
|
||||
@ -60,6 +66,80 @@ def decode_page_flags(page: Object) -> str:
|
||||
)
|
||||
|
||||
|
||||
@overload
|
||||
def PFN_PHYS(pfn: Object) -> Object:
|
||||
"""
|
||||
Get the physical address of a page frame number (PFN) given as an
|
||||
:class:`.Object`.
|
||||
|
||||
:param pfn: ``unsigned long``
|
||||
:return: ``phys_addr_t``
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def PFN_PHYS(prog: Program, pfn: IntegerLike) -> Object:
|
||||
"""
|
||||
Get the physical address of a page frame number (PFN) given as a
|
||||
:class:`.Program` and an integer.
|
||||
|
||||
:param pfn: Page frame number.
|
||||
:return: ``phys_addr_t``
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
def PFN_PHYS( # type: ignore # Need positional-only arguments.
|
||||
prog_or_pfn: Union[Program, Object], pfn: Optional[IntegerLike] = None
|
||||
) -> Object:
|
||||
if pfn is None:
|
||||
assert isinstance(prog_or_pfn, Object)
|
||||
prog = prog_or_pfn.prog_
|
||||
pfn = prog_or_pfn
|
||||
else:
|
||||
assert isinstance(prog_or_pfn, Program)
|
||||
prog = prog_or_pfn
|
||||
return Object(prog, "phys_addr_t", operator.index(pfn)) << prog["PAGE_SHIFT"]
|
||||
|
||||
|
||||
@overload
|
||||
def PHYS_PFN(addr: Object) -> Object:
|
||||
"""
|
||||
Get the page frame number (PFN) of a physical address given as an
|
||||
:class:`.Object`.
|
||||
|
||||
:param addr: ``phys_addr_t``
|
||||
:return: ``unsigned long``
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def PHYS_PFN(prog: Program, addr: int) -> Object:
|
||||
"""
|
||||
Get the page frame number (PFN) of a physical address given as a
|
||||
:class:`.Program` and an integer.
|
||||
|
||||
:param addr: Physical address.
|
||||
:return: ``unsigned long``
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
def PHYS_PFN( # type: ignore # Need positional-only arguments.
|
||||
prog_or_addr: Union[Program, Object], addr: Optional[IntegerLike] = None
|
||||
) -> Object:
|
||||
if addr is None:
|
||||
assert isinstance(prog_or_addr, Object)
|
||||
prog = prog_or_addr.prog_
|
||||
addr = prog_or_addr
|
||||
else:
|
||||
assert isinstance(prog_or_addr, Program)
|
||||
prog = prog_or_addr
|
||||
return Object(prog, "unsigned long", operator.index(addr)) >> prog["PAGE_SHIFT"]
|
||||
|
||||
|
||||
def page_to_pfn(page: Object) -> Object:
|
||||
"""
|
||||
Get the page frame number (PFN) of a page.
|
||||
@ -70,6 +150,26 @@ def page_to_pfn(page: Object) -> Object:
|
||||
return cast("unsigned long", page - page.prog_["vmemmap"])
|
||||
|
||||
|
||||
def page_to_phys(page: Object) -> Object:
|
||||
"""
|
||||
Get the physical address of a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
:return: ``phys_addr_t``
|
||||
"""
|
||||
return PFN_PHYS(page_to_pfn(page))
|
||||
|
||||
|
||||
def page_to_virt(page: Object) -> Object:
|
||||
"""
|
||||
Get the directly mapped virtual address of a page.
|
||||
|
||||
:param page: ``struct page *``
|
||||
:return: ``void *``
|
||||
"""
|
||||
return pfn_to_virt(page_to_pfn(page))
|
||||
|
||||
|
||||
@overload
|
||||
def pfn_to_page(pfn: Object) -> Object:
|
||||
"""
|
||||
@ -106,43 +206,6 @@ def pfn_to_page( # type: ignore # Need positional-only arguments.
|
||||
return prog["vmemmap"] + pfn
|
||||
|
||||
|
||||
@overload
|
||||
def virt_to_pfn(addr: Object) -> Object:
|
||||
"""
|
||||
Get the page frame number (PFN) of a directly mapped virtual address given
|
||||
as an :class:`.Object`.
|
||||
|
||||
:param addr: ``void *``
|
||||
:return: ``unsigned long``
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def virt_to_pfn(prog: Program, addr: IntegerLike) -> Object:
|
||||
"""
|
||||
Get the page frame number (PFN) of a directly mapped virtual address given
|
||||
as a :class:`.Program` and an integer.
|
||||
|
||||
:param addr: Virtual address.
|
||||
:return: ``unsigned long``
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
def virt_to_pfn( # type: ignore # Need positional-only arguments.
|
||||
prog_or_addr: Union[Program, Object], addr: Optional[IntegerLike] = None
|
||||
) -> Object:
|
||||
if addr is None:
|
||||
assert isinstance(prog_or_addr, Object)
|
||||
prog = prog_or_addr.prog_
|
||||
addr = prog_or_addr
|
||||
else:
|
||||
assert isinstance(prog_or_addr, Program)
|
||||
prog = prog_or_addr
|
||||
return cast("unsigned long", (operator.index(addr) - prog["PAGE_OFFSET"]) >> 12)
|
||||
|
||||
|
||||
@overload
|
||||
def pfn_to_virt(pfn: Object) -> Object:
|
||||
"""
|
||||
@ -169,24 +232,74 @@ def pfn_to_virt(prog: Program, pfn: IntegerLike) -> Object:
|
||||
def pfn_to_virt( # type: ignore # Need positional-only arguments.
|
||||
prog_or_pfn: Union[Program, Object], pfn: Optional[IntegerLike] = None
|
||||
) -> Object:
|
||||
if pfn is None:
|
||||
assert isinstance(prog_or_pfn, Object)
|
||||
prog = prog_or_pfn.prog_
|
||||
pfn = prog_or_pfn
|
||||
else:
|
||||
assert isinstance(prog_or_pfn, Program)
|
||||
prog = prog_or_pfn
|
||||
return cast("void *", (operator.index(pfn) << 12) + prog["PAGE_OFFSET"])
|
||||
return phys_to_virt(PFN_PHYS(prog_or_pfn, pfn)) # type: ignore
|
||||
|
||||
|
||||
def page_to_virt(page: Object) -> Object:
|
||||
@overload
|
||||
def phys_to_page(addr: Object) -> Object:
|
||||
"""
|
||||
Get the directly mapped virtual address of a page.
|
||||
Get the page containing a directly mapped physical address given as an
|
||||
:class:`.Object`.
|
||||
|
||||
:param page: ``struct page *``
|
||||
:param addr: ``phys_addr_t``
|
||||
:return: ``struct page *``
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def phys_to_page(prog: Program, addr: IntegerLike) -> Object:
|
||||
"""
|
||||
Get the page containing a directly mapped physical address given as a
|
||||
:class:`.Program` and an integer.
|
||||
|
||||
:param addr: Physical address.
|
||||
:return: ``struct page *``
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
def phys_to_page( # type: ignore # Need positional-only arguments.
|
||||
prog_or_addr: Union[Program, Object], addr: Optional[IntegerLike] = None
|
||||
) -> Object:
|
||||
return pfn_to_page(PHYS_PFN(prog_or_addr, addr)) # type: ignore
|
||||
|
||||
|
||||
@overload
|
||||
def phys_to_virt(addr: Object) -> Object:
|
||||
"""
|
||||
Get the directly mapped virtual address of a physical address given as an
|
||||
:class:`.Object`.
|
||||
|
||||
:param addr: ``phys_addr_t``
|
||||
:return: ``void *``
|
||||
"""
|
||||
return pfn_to_virt(page_to_pfn(page))
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def phys_to_virt(prog: Program, addr: IntegerLike) -> Object:
|
||||
"""
|
||||
Get the directly mapped virtual address of a physical address given as a
|
||||
:class:`.Program` and an integer.
|
||||
|
||||
:param addr: Physical address.
|
||||
:return: ``void *``
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
def phys_to_virt( # type: ignore # Need positional-only arguments.
|
||||
prog_or_addr: Union[Program, Object], addr: Optional[IntegerLike] = None
|
||||
):
|
||||
if addr is None:
|
||||
assert isinstance(prog_or_addr, Object)
|
||||
prog = prog_or_addr.prog_
|
||||
addr = prog_or_addr
|
||||
else:
|
||||
assert isinstance(prog_or_addr, Program)
|
||||
prog = prog_or_addr
|
||||
return cast("void *", addr + prog["PAGE_OFFSET"])
|
||||
|
||||
|
||||
@overload
|
||||
@ -219,6 +332,73 @@ def virt_to_page( # type: ignore # Need positional-only arguments.
|
||||
return pfn_to_page(virt_to_pfn(prog_or_addr, addr)) # type: ignore[arg-type]
|
||||
|
||||
|
||||
@overload
|
||||
def virt_to_pfn(addr: Object) -> Object:
|
||||
"""
|
||||
Get the page frame number (PFN) of a directly mapped virtual address given
|
||||
as an :class:`.Object`.
|
||||
|
||||
:param addr: ``void *``
|
||||
:return: ``unsigned long``
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def virt_to_pfn(prog: Program, addr: IntegerLike) -> Object:
|
||||
"""
|
||||
Get the page frame number (PFN) of a directly mapped virtual address given
|
||||
as a :class:`.Program` and an integer.
|
||||
|
||||
:param addr: Virtual address.
|
||||
:return: ``unsigned long``
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
def virt_to_pfn( # type: ignore # Need positional-only arguments.
|
||||
prog_or_addr: Union[Program, Object], addr: Optional[IntegerLike] = None
|
||||
) -> Object:
|
||||
return PHYS_PFN(virt_to_phys(prog_or_addr, addr)) # type: ignore
|
||||
|
||||
|
||||
@overload
|
||||
def virt_to_phys(addr: Object) -> Object:
|
||||
"""
|
||||
Get the physical address of a directly mapped virtual address given as an
|
||||
:class:`.Object`.
|
||||
|
||||
:param addr: ``void *``
|
||||
:return: ``phys_addr_t``
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def virt_to_phys(prog: Program, addr: IntegerLike) -> Object:
|
||||
"""
|
||||
Get the physical address of a directly mapped virtual address given as a
|
||||
:class:`.Program` and an integer.
|
||||
|
||||
:param addr: Virtual address.
|
||||
:return: ``phys_addr_t``
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
def virt_to_phys( # type: ignore # Need positional-only arguments.
|
||||
prog_or_addr: Union[Program, Object], addr: Optional[IntegerLike] = None
|
||||
) -> Object:
|
||||
if addr is None:
|
||||
assert isinstance(prog_or_addr, Object)
|
||||
prog = prog_or_addr.prog_
|
||||
addr = prog_or_addr
|
||||
else:
|
||||
assert isinstance(prog_or_addr, Program)
|
||||
prog = prog_or_addr
|
||||
return cast("unsigned long", addr - prog["PAGE_OFFSET"])
|
||||
|
||||
|
||||
def access_process_vm(task: Object, address: IntegerLike, size: IntegerLike) -> bytes:
|
||||
"""
|
||||
Read memory from a task's virtual address space.
|
||||
|
@ -12,17 +12,23 @@ import unittest
|
||||
|
||||
from drgn import FaultError
|
||||
from drgn.helpers.linux.mm import (
|
||||
PFN_PHYS,
|
||||
PHYS_PFN,
|
||||
access_process_vm,
|
||||
access_remote_vm,
|
||||
cmdline,
|
||||
decode_page_flags,
|
||||
environ,
|
||||
page_to_pfn,
|
||||
page_to_phys,
|
||||
page_to_virt,
|
||||
pfn_to_page,
|
||||
pfn_to_virt,
|
||||
phys_to_page,
|
||||
phys_to_virt,
|
||||
virt_to_page,
|
||||
virt_to_pfn,
|
||||
virt_to_phys,
|
||||
)
|
||||
from drgn.helpers.linux.pid import find_task
|
||||
from tests.linux_kernel import (
|
||||
@ -70,6 +76,20 @@ class TestMm(LinuxKernelTestCase):
|
||||
page = pfn_to_page(self.prog, pfns[0])
|
||||
self.assertIn("PG_swapbacked", decode_page_flags(page))
|
||||
|
||||
@skip_unless_have_full_mm_support
|
||||
@skip_unless_have_test_kmod
|
||||
def test_PFN_PHYS(self):
|
||||
self.assertEqual(
|
||||
PFN_PHYS(self.prog["drgn_test_pfn"]), self.prog["drgn_test_pa"]
|
||||
)
|
||||
|
||||
@skip_unless_have_full_mm_support
|
||||
@skip_unless_have_test_kmod
|
||||
def test_PHYS_PFN(self):
|
||||
self.assertEqual(
|
||||
PHYS_PFN(self.prog["drgn_test_pa"]), self.prog["drgn_test_pfn"]
|
||||
)
|
||||
|
||||
@skip_unless_have_full_mm_support
|
||||
@skip_unless_have_test_kmod
|
||||
def test_page_to_pfn(self):
|
||||
@ -77,6 +97,13 @@ class TestMm(LinuxKernelTestCase):
|
||||
page_to_pfn(self.prog["drgn_test_page"]), self.prog["drgn_test_pfn"]
|
||||
)
|
||||
|
||||
@skip_unless_have_full_mm_support
|
||||
@skip_unless_have_test_kmod
|
||||
def test_page_to_phys(self):
|
||||
self.assertEqual(
|
||||
page_to_phys(self.prog["drgn_test_page"]), self.prog["drgn_test_pa"]
|
||||
)
|
||||
|
||||
@skip_unless_have_full_mm_support
|
||||
@skip_unless_have_test_kmod
|
||||
def test_page_to_virt(self):
|
||||
@ -98,6 +125,20 @@ class TestMm(LinuxKernelTestCase):
|
||||
pfn_to_virt(self.prog["drgn_test_pfn"]), self.prog["drgn_test_va"]
|
||||
)
|
||||
|
||||
@skip_unless_have_full_mm_support
|
||||
@skip_unless_have_test_kmod
|
||||
def test_phys_to_page(self):
|
||||
self.assertEqual(
|
||||
phys_to_page(self.prog["drgn_test_pa"]), self.prog["drgn_test_page"]
|
||||
)
|
||||
|
||||
@skip_unless_have_full_mm_support
|
||||
@skip_unless_have_test_kmod
|
||||
def test_phys_to_virt(self):
|
||||
self.assertEqual(
|
||||
phys_to_virt(self.prog["drgn_test_pa"]), self.prog["drgn_test_va"]
|
||||
)
|
||||
|
||||
@skip_unless_have_full_mm_support
|
||||
@skip_unless_have_test_kmod
|
||||
def test_virt_to_page(self):
|
||||
@ -112,6 +153,13 @@ class TestMm(LinuxKernelTestCase):
|
||||
virt_to_pfn(self.prog["drgn_test_va"]), self.prog["drgn_test_pfn"]
|
||||
)
|
||||
|
||||
@skip_unless_have_full_mm_support
|
||||
@skip_unless_have_test_kmod
|
||||
def test_virt_to_phys(self):
|
||||
self.assertEqual(
|
||||
virt_to_phys(self.prog["drgn_test_va"]), self.prog["drgn_test_pa"]
|
||||
)
|
||||
|
||||
def test_read_physical(self):
|
||||
with self._pages() as (map, _, pfns):
|
||||
for i, pfn in enumerate(pfns):
|
||||
|
Loading…
Reference in New Issue
Block a user