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

本文介绍了如何通过内核的/proc/pid/pagemap接口来查看进程的页表信息,从而将虚拟地址转换为物理地址。详细解释了pagemap文件中的位字段含义,并通过示例展示了如何利用该接口确定进程间共享库的物理地址一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内核文档: 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!\n pagemap PID VIRTUAL_ADDRESS\n");
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 != '\0'
以下是一个简单的C++代码示例,用于将/proc/pid/pagemap映射到内存中并获取一个地址以判断其是否为物理地址虚拟地址: ```c++ #include <iostream> #include <fstream> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> using namespace std; int main() { // 获取进程ID pid_t pid = getpid(); // 构建/proc/pid/pagemap文件的路径 char path[100]; sprintf(path, "/proc/%d/pagemap", pid); // 打开/proc/pid/pagemap文件 int fd = open(path, O_RDONLY); if (fd == -1) { cout << "无法打开/proc/pid/pagemap文件" << endl; return -1; } // 获取一个地址,这里以0地址为例 void *addr = (void*)0; // 计算地址在pagemap中的索引 off_t offset = (off_t)addr / getpagesize() * sizeof(uint64_t); // 将pagemap映射到内存中 uint64_t *pagemap = (uint64_t*)mmap(NULL, sizeof(uint64_t), PROT_READ, MAP_PRIVATE, fd, offset); if (pagemap == MAP_FAILED) { cout << "无法映射/proc/pid/pagemap文件" << endl; return -1; } // 判断是否为物理地址 if (*pagemap & (1ULL<<63)) { cout << "物理地址" << endl; } else { cout << "虚拟地址" << endl; } // 解除pagemap的映射 munmap(pagemap, sizeof(uint64_t)); // 关闭/proc/pid/pagemap文件 close(fd); return 0; } ``` 在上面的代码中,我们首先获取当前进程的ID,然后构建/proc/pid/pagemap文件的路径。接着打开该文件,并获取一个地址(这里以0地址为例)。然后我们计算该地址在pagemap中的索引,并将pagemap映射到内存中。我们可以通过判断pagemap中的第63位来确定该地址是物理地址还是虚拟地址。最后我们需要解除pagemap的映射并关闭/proc/pid/pagemap文件。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值