如何转储进程的内存页?
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
,帮助您调试程序。
我想在进程完成执行后转储其内存页。我正在尝试为此使用 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
,帮助您调试程序。