Le script python rapide et sale suivant vide la mémoire d'un processus vers stdout. Cela a pour effet secondaire de charger toute page échangée ou fichier mappé. Appelez-le comme cat_proc_mem 123 456 789
où les arguments sont des ID de processus.
Ce script est complètement spécifique à Linux. Il peut être adaptable à d'autres systèmes avec un /proc
similaire structure (Solaris ?), mais oubliez de l'exécuter, par ex. *BSD. Même sous Linux, vous devrez peut-être modifier la définition de c_pid_t
et les valeurs de PTRACE_ATTACH
et PTRACE_DETACH
. Il s'agit d'un script de preuve de principe, et non d'un exemple de bonnes pratiques de programmation. Utilisez à vos risques et périls.
Linux rend la mémoire d'un processus disponible en tant que /proc/$pid/mem
. Seules certaines plages d'adresses sont lisibles. Ces plages peuvent être trouvées en lisant les informations de mappage de la mémoire à partir du fichier texte /proc/$pid/maps
. Le pseudo-fichier /proc/$pid/mem
ne peut pas être lu par tous les processus qui ont la permission de le lire :le processus lecteur doit avoir appelé ptrace(PTRACE_ATTACH, $pid)
.
#!/usr/bin/env python
import ctypes, re, sys
## Partial interface to ptrace(2), only for PTRACE_ATTACH and PTRACE_DETACH.
c_ptrace = ctypes.CDLL("libc.so.6").ptrace
c_pid_t = ctypes.c_int32 # This assumes pid_t is int32_t
c_ptrace.argtypes = [ctypes.c_int, c_pid_t, ctypes.c_void_p, ctypes.c_void_p]
def ptrace(attach, pid):
op = ctypes.c_int(16 if attach else 17) #PTRACE_ATTACH or PTRACE_DETACH
c_pid = c_pid_t(pid)
null = ctypes.c_void_p()
err = c_ptrace(op, c_pid, null, null)
if err != 0: raise SysError, 'ptrace', err
## Parse a line in /proc/$pid/maps. Return the boundaries of the chunk
## the read permission character.
def maps_line_range(line):
m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line)
return [int(m.group(1), 16), int(m.group(2), 16), m.group(3)]
## Dump the readable chunks of memory mapped by a process
def cat_proc_mem(pid):
## Apparently we need to ptrace(PTRACE_ATTACH, $pid) to read /proc/$pid/mem
ptrace(True, int(pid))
## Read the memory maps to see what address ranges are readable
maps_file = open("/proc/" + pid + "/maps", 'r')
ranges = map(maps_line_range, maps_file.readlines())
maps_file.close()
## Read the readable mapped ranges
mem_file = open("/proc/" + pid + "/mem", 'r', 0)
for r in ranges:
if r[2] == 'r':
mem_file.seek(r[0])
chunk = mem_file.read(r[1] - r[0])
print chunk,
mem_file.close()
## Cleanup
ptrace(False, int(pid))
if __name__ == "__main__":
for pid in sys.argv[1:]:
cat_proc_mem(pid)
Voir aussi plus d'informations sur /proc/$pid/mem
.
unswap () {
cat_proc_mem "[email protected]" >/dev/null
}
Si vous avez vraiment assez de RAM disponible, vous pouvez utiliser cette séquence (en tant que root) :
$ swapoff -a
$ swapon -a
(pour forcer le swap-in explicite de toutes vos applications)
(en supposant que vous utilisez Linux)
Juste pour être complet, GDB peut vider l'image de processus. Je n'ai pas vérifié qu'il l'annule, mais il doit --- il n'y a pas d'autre moyen de lire toute la mémoire du processus:
gdb -p $mypid
suivie par
(gdb) gcore /tmp/myprocess-core
Saved corefile /tmp/myprocess-core