将 linux 进程的内存转储到文件

Fra*_*rth 70 linux memory process

是否可以将为进程分配的当前内存(通过 PID)转储到文件中?或者以某种方式阅读它?

A. *_*son 65

我制作了一个脚本来完成这个任务。

这个想法来自 James Lawrie 的回答和这篇文章: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
Run Code Online (Sandbox Code Playgroud)

把它放在一个文件中(例如“dump-all-memory-of-pid.sh”)并使其可执行

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

输出将打印到具有以下名称的文件中: pid-startaddress-stopaddress.dump

依赖项: gdb

  • 惊人的!只是用它来发现神秘的 bash 实例正在运行哪个脚本。 (2认同)
  • @mxmlnkn 这是数据(`rw-p`),其他范围用于代码(`r-xp`)。如果您想要两者的转储,请继续将“grep”替换为“cat”。 (2认同)

Jam*_*s L 57

我不确定如何将所有内存转储到文件中而不重复执行此操作(如果有人知道让 gdb 执行此操作的自动方法,请告诉我),但是假设您知道,以下内容适用于任何一批内存pid:

$ cat /proc/[pid]/maps
Run Code Online (Sandbox Code Playgroud)

这将采用以下格式(示例):

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
Run Code Online (Sandbox Code Playgroud)

选择一批内存(例如 00621000-00622000),然后使用 gdb 作为 root 附加到进程并转储该内存:

$ gdb --pid [pid]
(gdb) dump memory /root/output 0x00621000 0x00622000
Run Code Online (Sandbox Code Playgroud)

然后使用 strings 命令分析 /root/output,不要在屏幕上布满 PuTTY。

  • 有没有办法在没有 gdb 的情况下在 bash/sh 中做到这一点? (3认同)
  • @Programming4life [gcore(1)](http://man7.org/linux/man-pages/man1/gcore.1.html) (3认同)

Aqu*_*wer 44

尝试

    gcore $pid
Run Code Online (Sandbox Code Playgroud)

哪里$pid是pid的实际编号;有关更多信息,请参阅:info gcore

转储可能需要一些时间,并且某些内存可能无法读取,但已经足够了......还要注意它可以创建大文件,我只是这样创建了一个 2GB 文件..

  • @CMCDragonkai 使用 `gcore -a PID` (3认同)

小智 13

纯bash解决方案:

procdump() 
( 
    cat /proc/$1/maps | grep "rw-p" | awk '{print $1}' | ( IFS="-"
    while read a b; do
        dd if=/proc/$1/mem bs=$( getconf PAGESIZE ) iflag=skip_bytes,count_bytes \
           skip=$(( 0x$a )) count=$(( 0x$b - 0x$a )) of="$1_mem_$a.bin"
    done )
)
Run Code Online (Sandbox Code Playgroud)

用法:procdump PID

为了更干净的转储过滤掉*.so内存映射的共享库和空的内存范围:

procdump()
( 
    cat /proc/$1/maps | grep -Fv ".so" | grep " 0 " | awk '{print $1}' | ( IFS="-"
    while read a b; do
        dd if=/proc/$1/mem bs=$( getconf PAGESIZE ) iflag=skip_bytes,count_bytes \
           skip=$(( 0x$a )) count=$(( 0x$b - 0x$a )) of="$1_mem_$a.bin"
    done )
)
Run Code Online (Sandbox Code Playgroud)

  • 我对此脚本遇到的一个问题是,与使用等于页面大小(对我来说是 4096)的块大小(我获得 ~100MB/s)相比,块大小为 1 会导致带宽慢到令人无法接受的 ~30kB/s!请参阅[此处](https://gist.github.com/mxmlnkn/05e1cd03a4102e353d792bd17687aed3)。`getconf PAGESIZE` 用于获取页面大小,然后将地址和计数除以它。 (2认同)

小智 5

我也制作了自己的程序来转储整个进程内存,它是用 C 语言编写的,因此可以交叉编译为 Android,这正是我所需要的。

您还可以指定 IP 地址和 TCP 端口。源代码在这里