一个进程的内存是否加载到物理内存,系统是有记录的。记录文件就是/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);
|