利用/proc/pid/pagemap将虚拟地址转换为物理地址

内核文档: Documentation/vm/pagemap.txt

pagemap is a new (as of 2.6.25) set of interfaces in the kernel that allow
userspace programs to examine the page tables and related information by
reading files in /proc.

There are four components to pagemap:

 * /proc/pid/pagemap.  This file lets a userspace process find out which
   physical frame each virtual page is mapped to.  It contains one 64-bit
   value for each virtual page, containing the following data (from
   fs/proc/task_mmu.c, above pagemap_read):

    * Bits 0-54  page frame number (PFN) if present
    * Bits 0-4   swap type if swapped
    * Bits 5-54  swap offset if swapped
    * Bit  55    pte is soft-dirty (see Documentation/vm/soft-dirty.txt)
    * Bit  56    page exclusively mapped (since 4.2)
    * Bits 57-60 zero
    * Bit  61    page is file-page or shared-anon (since 3.5)
    * Bit  62    page swapped
    * Bit  63    page present

   Since Linux 4.0 only users with the CAP_SYS_ADMIN capability can get PFNs.
   In 4.0 and 4.1 opens by unprivileged fail with -EPERM.  Starting from
   4.2 the PFN field is zeroed if the user does not have CAP_SYS_ADMIN.
   Reason: information about PFNs helps in exploiting Rowhammer vulnerability.

   If the page is not present but in swap, then the PFN contains an
   encoding of the swap file number and the page's offset into the
   swap. Unmapped pages return a null PFN. This allows determining
   precisely which pages are mapped (or in swap) and comparing mapped
   pages between processes.

   Efficient users of this interface will use /proc/pid/maps to
   determine which areas of memory are actually mapped and llseek to
   skip over unmapped regions.


 下面是一个工具:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <assert.h>
 5 #include <errno.h>
 6 #include <stdint.h>
 7 #include <string.h>
 8 
 9 #define PAGEMAP_ENTRY 8
10 #define GET_BIT(X,Y) (X & ((uint64_t)1<<Y)) >> Y
11 #define GET_PFN(X) X & 0x7FFFFFFFFFFFFF
12 
13 const int __endian_bit = 1;
14 #define is_bigendian() ( (*(char*)&__endian_bit) == 0 )
15 
16 int i, c, pid, status;
17 unsigned long virt_addr; 
18 uint64_t read_val, file_offset, page_size;
19 char path_buf [0x100] = {};
20 FILE * f;
21 char *end;
22 
23 int read_pagemap(char * path_buf, unsigned long virt_addr);
24 
25 int main(int argc, char ** argv){
26     if(argc!=3){
27         printf("Argument number is not correct!
 pagemap PID VIRTUAL_ADDRESS
");
28         return -1;
29     }
30     if(!memcmp(argv[1],"self",sizeof("self"))){
31         sprintf(path_buf, "/proc/self/pagemap");
32         pid = -1;
33     }
34     else{
35         pid = strtol(argv[1],&end, 10);
36         if (end == argv[1] || *end != '