墙外通道:http://fivelinesofcode.blogspot.com/2014/03/how-to-translate-virtual-to-physical.html
I currently work on a project where I need to make translations for virtual addresses of user-level application to physical addresses in Linux. I implemented my own system call to do that, but had hard times with verifying the results I'm getting.
Later I found out that in newer kernels there is a really nice virtual file in the /proc file system to get this information. I tried to cat it, doing cat /proc/self/pagemap, and got terrible binary output in my console.
So, it looks like working with this file is not such a pleasant experience. It's a binary file with all that it implies. I found couple of scripts that access this file and provide you with a nice text result, but unfortunately those were written in perl and ruby, and I needed to run it on very minimalistic embedded system. I needed something that fits into a single binary.
Long story short, I decided to bite the bullet and write a tool in C. My contribution might be helpful for someone, that's why I'm sharing this code.
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <assert.h> #include <errno.h> #include <stdint.h> #define PAGEMAP_ENTRY 8 #define GET_BIT(X,Y) (X & ((uint64_t)1<<Y)) >> Y #define GET_PFN(X) X & 0x7FFFFFFFFFFFFF const int __endian_bit = 1; #define is_bigendian() ( (*(char*)&__endian_bit) == 0 ) int i, c, pid, status; unsigned long virt_addr; uint64_t read_val, file_offset; char path_buf [0x100] = {}; FILE * f; char *end; int read_pagemap(char * path_buf, unsigned long virt_addr); int main(int argc, char ** argv){ //printf("%lu ", GET_BIT(0xA680000000000000, 63)); //return 0; if(argc!=3){ printf("Argument number is not correct! pagemap PID VIRTUAL_ADDRESS "); return -1; } if(!memcmp(argv[1],"self",sizeof("self"))){ sprintf(path_buf, "/proc/self/pagemap"); pid = -1; } else{ pid = strtol(argv[1],&end, 10); if (end == argv[1] || *end != '