Чтение памяти жизненного процесса без его прерывания (/proc/kcore - вариант)
Я хотел бы изучить память о жизненном процессе, и когда я это сделаю, процесс не должен нарушаться - поэтому привязка gdb к процессу (который остановит его) не является вариантом.
Поэтому я хотел бы получить эту информацию от /proc/kcore (если вы знаете другой способ сделать это, пожалуйста, дайте мне знать).
Поэтому я сделал небольшой эксперимент. Я создал файл под названием TEST с только "EXTRATESTEXTRA" внутри.
Затем я открыл его с меньшим
$ less TEST
Я получил PID этого процесса с помощью
$ ps aux | grep TEST
user 7785 0.0 0.0 17944 992 pts/8 S+ 16:15 0:00 less TEST
user 7798 0.0 0.0 13584 904 pts/9 S+ 16:16 0:00 grep TEST
И затем я использовал этот script для создания дампа всех файлов:
#!/bin/bash
grep rw-p /proc/$1/maps | sed -n 's/^\([0-9a-f]*\)-\([0-9a-f]*\) .*$/\1 \2/p' | while read start stop; do gdb --batch --pid $1 -ex "dump memory $1-$start-$stop.dump 0x$start 0x$stop"; done
(я нашел его на этом сайте https://serverfault.com/info/173999/dump-a-linux-processs-memory-to-file)
$ sudo ./dump_all_pid_memory.sh 7785
После этого я искал "TRATESTEX" во всех сбрасываемых файлах:
$ grep -a -o -e '...TRATESTEX...' ./*.dump
./7785-00624000-00628000.dump:HEXTRATESTEXTRA
./7785-00b8f000-00bb0000.dump:EXTRATESTEXTRA
./7785-00b8f000-00bb0000.dump:EXTRATESTEXTRA
Итак, я пришел к выводу, что должна быть видимость этой строки где-то между 0x00624000 и 0x00628000.
Поэтому я преобразовал смещения в десятичные числа и использовал dd для получения памяти из /proc/kcore:
$ sudo dd if="/proc/kcore" of="./y.txt" skip="0" count="1638400" bs=1
К моему удивлению, файл y.txt был заполнен нулями (я не нашел строку, которую я искал в ней).
В качестве бонусного сюрприза я одновременно проверил сравнительный тест с другим тестовым файлом и обнаружил, что другая тестовая строка, которую я использовал
(оба процесса с меньшим количеством выполнялись одновременно) должны быть найдены в одном месте (демпинг и градация дали такое же смещение).
Поэтому должно быть что-то, что я не понимаю ясно.
-
Не предполагается, что /proc/pid/maps отображает смещение памяти (например: если бы он сказал, что "XXX" находится на смещении 0x10, другая программа не может использовать такое же смещение am я право? - это источник моего второго удивления)
-
Как я могу прочитать /proc/kmap, чтобы получить память, принадлежащую процессу, который я знаю pid?
EDIT - для будущих споткнеров (см. ниже):
Подводя итоги и добавьте собственные комментарии:
-/proc/pid/maps отображает части памяти. КАК ПРОЦЕСС СИДЕТЬ ЭТО (по-разному для каждого процесса, ищет сопоставление памяти в Linux), поэтому разные процессы могут использовать одну и ту же часть памяти (поскольку она выглядит с их точки зрения). Вы можете прочитать детали, указанные здесь, из /proc/pid/mem как суперпользователь (или родительский процесс, например gdb, с помощью ptrace)
- память в /proc/kcore
не совпадает с памятью с точки зрения процесса в /proc/pid/mem
- поэтому для поиска памяти процесса в /proc/kcore
нужно было бы выяснить, как память процесса отображается в память ядра ( много грязных вещей и много времени)
Таким образом, чтобы получить память процесса, сначала прочитайте, в каких областях /proc/pid/maps
разрешено читать/писать с/на, а затем сбрасывать копии областей из /proc/pid/mem
. script ниже выгружает все записываемые области (источник: https://unix.stackexchange.com/info/6301/how-do-i-read-from-proc-pid-mem-under-linux). EDIT: пересмотренный рабочий python script переносится на свой собственный ответ, поэтому его можно прокомментировать в отличие от вопроса.
Ответы
Ответ 1
Для процесса 1234 вы можете получить свою карту памяти, последовательно прочитав /proc/1234/maps
(текстовый псевдофайл) и прочитав виртуальную память, например. читать (2) -инг или mmap (2) -в соответствующих сегментах /proc/1234/mem
разреженного псевдо -file.
Тем не менее, я считаю, что вы не можете избежать какой-либо синхронизации (возможно, с ptrace (2), поскольку gdb
делает), поскольку процесс 1234 может (и делает) изменить его адресное пространство в любое время (с помощью mmap
и связанных с ним системных вызовов).
Ситуация различна, если контролируемый процесс 1234 не является произвольным, но если вы можете улучшить его, чтобы как-то связаться с процессом мониторинга.
Я не понимаю, почему вы спрашиваете об этом. И gdb
может watch
разместить некоторое место без остановки процесса.
Ответ 2
Если у вас есть root-доступ и находятся в системе Linux, вы можете использовать следующий linux script (адаптированный из отличный ответ от unix.stackexchange.com Gilles и ответ, первоначально заданный в вопросе выше, но включающий синтаксические ошибки и не являющиеся питоническими):
#!/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
Если вы сохраните это как write_mem.py, вы можете запустить это (с помощью python2.6 или 2.7) или в начале python2.5 (если вы добавите from __future__ import with_statement
) как:
sudo python write_mem.py 1234 > pid1234_memory_dump
чтобы выгрузить память pid1234 в файл pid1234_memory_dump.
Ответ 3
Вам нужно будет использовать /proc//mem для чтения памяти процессов, я бы не рекомендовал читать /proc/kcore или любую из функций памяти ядра (что требует много времени)
Ответ 4
я достиг этого, выпустив следующую команду
[root @stage1 ~] # echo "Использование памяти для PID [MySql]:"; для mem в {Private, Rss, Shared, Swap, Pss}; do grep $mem/proc/ ps aux |grep mysql |awk '{print $2}'|head -n 1
/smaps | awk -v mem_type = "$ mem" '{i = я + $2} END {print mem_type, "использование памяти:" i}'; done
Результат результата
Использование памяти для PID [MySql]:
Использование частной памяти: 204
Использование памяти Rss: 1264
Использование общей памяти: 1060
Использование памяти обмена: 0
Использование памяти Pss: 423