Dalla versione 3.2 del kernel. Puoi utilizzare la chiamata di sistema process_vm_readv per leggere la memoria del processo senza interruzioni.
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);
Queste chiamate di sistema trasferiscono i dati tra lo spazio degli indirizzi del processo chiamante ("il processo locale") e il processo identificato da pid ("il processo remoto"). I dati si spostano direttamente tra gli spazi degli indirizzi dei due processi, senza passare attraverso lo spazio del kernel.
Per il processo 1234 puoi ottenere la sua mappa di memoria leggendo in sequenza /proc/1234/maps
(uno pseudo-file testuale) e leggere la memoria virtuale ad es. read(2)-ing o mmap(2)-ing segmenti appropriati di /proc/1234/mem
pseudo-file sparse.
Tuttavia, credo che tu non possa evitare un qualche tipo di sincronizzazione (forse con ptrace(2), come gdb
lo fa), poiché il processo 1234 può (e lo fa) alterare il suo spazio di indirizzi in qualsiasi momento (con mmap
e chiamate di sistema correlate).
La situazione è diversa se il processo monitorato 1234 non è arbitrario, ma se potessi migliorarlo per comunicare in qualche modo con il processo monitorato.
Non sono sicuro di capire perché me lo chiedi. E gdb
è in grado di watch
qualche posizione senza interrompere il processo.
Se hai accesso root e sei su un sistema Linux, puoi usare il seguente script linux (adattato dall'eccellente risposta unix.stackexchange.com di Gilles e la risposta originariamente data nella domanda sopra ma includendo SyntaxErrors e non essendo 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
Se lo salvi come write_mem.py, puoi eseguirlo (con python2.6 o 2.7) o all'inizio di python2.5 (se aggiungi from __future__ import with_statement
) come:
sudo python write_mem.py 1234 > pid1234_memory_dump
per eseguire il dump della memoria pid1234 nel file pid1234_memory_dump.