Depuis la version 3.2 du noyau. Vous pouvez utiliser l'appel système process_vm_readv pour lire la mémoire du processus sans interruption.
ssize_t process_vm_readv(pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags);
Ces appels système transfèrent des données entre l'espace d'adressage du processus appelant ("le processus local") et le processus identifié par pid ("le processus distant"). Les données se déplacent directement entre les espaces d'adressage des deux processus, sans passer par l'espace noyau.
Pour le processus 1234, vous pouvez obtenir sa carte mémoire en lisant séquentiellement /proc/1234/maps
(un pseudo-fichier textuel) et lire la mémoire virtuelle par ex. read(2)-ing ou mmap(2)-ing segments appropriés du /proc/1234/mem
pseudo-fichier fragmenté.
Cependant, je crois que vous ne pouvez pas éviter une sorte de synchronisation (peut-être avec ptrace(2), comme gdb
fait), puisque le processus 1234 peut (et fait) modifier son espace d'adressage à tout moment (avec mmap
&appels système associés).
La situation est différente si le processus surveillé 1234 n'est pas arbitraire, mais si vous pouviez l'améliorer pour communiquer d'une manière ou d'une autre avec le processus de surveillance.
Je ne suis pas sûr de comprendre pourquoi tu demandes ça. Et gdb
est capable de watch
un endroit sans arrêter le processus.
Si vous avez un accès root et que vous êtes sur un système Linux, vous pouvez utiliser le script Linux suivant (adapté de l'excellente réponse unix.stackexchange.com de Gilles et de la réponse donnée à l'origine dans la question ci-dessus mais incluant les erreurs de syntaxe et n'étant pas pythonic) :
#!/usr/bin/env python
import re
import sys
def print_memory_of_pid(pid, only_writable=True):
"""
Run as root, take an integer PID and return the contents of memory to STDOUT
"""
memory_permissions = 'rw' if only_writable else 'r-'
sys.stderr.write("PID = %d" % pid)
with open("/proc/%d/maps" % pid, 'r') as maps_file:
with open("/proc/%d/mem" % pid, 'r', 0) as mem_file:
for line in maps_file.readlines(): # for each mapped region
m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r][-w])', line)
if m.group(3) == memory_permissions:
sys.stderr.write("\nOK : \n" + line+"\n")
start = int(m.group(1), 16)
if start > 0xFFFFFFFFFFFF:
continue
end = int(m.group(2), 16)
sys.stderr.write( "start = " + str(start) + "\n")
mem_file.seek(start) # seek to region start
chunk = mem_file.read(end - start) # read region contents
print chunk, # dump contents to standard output
else:
sys.stderr.write("\nPASS : \n" + line+"\n")
if __name__ == '__main__': # Execute this code when run from the commandline.
try:
assert len(sys.argv) == 2, "Provide exactly 1 PID (process ID)"
pid = int(sys.argv[1])
print_memory_of_pid(pid)
except (AssertionError, ValueError) as e:
print "Please provide 1 PID as a commandline argument."
print "You entered: %s" % ' '.join(sys.argv)
raise e
Si vous enregistrez ceci sous write_mem.py, vous pouvez l'exécuter (avec python2.6 ou 2.7) ou au début de python2.5 (si vous ajoutez from __future__ import with_statement
) comme :
sudo python write_mem.py 1234 > pid1234_memory_dump
pour vider la mémoire pid1234 dans le fichier pid1234_memory_dump.