检查 pmap 报告的虚拟内存块
examining virtual memory block reported by pmap
我发现我的程序有漏洞。它不会被 "valgrind memcheck" 捕获(我通过摘要报告确认了这一点,它没有接近我能看到的最高使用率)。使用 "valgrind massif --pages-as-heap" 后,我可以更接近我的内存使用情况。
但是,它没有报告执行 mmap 并分配大部分内存的部分的完整回溯,我也无法检查内存分配,因为我只能在程序被杀死后才能收集 massif 输出。
我尝试的另一件事是检查占用大量 RSS space 的内存块。但是我不知道如何查看 pmap 报告的内存块的内容。将该地址放在 gdb dint 帮助上。我听说 gdb 使用了一些地址随机化。有人可以帮助我如何获得与 pmap 输出报告的内存位置相对应的符号。
putting that addr on gdb dint help.
我不知道你所说的 "putting that addr on gdb" 是什么意思,但正确地做到这一点 会 有所帮助。
I heard some address randomization is used by gdb.
你没听错:GDB 本身不做任何随机化,它(默认)禁用 OS 执行的随机化,以便进行调试更容易,更可重现。
Can some one help me how to get the symbol that corresponds to the memory location reported by pmap output.
你很困惑:堆分配的内存根据定义没有任何符号。
好的,让我们通过使用 GDB 检查在 pmap
中可见的内存的示例来工作。让我们从编译这个程序开始,它构建了一个 100 万长的链表,其中包含一些字符串:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
typedef struct Node { struct Node *next; char payload[64]; } Node;
int main()
{
int j;
Node *head = NULL;
for (j = 0; j < 1000000; j++) {
Node *n = malloc(sizeof(*n));
n->next = head;
sprintf(n->payload, "string %d", j);
head = n;
}
return 0;
}
gcc -Wall -g -std=c99 t.c && gdb -q ./a.out
(gdb) b 17
Breakpoint 1 at 0x4005e3: file t.c, line 17.
(gdb) r
Starting program: /tmp/a.out
Breakpoint 1, main () at t.c:17
17 return 0;
现在我们可以用pmap检查程序了:
(gdb) info prog
Using the running image of child process 23785.
Program stopped at 0x4005e3.
It stopped at breakpoint 1.
Type "info stack" or "info registers" for more information.
(gdb) shell pmap 23785
23785: /tmp/a.out
0000000000400000 4K r-x-- a.out
0000000000600000 4K r---- a.out
0000000000601000 4K rw--- a.out
0000000000602000 78144K rw--- [ anon ]
00007ffff7a11000 1784K r-x-- libc-2.19.so
00007ffff7bcf000 2048K ----- libc-2.19.so
00007ffff7dcf000 16K r---- libc-2.19.so
00007ffff7dd3000 8K rw--- libc-2.19.so
00007ffff7dd5000 20K rw--- [ anon ]
00007ffff7dda000 140K r-x-- ld-2.19.so
00007ffff7fd1000 12K rw--- [ anon ]
00007ffff7ff6000 8K rw--- [ anon ]
00007ffff7ff8000 8K r---- [ anon ]
00007ffff7ffa000 8K r-x-- [ anon ]
00007ffff7ffc000 4K r---- ld-2.19.so
00007ffff7ffd000 4K rw--- ld-2.19.so
00007ffff7ffe000 4K rw--- [ anon ]
00007ffffffde000 132K rw--- [ stack ]
ffffffffff600000 4K r-x-- [ anon ]
total 82356K
很明显,从 0x602000
开始的 78MiB 的 anon
space 一定是我们大部分数据所在的位置。 (您也可以通过在循环中单步执行几次来验证这一点。)
我们如何看待这些数据?像这样:
(gdb) x/30gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000051
0x602010: 0x0000000000000000 0x3020676e69727473
0x602020: 0x0000000000000000 0x0000000000000000
0x602030: 0x0000000000000000 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000000
0x602050: 0x0000000000000000 0x0000000000000051
0x602060: 0x0000000000602010 0x3120676e69727473
0x602070: 0x0000000000000000 0x0000000000000000
0x602080: 0x0000000000000000 0x0000000000000000
0x602090: 0x0000000000000000 0x0000000000000000
0x6020a0: 0x0000000000000000 0x0000000000000051
0x6020b0: 0x0000000000602060 0x3220676e69727473
0x6020c0: 0x0000000000000000 0x0000000000000000
0x6020d0: 0x0000000000000000 0x0000000000000000
0x6020e0: 0x0000000000000000 0x0000000000000000
您可以立即注意到在 0x602018
、0x602068
和 0x6020b8
处有 ASCII
个字符串。
您可以像这样检查这些字符串:
(gdb) x/s 0x602018
0x602018: "string 0"
(gdb) x/s 0x602068
0x602068: "string 1"
(gdb) x/s 0x6020b8
0x6020b8: "string 2"
您还可以注意到在 0x602060
处有一个指向 0x602010
的指针,在 0x6020b0
处有一个指向 0x602060
.
的指针
这让您猜测在 0x602060
处有一个节点,在 0x6020b0
处有另一个节点。你可以证实这个猜测:
(gdb) p *(Node*)0x602060
= {next = 0x602010, payload = "string 1", '[=14=]0' <repeats 55 times>}
(gdb) p *(Node*)0x6020b0
= {next = 0x602060, payload = "string 2", '[=14=]0' <repeats 55 times>}
这就是全部。
我发现我的程序有漏洞。它不会被 "valgrind memcheck" 捕获(我通过摘要报告确认了这一点,它没有接近我能看到的最高使用率)。使用 "valgrind massif --pages-as-heap" 后,我可以更接近我的内存使用情况。 但是,它没有报告执行 mmap 并分配大部分内存的部分的完整回溯,我也无法检查内存分配,因为我只能在程序被杀死后才能收集 massif 输出。 我尝试的另一件事是检查占用大量 RSS space 的内存块。但是我不知道如何查看 pmap 报告的内存块的内容。将该地址放在 gdb dint 帮助上。我听说 gdb 使用了一些地址随机化。有人可以帮助我如何获得与 pmap 输出报告的内存位置相对应的符号。
putting that addr on gdb dint help.
我不知道你所说的 "putting that addr on gdb" 是什么意思,但正确地做到这一点 会 有所帮助。
I heard some address randomization is used by gdb.
你没听错:GDB 本身不做任何随机化,它(默认)禁用 OS 执行的随机化,以便进行调试更容易,更可重现。
Can some one help me how to get the symbol that corresponds to the memory location reported by pmap output.
你很困惑:堆分配的内存根据定义没有任何符号。
好的,让我们通过使用 GDB 检查在 pmap
中可见的内存的示例来工作。让我们从编译这个程序开始,它构建了一个 100 万长的链表,其中包含一些字符串:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
typedef struct Node { struct Node *next; char payload[64]; } Node;
int main()
{
int j;
Node *head = NULL;
for (j = 0; j < 1000000; j++) {
Node *n = malloc(sizeof(*n));
n->next = head;
sprintf(n->payload, "string %d", j);
head = n;
}
return 0;
}
gcc -Wall -g -std=c99 t.c && gdb -q ./a.out
(gdb) b 17
Breakpoint 1 at 0x4005e3: file t.c, line 17.
(gdb) r
Starting program: /tmp/a.out
Breakpoint 1, main () at t.c:17
17 return 0;
现在我们可以用pmap检查程序了:
(gdb) info prog
Using the running image of child process 23785.
Program stopped at 0x4005e3.
It stopped at breakpoint 1.
Type "info stack" or "info registers" for more information.
(gdb) shell pmap 23785
23785: /tmp/a.out
0000000000400000 4K r-x-- a.out
0000000000600000 4K r---- a.out
0000000000601000 4K rw--- a.out
0000000000602000 78144K rw--- [ anon ]
00007ffff7a11000 1784K r-x-- libc-2.19.so
00007ffff7bcf000 2048K ----- libc-2.19.so
00007ffff7dcf000 16K r---- libc-2.19.so
00007ffff7dd3000 8K rw--- libc-2.19.so
00007ffff7dd5000 20K rw--- [ anon ]
00007ffff7dda000 140K r-x-- ld-2.19.so
00007ffff7fd1000 12K rw--- [ anon ]
00007ffff7ff6000 8K rw--- [ anon ]
00007ffff7ff8000 8K r---- [ anon ]
00007ffff7ffa000 8K r-x-- [ anon ]
00007ffff7ffc000 4K r---- ld-2.19.so
00007ffff7ffd000 4K rw--- ld-2.19.so
00007ffff7ffe000 4K rw--- [ anon ]
00007ffffffde000 132K rw--- [ stack ]
ffffffffff600000 4K r-x-- [ anon ]
total 82356K
很明显,从 0x602000
开始的 78MiB 的 anon
space 一定是我们大部分数据所在的位置。 (您也可以通过在循环中单步执行几次来验证这一点。)
我们如何看待这些数据?像这样:
(gdb) x/30gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000051
0x602010: 0x0000000000000000 0x3020676e69727473
0x602020: 0x0000000000000000 0x0000000000000000
0x602030: 0x0000000000000000 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000000
0x602050: 0x0000000000000000 0x0000000000000051
0x602060: 0x0000000000602010 0x3120676e69727473
0x602070: 0x0000000000000000 0x0000000000000000
0x602080: 0x0000000000000000 0x0000000000000000
0x602090: 0x0000000000000000 0x0000000000000000
0x6020a0: 0x0000000000000000 0x0000000000000051
0x6020b0: 0x0000000000602060 0x3220676e69727473
0x6020c0: 0x0000000000000000 0x0000000000000000
0x6020d0: 0x0000000000000000 0x0000000000000000
0x6020e0: 0x0000000000000000 0x0000000000000000
您可以立即注意到在 0x602018
、0x602068
和 0x6020b8
处有 ASCII
个字符串。
您可以像这样检查这些字符串:
(gdb) x/s 0x602018
0x602018: "string 0"
(gdb) x/s 0x602068
0x602068: "string 1"
(gdb) x/s 0x6020b8
0x6020b8: "string 2"
您还可以注意到在 0x602060
处有一个指向 0x602010
的指针,在 0x6020b0
处有一个指向 0x602060
.
这让您猜测在 0x602060
处有一个节点,在 0x6020b0
处有另一个节点。你可以证实这个猜测:
(gdb) p *(Node*)0x602060
= {next = 0x602010, payload = "string 1", '[=14=]0' <repeats 55 times>}
(gdb) p *(Node*)0x6020b0
= {next = 0x602060, payload = "string 2", '[=14=]0' <repeats 55 times>}
这就是全部。