判斷內存地址是否缺頁

一個進程的內存是否加載到物理內存,系統是有記錄的。記錄文件就是/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];
        forint 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;
        forint 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);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章