123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960 |
- #!/usr/bin/env python3
- # Copyright 2021 The Chromium Authors. All rights reserved.
- # Use of this source code is governed by a BSD-style license that can be
- # found in the LICENSE file.
- """Extract physical addresses (PFNs) from /proc/PID/pagemap files.
- This can be useful, for example, to compare whether two addresses from
- potentially two different processes map to the same physical page. The virtual
- addresses required for this script can be obtained from log messages, while the
- pagemap files can be copied or fetched from an Android device using `adb pull`.
- """
- import argparse
- import logging
- import os
- import struct
- import sys
- _BYTES_PER_PAGEMAP_VALUE = 8
- _BYTES_PER_OS_PAGE = 4096
- _VIRTUAL_TO_PAGEMAP_OFFSET = _BYTES_PER_OS_PAGE // _BYTES_PER_PAGEMAP_VALUE
- _MASK_PRESENT = 1 << 63
- _MASK_PFN = (1 << 55) - 1
- def PrintPfn(fd, vaddr):
- os.lseek(fd, vaddr // _VIRTUAL_TO_PAGEMAP_OFFSET, os.SEEK_SET)
- buf = os.read(fd, _BYTES_PER_PAGEMAP_VALUE)
- if len(buf) < _BYTES_PER_PAGEMAP_VALUE:
- logging.error('Could not retrieve the pagemap entry')
- return False
- pagemap_values = struct.unpack(
- '=%dQ' % (len(buf) // _BYTES_PER_PAGEMAP_VALUE), buf)
- for pagemap_value in pagemap_values:
- if pagemap_value & _MASK_PRESENT:
- print(hex(pagemap_value & _MASK_PFN))
- else:
- logging.error('Page not present: %s', hex(vaddr))
- return False
- return True
- def main():
- logging.getLogger().setLevel(logging.INFO)
- parser = argparse.ArgumentParser()
- parser.add_argument('--pagemap-file',
- required=True,
- help='Path to a saved /proc/pid/pagemap file.')
- parser.add_argument('--vaddr',
- required=True,
- help='Virtual address (in hex) to inspect.')
- args = parser.parse_args()
- fd = os.open(args.pagemap_file, os.O_RDONLY)
- if not PrintPfn(fd, int(args.vaddr, 16)):
- return 1
- return 0
- if __name__ == '__main__':
- sys.exit(main())
|