print_pagemap_pfn.py 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. #!/usr/bin/env python3
  2. # Copyright 2021 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """Extract physical addresses (PFNs) from /proc/PID/pagemap files.
  6. This can be useful, for example, to compare whether two addresses from
  7. potentially two different processes map to the same physical page. The virtual
  8. addresses required for this script can be obtained from log messages, while the
  9. pagemap files can be copied or fetched from an Android device using `adb pull`.
  10. """
  11. import argparse
  12. import logging
  13. import os
  14. import struct
  15. import sys
  16. _BYTES_PER_PAGEMAP_VALUE = 8
  17. _BYTES_PER_OS_PAGE = 4096
  18. _VIRTUAL_TO_PAGEMAP_OFFSET = _BYTES_PER_OS_PAGE // _BYTES_PER_PAGEMAP_VALUE
  19. _MASK_PRESENT = 1 << 63
  20. _MASK_PFN = (1 << 55) - 1
  21. def PrintPfn(fd, vaddr):
  22. os.lseek(fd, vaddr // _VIRTUAL_TO_PAGEMAP_OFFSET, os.SEEK_SET)
  23. buf = os.read(fd, _BYTES_PER_PAGEMAP_VALUE)
  24. if len(buf) < _BYTES_PER_PAGEMAP_VALUE:
  25. logging.error('Could not retrieve the pagemap entry')
  26. return False
  27. pagemap_values = struct.unpack(
  28. '=%dQ' % (len(buf) // _BYTES_PER_PAGEMAP_VALUE), buf)
  29. for pagemap_value in pagemap_values:
  30. if pagemap_value & _MASK_PRESENT:
  31. print(hex(pagemap_value & _MASK_PFN))
  32. else:
  33. logging.error('Page not present: %s', hex(vaddr))
  34. return False
  35. return True
  36. def main():
  37. logging.getLogger().setLevel(logging.INFO)
  38. parser = argparse.ArgumentParser()
  39. parser.add_argument('--pagemap-file',
  40. required=True,
  41. help='Path to a saved /proc/pid/pagemap file.')
  42. parser.add_argument('--vaddr',
  43. required=True,
  44. help='Virtual address (in hex) to inspect.')
  45. args = parser.parse_args()
  46. fd = os.open(args.pagemap_file, os.O_RDONLY)
  47. if not PrintPfn(fd, int(args.vaddr, 16)):
  48. return 1
  49. return 0
  50. if __name__ == '__main__':
  51. sys.exit(main())