Processar páginas de memória
@ G-Man está correto que o sistema de arquivos /proc
pode lhe fornecer as informações. E ele também está correto que /proc/<pid>/maps
dará algumas informações. Por exemplo, aqui está um pouco de /proc/<pid>/maps
output:
7f2c09a0c000-7f2c09a0d000 r--p 00022000 08:03 3804420 /usr/lib/ld-2.24.so
7f2c09a0d000-7f2c09a0e000 rw-p 00023000 08:03 3804420 /usr/lib/ld-2.24.so
7f2c09a0e000-7f2c09a0f000 rw-p 00000000 00:00 0
7ffc46cf9000-7ffc46d1a000 rw-p 00000000 00:00 0 [stack]
7ffc46d86000-7ffc46d88000 r--p 00000000 00:00 0 [vvar]
7ffc46d88000-7ffc46d8a000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
O problema aqui é que obtemos as páginas virtuais nesta saída e nenhuma relação com as páginas físicas pode ser encontrada a partir daí.
Por outro lado, /proc
também possui um /proc/<pid>/pagemap
, que é um mapeamento da memória virtual para as páginas de memória reais (incluindo swap). Vamos ver o que o man 5 proc
nos diz sobre isso:
/proc/[pid]/pagemap (since Linux 2.6.25)
This file shows the mapping of each of the process's virtual pages into physical page frames or swap area.
It contains one 64-bit value for each virtual page, with the bits set as follows:
63 If set, the page is present in RAM.
62 If set, the page is in swap space
61 (since Linux 3.5)
The page is a file-mapped page or a shared anonymous page.
60-56 (since Linux 3.11)
Zero
55 (Since Linux 3.11)
PTE is soft-dirty (see the kernel source file Documentation/vm/soft-dirty.txt).
54-0 If the page is present in RAM (bit 63), then these bits provide the page frame number, which can
be used to index /proc/kpageflags and /proc/kpagecount. If the page is present in swap (bit
62), then bits 4-0 give the swap type, and bits 54-5 encode the swap offset.
OK, temos um inteiro de 64 bits para cada página de memória e um monte de sinalizadores que nos informam o que a página faz. Para ler /proc/<pid>/pagemap
, precisamos de permissões de root. Além disso, o arquivo é apenas uma lista de inteiros de 64 bits, então eu vou usar:
[~]# cat /proc/950/pagemap |xxd |less
...
000020c0: 0585 0600 0000 00a0 0285 0600 0000 00a0 ................
000020d0: 0385 0600 0000 00a0 6692 0600 0000 00a0 ........f.......
000020e0: 6792 0600 0000 00a0 488e 0600 0000 00a0 g.......H.......
000020f0: 498e 0600 0000 00a0 1c93 0600 0000 00a0 I...............
00002100: c45e 0600 0000 00a0 c55e 0600 0000 00a0 .^.......^......
00002110: c65e 0600 0000 00a0 c75e 0600 0000 00a0 .^.......^......
00002120: c85e 0600 0000 00a0 c95e 0600 0000 00a0 .^.......^......
00002130: ca5e 0600 0000 00a0 f05e 0600 0000 00a0 .^.......^......
00002140: f15e 0600 0000 00a0 f25e 0600 0000 00a0 .^.......^......
00002150: f35e 0600 0000 00a0 f45e 0600 0000 00a0 .^.......^......
00002160: f55e 0600 0000 00a0 f65e 0600 0000 00a0 .^.......^......
...
000035c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000035d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000035e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000035f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00003600: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00003610: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00003620: 0000 0000 0000 0000 c460 0400 0000 0081 .........'......
00003630: f02a 0400 0000 0081 b6f7 0100 0000 0081 .*..............
00003640: 804b 0300 0000 0081 0770 0400 0000 0081 .K.......p......
00003650: 2844 0500 0000 0081 3d9b 0400 0000 0081 (D......=.......
00003660: 192f 0400 0000 0081 813c 0300 0000 0081 ./.......<......
00003670: b1f7 0100 0000 0081 40a7 0300 0000 0081 ........@.......
00003680: ee58 0400 0000 0081 97c8 0300 0000 0081 .X..............
00003690: 9afa 0100 0000 0081 0000 0000 0000 0000 ................
000036a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000036b0: 4d80 0400 0000 0081 0bb7 0400 0000 0081 M...............
000036c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
...
A saída acima é apenas do meu processo de shell. Há muita saída porque é um mapa de toda a memória do processo. E todas as partes que não estão mapeadas no momento simplesmente contêm zeros.
Vamos pegar a página c85e 0600 0000 00a0
(em 0x2120 da saída xxd) que está em uma máquina little-endian, então vamos invertê-la para a000 0000 0006 5ec8
. Como o primeiro byte é 0xa0, o bit 63 é definido, portanto, é uma página na RAM. A numeração de bits é baseada em zero, então o bit 63 é o último bit (não o bit 64). E os últimos 54 bits são 0x65ec8 (com um monte de zeros na frente), que é o índice da página atual.
Agora, a página 2844 0500 0000 0081
(em 0x3650 da saída xxd) pode ser invertida para 8100 0000 0005 4428
. Lá, o primeiro byte é 0x81 e seu bit 62 é definido, portanto, é uma página no SWAP. Não tenho certeza sobre o motivo que o bit 56 está definido: talvez algo indocumentado ou um erro no homem (que observa o bit 55). No entanto, os bits 54-0 nos dizem outras coisas: 0x28 nos dá o tipo de swap, ou seja, 0x8; e o deslocamento está em 0x5442 >> 1
(porque o último bit faz parte do tipo de troca), ou seja, 0x2a21.
(Espero não ter estragado o cálculo flag / little-endian desta vez. Eu estraguei a contagem de bits na primeira vez que escrevi isso.)
Página para processar o problema
O único problema com o acima é que isso é um mapa do processo - > página. Não é realmente página - > processo. Mas você pode pesquisar todos os /proc/kpagecount
para ver todas as páginas atualmente usadas (tudo o que tiver uma contagem > 0, que é outra lista de inteiros de 64 bits, um por página). Em seguida, pesquise todos os diretórios proc/<pid>
. Isso se torna um problema se os processos começarem e terminarem rapidamente, para que você não encontre o /proc/<pid>
. Mas isso não deve ser importante, a menos que você esteja tentando impor políticas de segurança ou algo semelhante. (nunca confie em /proc
para políticas de segurança, porque as coisas mudam muito rápido).
Extra
Agora você pode usar o índice 0x54428 para procurar os sinalizadores de página em /proc/kpageflags
, será o inteiro 0x54428th
64bit. Isso também é descrito em man 5 proc
.