Source code for crash.commands.vtop
#!/usr/bin/python3
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
"""
SUMMARY
-------
Translate virtual addresses to physical addresses
::
vtop [-c [pid | taskp]] [-u|-k] address ...
DESCRIPTION
-----------
This command translates a user or kernel virtual address to its physical
address. Also displayed is the PTE translation, the vm_area_struct data
for user virtual addresses, the mem_map page data associated with the
physical page, and the swap location or file location if the page is
not mapped. The -u and -k options specify that the address is a user
or kernel virtual address; -u and -k are not necessary on processors whose
virtual addresses self-define themselves as user or kernel. User addresses
are translated with respect to the current context unless the -c option
is used. Kernel virtual addresses are translated using the swapper_pg_dir
as the base page directory unless the -c option is used.
-u The address is a user virtual address; only required
on processors with overlapping user and kernel virtual
address spaces.
-k The address is a kernel virtual address; only required
on processors with overlapping user and kernel virtual
address spaces.
-c pid-or-taskp Translate the virtual address from the page directory
of the specified PID or hexadecimal task_struct pointer.
However, if this command is invoked from "foreach vtop",
the pid or taskp argument should NOT be entered; the
address will be translated using the page directory of
each task specified by "foreach".
``address`` A hexadecimal user or kernel virtual address.
NOTE
----
Although the ``-c`` option is referenced in the documentation, it
is currently unimplemented and will cause a command error.
EXAMPLES
--------
Translate user virtual address 80b4000:
::
py-crash> vtop 80b4000
VIRTUAL PHYSICAL
80b4000 660f000
PAGE DIRECTORY: c37f0000
PGD: c37f0080 => e0d067
PMD: c37f0080 => e0d067
PTE: c0e0d2d0 => 660f067
PAGE: 660f000
PTE PHYSICAL FLAGS
660f067 660f000 (PRESENT|RW|USER|ACCESSED|DIRTY)
VMA START END FLAGS FILE
c773daa0 80b4000 810c000 77
PAGE PHYSICAL INODE OFFSET CNT FLAGS
c0393258 660f000 0 17000 1 uptodate
Translate kernel virtual address c806e000, first using swapper_pg_dir
as the page directory base, and secondly, using the page table base
of PID 1359:
::
py-crash> vtop c806e000
VIRTUAL PHYSICAL
c806e000 2216000
PAGE DIRECTORY: c0101000
PGD: c0101c80 => 94063
PMD: c0101c80 => 94063
PTE: c00941b8 => 2216063
PAGE: 2216000
PTE PHYSICAL FLAGS
2216063 2216000 (PRESENT|RW|ACCESSED|DIRTY)
PAGE PHYSICAL INODE OFFSET CNT FLAGS
c02e9370 2216000 0 0 1
py-crash> vtop -c 1359 c806e000
VIRTUAL PHYSICAL
c806e000 2216000
PAGE DIRECTORY: c5caf000
PGD: c5cafc80 => 94063
PMD: c5cafc80 => 94063
PTE: c00941b8 => 2216063
PAGE: 2216000
PTE PHYSICAL FLAGS
2216063 2216000 (PRESENT|RW|ACCESSED|DIRTY)
PAGE PHYSICAL INODE OFFSET CNT FLAGS
c02e9370 2216000 0 0 1
Determine swap location of user virtual address 40104000:
::
py-crash> vtop 40104000
VIRTUAL PHYSICAL
40104000 (not mapped)
PAGE DIRECTORY: c40d8000
PGD: c40d8400 => 6bbe067
PMD: c40d8400 => 6bbe067
PTE: c6bbe410 => 58bc00
PTE SWAP OFFSET
58bc00 /dev/sda8 22716
VMA START END FLAGS FILE
c7200ae0 40104000 40b08000 73
SWAP: /dev/sda8 OFFSET: 22716
"""
import argparse
import addrxlat
import addrxlat.exceptions
from crash.commands import Command, ArgumentParser
from crash.commands import CommandError, CommandLineError
from crash.addrxlat import CrashAddressTranslation
[docs]class LinuxPGT:
table_names = ('PTE', 'PMD', 'PUD', 'PGD')
def __init__(self, ctx: addrxlat.Context, sys: addrxlat.System) -> None:
self.context = ctx
self.system = sys
self.step: addrxlat.Step
self.table = self.table_names[0]
self.ptr: addrxlat.FullAddress
self.note = ''
[docs] def begin(self, addr: int) -> bool:
meth = self.system.get_map(addrxlat.SYS_MAP_HW).search(addr)
if meth == addrxlat.SYS_METH_NONE:
meth = self.system.get_map(addrxlat.SYS_MAP_KV_PHYS).search(addr)
if meth == addrxlat.SYS_METH_NONE:
return False
self.step = addrxlat.Step(self.context, self.system)
self.step.meth = self.system.get_meth(meth)
self.step.launch(addr)
return True
[docs] def next(self) -> bool:
if self.step.remain <= 1:
return False
level = self.step.remain - 1
self.table = self.table_names[level - 1]
# pylint is picking up base as _addrxlat.FullAddress instead of
# addrxlat.FullAddress
# pylint: disable=no-member
self.ptr = self.step.base.copy()
# self.step.idx is a 9-tuple
# pylint: disable=unsubscriptable-object
self.ptr.addr += self.step.idx[level] * self.step.elemsz
self.note = ''
try:
self.step.step()
except addrxlat.exceptions.NotPresentError: # pylint: disable=no-member
self.note = ' (NOT PRESENT)'
self.step.remain = 0
return True
[docs] def address(self) -> str:
return '{:16x}'.format(self.ptr.addr)
[docs] def value(self) -> str:
return '{:x}{}'.format(self.step.raw, self.note)
[docs]class LinuxNonAutoPGT(LinuxPGT):
[docs] def address(self) -> str:
addr = super().address() + ' [machine], '
tmp = self.ptr.copy()
try:
tmp.conv(addrxlat.KPHYSADDR, self.context, self.system)
return addr + '{:x} [phys]'.format(tmp.addr)
except (addrxlat.exceptions.NotPresentError, # pylint: disable=no-member
addrxlat.exceptions.NoDataError): # pylint: disable=no-member
return addr + 'N/A'
class _Parser(ArgumentParser):
def format_usage(self) -> str:
return "vtop [-c [pid | taskp]] [-u|-k] address ...\n"
[docs]class VTOPCommand(Command):
"""convert virtual address to physical"""
def __init__(self) -> None:
parser = _Parser(prog="vtop")
group = parser.add_mutually_exclusive_group()
group.add_argument('-u', action='store_true', default=False)
group.add_argument('-k', action='store_true', default=False)
parser.add_argument('-c', action='store_true', default=False)
parser.add_argument('args', nargs=argparse.ONE_OR_MORE)
super().__init__("vtop", parser)
[docs] def execute(self, args: argparse.Namespace) -> None:
if args.c:
raise CommandError("support for the -c argument is unimplemented")
trans = CrashAddressTranslation()
# Silly mypy bug means the base class needs come first
if not trans.is_non_auto:
pgt = LinuxPGT(trans.context, trans.system)
else:
pgt = LinuxNonAutoPGT(trans.context, trans.system)
for addr in args.args:
try:
addr = int(addr, 16)
except ValueError:
raise CommandLineError(f"{addr} is not a hex address")
fulladdr = addrxlat.FullAddress(addrxlat.KVADDR, addr)
print('{:16} {:16}'.format('VIRTUAL', 'PHYSICAL'))
try:
fulladdr.conv(addrxlat.KPHYSADDR, trans.context, trans.system)
phys = '{:x}'.format(fulladdr.addr)
except addrxlat.BaseException:
phys = '---'
print('{:<16x} {:<16}\n'.format(addr, phys))
if pgt.begin(addr):
while pgt.next():
print('{:>4}: {} => {}'.format(pgt.table, pgt.address(), pgt.value()))
if pgt.step.remain:
pgt.ptr = pgt.step.base
print('PAGE: {}'.format(pgt.address()))
else:
print('NO TRANSLATION')
print()
VTOPCommand()