如何转储进程的内存页?

How to dump memory pages of a process?

我想在进程完成执行后转储其内存页。我正在尝试为此使用 gdb,首先我在 exit 和 _exit 处设置断点然后我 运行 gdb 中的进程,一旦进程中断我使用 info proc mappings 来获取进程的内存映射.它看起来像下面这样:

Mapped address spaces:

          Start Addr           End Addr       Size     Offset objfile
            0x400000           0x415000    0x15000        0x0 /path/workspace/freqmine
            0x614000           0x615000     0x1000    0x14000 /path/workspace/freqmine
            0x615000           0x616000     0x1000    0x15000 /path/workspace/freqmine
            0x616000          0x129b000   0xc85000        0x0 [heap]
      0x7ffff71f4000     0x7ffff720a000    0x16000        0x0 /lib/x86_64-linux-gnu/libgcc_s.so.1
      0x7ffff720a000     0x7ffff7409000   0x1ff000    0x16000 /lib/x86_64-linux-gnu/libgcc_s.so.1
      0x7ffff7409000     0x7ffff740a000     0x1000    0x15000 /lib/x86_64-linux-gnu/libgcc_s.so.1
      0x7ffff740a000     0x7ffff750f000   0x105000        0x0 /lib/x86_64-linux-gnu/libm-2.19.so
      0x7ffff750f000     0x7ffff770e000   0x1ff000   0x105000 /lib/x86_64-linux-gnu/libm-2.19.so
      0x7ffff770e000     0x7ffff770f000     0x1000   0x104000 /lib/x86_64-linux-gnu/libm-2.19.so
      0x7ffff770f000     0x7ffff7710000     0x1000   0x105000 /lib/x86_64-linux-gnu/libm-2.19.so
      0x7ffff7710000     0x7ffff78cb000   0x1bb000        0x0 /lib/x86_64-linux-gnu/libc-2.19.so
      0x7ffff78cb000     0x7ffff7acb000   0x200000   0x1bb000 /lib/x86_64-linux-gnu/libc-2.19.so
      0x7ffff7acb000     0x7ffff7acf000     0x4000   0x1bb000 /lib/x86_64-linux-gnu/libc-2.19.so
      0x7ffff7acf000     0x7ffff7ad1000     0x2000   0x1bf000 /lib/x86_64-linux-gnu/libc-2.19.so
      0x7ffff7ad1000     0x7ffff7ad6000     0x5000        0x0 
      0x7ffff7ad6000     0x7ffff7bbc000    0xe6000        0x0 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
      0x7ffff7bbc000     0x7ffff7dbb000   0x1ff000    0xe6000 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
      0x7ffff7dbb000     0x7ffff7dc3000     0x8000    0xe5000 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
      0x7ffff7dc3000     0x7ffff7dc5000     0x2000    0xed000 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19
      0x7ffff7dc5000     0x7ffff7dda000    0x15000        0x0 
      0x7ffff7dda000     0x7ffff7dfd000    0x23000        0x0 /lib/x86_64-linux-gnu/ld-2.19.so
      0x7ffff7fce000     0x7ffff7fd3000     0x5000        0x0 
      0x7ffff7ff7000     0x7ffff7ffa000     0x3000        0x0 
      0x7ffff7ffa000     0x7ffff7ffc000     0x2000        0x0 [vdso]
      0x7ffff7ffc000     0x7ffff7ffd000     0x1000    0x22000 /lib/x86_64-linux-gnu/ld-2.19.so
      0x7ffff7ffd000     0x7ffff7ffe000     0x1000    0x23000 /lib/x86_64-linux-gnu/ld-2.19.so
      0x7ffff7ffe000     0x7ffff7fff000     0x1000        0x0 
      0x7ffffffdd000     0x7ffffffff000    0x22000        0x0 [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0 [vsyscall]

现在我有两个问题,第一:getconf PAGESIZE 在我的机器上 returns 4096 等于 0x1000,其中一些内存 space虽然有不同的尺寸。这怎么可能?这些 spaces 内存页还是逻辑 spaces?如果这些不是内存页,如何查看内存页的地址,甚至直接将内存页转储到文件?

我的第二个问题是:这些地址应该是程序看到的虚拟地址(不是物理地址),为什么程序space不从0开始呢?如果我尝试转储从地址 0 开始的内存,我会收到以下错误:Cannot access memory at address 0x0。为什么在这些内存 space 之间有一些区域无法访问(例如堆之后的区域)?进程的虚拟 space 不应该是连续的吗?

some of these memory spaces have different sizes though. how is that possible?

简单:它们跨越多个页面(请注意,它们的所有大小都是 0x1000 的 倍数)。

are these spaces memory pages or just logical spaces?

它们是具有相同底层映射(相同文件)和相同保护的一个或多个页面的跨度。我不确定你到底叫什么 "logical spaces",但你可以这么称呼它们。

these addresses are supposed to be virtual addresses viewed by the program (not physical addresses),

正确。

so why doesn't the program space start at 0?

因为很久以前,VAX 机器曾经在地址 0 处映射某些东西,这使得查找 NULL 指针取消引用变得困难(它们没有崩溃)。这被认为是一个 坏主意 ,因此后来的 UNIX 变体 not 映射零页,并且任何取消引用 NULL 的尝试指针原因 SIGSEGV,帮助您调试程序。