Подтвердить что ты не робот

Чтение памяти жизненного процесса без его прерывания (/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 переносится на свой собственный ответ, поэтому его можно прокомментировать в отличие от вопроса.

4b9b3361

Ответ 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