一個進程的內存是否加載到物理內存,系統是有記錄的。記錄文件就是/proc/$pid/pagemap
pagemap和內存地址的對應關係:
file_offset = virt_addr / PAGE_SIZE * PAGEMAP_ENTRY;
8字節的PAGEMAP_ENTRY用於記錄這一頁的內存映射信息:
* 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
完整代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
const int __endian_bit = 1 ; #define PAGEMAP_ENTRY 8 #define is_bigendian () ( (*( char *)&__endian_bit) == 0 ) #define GET_BIT (X,Y) (X & ((uint64_t)1<<Y)) >> Y #define GET_PFN (X) X & 0x7FFFFFFFFFFFFF char page_path [0xff] = {0}; snprintf(page_path, sizeof (page_path ) - 1 , "/proc/%u/pagemap" , getpid()); FILE * f = fopen (page_path, "rb" ); //open(page_path, O_RDONLY); if (! f) return -1; unsigned long file_offset = addr / PAGE_SIZE * PAGEMAP_ENTRY; int status = fseek (f, file_offset, SEEK_SET); unsigned char c_buf [PAGEMAP_ENTRY]; for ( int i = 0; i < PAGEMAP_ENTRY; i++) { int c = getc (f); if ( c == EOF) return -1; if (is_bigendian()) c_buf[ i] = c; else c_buf [PAGEMAP_ENTRY - i -1] = c; } unsigned long long read_val = 0; for ( int i = 0; i < PAGEMAP_ENTRY; i++) { read_val = ( read_val << 8) + c_buf[ i]; } if (GET_BIT( read_val, 63)) printf ( "PFN: 0x%llx" ,(unsigned long long ) GET_PFN(read_val)); else printf ( "page not present" ); if (GET_BIT( read_val, 62)) printf ( "Result: 0x%llx" , read_val ); fclose (f);
|