Despejar a memória de um processo Linux em um arquivo

Respostas:

46

Não tenho certeza de como você despeja toda a memória em um arquivo sem fazer isso repetidamente (se alguém souber uma maneira automatizada de obter o gdb, informe-me), mas o seguinte funciona para qualquer lote de memória, desde que você saiba o pid:

$ cat /proc/[pid]/maps

Isso estará no formato (exemplo):

00400000-00421000 r-xp 00000000 08:01 592398                             /usr/libexec/dovecot/pop3-login
00621000-00622000 rw-p 00021000 08:01 592398                             /usr/libexec/dovecot/pop3-login
00622000-0066a000 rw-p 00622000 00:00 0                                  [heap]
3e73200000-3e7321c000 r-xp 00000000 08:01 229378                         /lib64/ld-2.5.so
3e7341b000-3e7341c000 r--p 0001b000 08:01 229378                         /lib64/ld-2.5.so

Escolha um lote de memória (por exemplo, 00621000-00622000) e use gdb como root para se conectar ao processo e despejar essa memória:

$ gdb --pid [pid]
(gdb) dump memory /root/output 0x00621000 0x00622000

Em seguida, analise / root / output com o comando strings, a menos que você queira o PuTTY em toda a tela.

James L
fonte
11
Existe uma maneira de fazer isso em apenas bash / sh sem gdb?
Programming4life
3
@ Programming4life gcore (1)
julian
51

Eu criei um script que realiza essa tarefa.

A idéia vem da resposta de James Lawrie e deste post: http://www.linuxforums.org/forum/programming-scripting/52375-reading-memory-other-processes.html#post287195

#!/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

coloque isso em um arquivo (por exemplo, "dump-all-memory-of-pid.sh") e torne-o executável

uso: ./dump-all-memory-of-pid.sh [pid]

A saída é impressa em arquivos com os nomes: pid-startaddress-stopaddress.dump

Dependências: gdb

A. Nilsson
fonte
2
Impressionante! Apenas usei para descobrir qual script uma instância misteriosa do bash estava executando.
26416 Tobia
Por que você está apenas aguardando e diminuindo intervalos com rw-ppermissões?
mxmlnkn
@mxmlnkn São dados ( rw-p), os outros intervalos são para código ( r-xp). Se você quiser um despejo de ambos, vá em frente e troque greppor exemplo cat.
A. Nilsson
39

experimentar

    gcore $pid

onde $pidé o número real do pid; para mais informações, consulte:info gcore

pode levar algum tempo para que o despejo aconteça, e alguma memória pode não ser legível, mas é boa o suficiente ... esteja ciente também de que ele pode criar arquivos grandes, acabei de criar um arquivo de 2 GB dessa maneira ..

Poder do Aquário
fonte
11
Está gcoredespejando um arquivo esparso?
CMCDragonkai
3

man proc diz:

/ proc / [pid] / mem Este arquivo pode ser usado para acessar as páginas da memória de um processo através de open (2), read (2) e lseek (2).

Talvez possa ajudá-lo

Dom
fonte
11
Isso não é suficiente, ler outro processo precisa de uma combinação de / proc / <pid> / {mem, * maps}, ptrace e algum tratamento de sinal para evitar travar o processo de destino.
Tobu
@Tobu Indeed . Eu escrevi um roteiro de prova de conceito .
Gilles 'SO- stop be evil'
3

Eu criei meu próprio programa para despejar toda a memória do processo, ela está em C para que possa ser compilada em conjunto com o Android, que é o que eu precisava.

Você também pode especificar o endereço IP e a porta TCP. Código fonte aqui .

Tal Aloni
fonte
2

Solução de bash pura:

procdump () 
{ 
    cat /proc/$1/maps | grep "rw-p" | awk '{print $1}' | ( IFS="-"
    while read a b; do
        count=$(( bd-ad ))
        ad=$(printf "%llu" "0x$a")
        bd=$(printf "%llu" "0x$b")
        dd if=/proc/$1/mem bs=1 skip=$ad count=$count of=$1_mem_$a.bin
    done )
}

Uso: procdump PID

para um despejo mais limpo:

procdump () 
{ 
    cat /proc/$1/maps | grep -Fv ".so" | grep " 0 " | awk '{print $1}' | ( IFS="-"
    while read a b; do
        ad=$(printf "%llu" "0x$a")
        bd=$(printf "%llu" "0x$b")
        dd if=/proc/$1/mem bs=1 skip=$ad count=$(( bd-ad )) of=$1_mem_$a.bin
    done )
}
Zibri
fonte
Portanto, pelo que entendi, a idéia por trás do despejo mais limpo é que apenas os arquivos na memória têm um tamanho anexado à região da memória, em contraste com a memória real do aplicativo, que possui o tamanho 0 (já que o tamanho realmente usado é desconhecido pelo OS).
mxmlnkn
Um problema que tenho com esse script é que o tamanho de bloco de 1 leva a uma largura de banda inaceitavelmente lenta de ~ 30kB / s, em comparação com o uso de um tamanho de bloco igual ao tamanho da página (4096 para mim) para o qual recebo ~ 100MB / s! Veja aqui . getconf PAGESIZEé usado para obter o tamanho da página e, em seguida, os endereços e as contagens são divididos por ela.
mxmlnkn
0

Se você deseja despejar um segmento de memória separado do processo em execução sem criar um arquivo principal enorme (por exemplo, com gcore), você pode usar uma pequena ferramenta a partir daqui . Há também uma linha no README, se você deseja despejar todos os segmentos legíveis em arquivos separados.

Nopius
fonte