Desde la versión 3.2 del kernel. Puede usar la llamada al sistema process_vm_readv para leer la memoria del proceso sin interrupción.
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);
Estas llamadas al sistema transfieren datos entre el espacio de direcciones del proceso que llama ("el proceso local") y el proceso identificado por pid ("el proceso remoto"). Los datos se mueven directamente entre los espacios de direcciones de los dos procesos, sin pasar por el espacio del kernel.
Para el proceso 1234, puede obtener su mapa de memoria leyendo secuencialmente /proc/1234/maps
(un pseudoarchivo textual) y leer la memoria virtual, p. read(2)-ing o mmap(2)-ing segmentos apropiados del /proc/1234/mem
pseudo-archivo disperso.
Sin embargo, creo que no puedes evitar algún tipo de sincronización (quizás con ptrace(2), como gdb
lo hace), ya que el proceso 1234 puede (y lo hace) alterar su espacio de direcciones en cualquier momento (con mmap
y llamadas al sistema relacionadas).
La situación es diferente si el proceso monitoreado 1234 no es arbitrario, pero si podría mejorarlo para comunicarse de alguna manera con el proceso de monitoreo.
No estoy seguro de entender por qué preguntas esto. Y gdb
es capaz de watch
alguna ubicación sin detener el proceso.
Si tiene acceso de root y está en un sistema Linux, puede usar el siguiente script de Linux (adaptado de la excelente respuesta de Gilles en unix.stackexchange.com y la respuesta dada originalmente en la pregunta anterior, pero que incluye SyntaxErrors y no es 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 guarda esto como write_mem.py, puede ejecutar esto (con python2.6 o 2.7) o temprano en python2.5 (si agrega from __future__ import with_statement
) como:
sudo python write_mem.py 1234 > pid1234_memory_dump
para volcar la memoria pid1234 en el archivo pid1234_memory_dump.