【问题标题】:generate core file with gdb使用 gdb 生成核心文件
【发布时间】:2013-12-27 07:17:15
【问题描述】:

我用gdb generate-core-file为一个进程(mongod)生成core文件,但是进程mmap很多数据文件,这个进程的Res高达36.1G。
核心文件消耗34G空间后,磁盘上没有更多可用空间,所以我得到了:

警告:写笔记部分(设备上没有剩余空间) 保存的corefile core.12038

我想知道是否所有的 mmap 数据都将转储到核心文件?如果只想看一些局部变量怎么办?

背景: 我们在生产中遇到了问题,生产中的二进制文件中没有符号信息。所以我想生成核心文件并离线进行一些分析。

【问题讨论】:

    标签: gdb core-file


    【解决方案1】:

    我想知道是否所有的 mmap 数据都将转储到核心文件?

    通常内核只转储可写 mmap,而不转储只读 mmap。但是,这是可配置的:参见 core(5) 手册页(“控制将哪些映射写入核心转储”部分)。

    背景:我们在生产中遇到了问题,生产中的二进制文件中没有符号信息。

    “标准”方法是使用gdbserver 远程调试此类二进制文件,并使用gdb 连接到它,确实 可以访问完全调试的二进制文件。

    【讨论】:

    • 谢谢俄罗斯人!!这正是我想要的。在这种情况下,gdbserver 似乎是一个很好的解决方案。我也发现systemtap-server也有这种用处。
    • 嗨俄罗斯人,我尝试了以下两种方法,但它们都不起作用。方法一:echo '1' > /proc/{pid}/coredump_filter;方法二:停止app,回显“1” > /proc/self/coredump_filter;启动应用程序。它们都生成一个10G+的核心文件。 app 是 mongoDB,使用 mmap 管理数据缓存。 # uname -rm 2.6.32-279.el6.x86_64 x86_64
    【解决方案2】:

    如果我只想查看一些局部变量,我该怎么办? 背景:我们在生产中遇到了问题,生产中的二进制文件中没有符号信息。

    您的问题中没有提到操作系统,所以如果您使用的是 Linux
    1) 在生产服务器上安装带有调试信息的程序
    2)如果您不能这样做,请分析您感兴趣的函数的汇编代码并从汇编程序中获取局部变量的值

    然后使用 SystemTap 跟踪您的程序。

    让我用一个简单的例子来说明这两种方法。 一、C++程序分析:

    >cat main.cpp
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int f(int arg)
    {
        int a = arg+1;
        int b = arg+2;
        int c = a + b;
        printf ("printf in program: f, c: %d\n", c);
        return c;
    }
    
    int main(int argc, char *argv[])
    {
       printf ("f: %p\n", &f);
       int sum = 0;
       while (true) {
         for (int i= atoi(argv[1]); i < atoi(argv[2]); ++i) {
           sum += f(i);
         }
         sleep(5);
       }
    
       printf("Sum: %d\n", sum);
       return 0;
    }
    

    所以我想在函数 f() 中获取局部变量“c”的值。

    1) 如果符号信息可用

    >cat measure_f.stp
    probe process("a.out").statement("*@main.cpp:10")
    {
      printf("SystemTap, time: %s, the local variable c :%d\n", ctime(gettimeofday_s()), $c)
    }
    
    >sudo stap measure_f.stp -c "./a.out 21 23"
    f: 0x400634
    printf in program: f, c: 45
    printf in program: f, c: 47
    SystemTap, time: Fri Dec 27 12:59:31 2013, the local variable c :45
    SystemTap, time: Fri Dec 27 12:59:31 2013, the local variable c :47
    printf in program: f, c: 45
    printf in program: f, c: 47
    SystemTap, time: Fri Dec 27 12:59:36 2013, the local variable c :45
    SystemTap, time: Fri Dec 27 12:59:36 2013, the local variable c :47
    

    1) 如果符号信息不可用,则使用汇编程序

    先反汇编你的函数,找到你要监控的地址

    (gdb) disassemble /m f
    Dump of assembler code for function f(int):
    6       {
       0x0000000000400634 <+0>:     push   %rbp
       0x0000000000400635 <+1>:     mov    %rsp,%rbp
       0x0000000000400638 <+4>:     sub    $0x20,%rsp
       0x000000000040063c <+8>:     mov    %edi,-0x14(%rbp)
    
    7           int a = arg+1;
       0x000000000040063f <+11>:    mov    -0x14(%rbp),%eax
       0x0000000000400642 <+14>:    add    $0x1,%eax
       0x0000000000400645 <+17>:    mov    %eax,-0xc(%rbp)
    
    8           int b = arg+2;
       0x0000000000400648 <+20>:    mov    -0x14(%rbp),%eax
       0x000000000040064b <+23>:    add    $0x2,%eax
       0x000000000040064e <+26>:    mov    %eax,-0x8(%rbp)
    
    9           int c = a + b;
       0x0000000000400651 <+29>:    mov    -0x8(%rbp),%eax
       0x0000000000400654 <+32>:    mov    -0xc(%rbp),%edx
       0x0000000000400657 <+35>:    lea    (%rdx,%rax,1),%eax
       0x000000000040065a <+38>:    mov    %eax,-0x4(%rbp)
    
    10          printf ("printf in program: f, c: %d\n", c);
       0x000000000040065d <+41>:    mov    -0x4(%rbp),%eax
       0x0000000000400660 <+44>:    mov    %eax,%esi
       0x0000000000400662 <+46>:    mov    $0x4007f8,%edi
       0x0000000000400667 <+51>:    mov    $0x0,%eax
       0x000000000040066c <+56>:    callq  0x4004f8 <printf@plt>
    
    11          return c;
       0x0000000000400671 <+61>:    mov    -0x4(%rbp),%eax
    
    12      }
       0x0000000000400674 <+64>:    leaveq
       0x0000000000400675 <+65>:    retq
    

    如您所见,为了获取局部变量 c,必须在 0x000000000040065a 上获取寄存器 %eax

    > cat measure_f_2.stp
    probe begin
    {
      printf("Monitoring process %d\n", $1)
    }
    
    probe process($1).statement(0x000000000040065a).absolute
    { 
      printf("SystemTap (2), time: %s, the local variable c (rax):%d\n", ctime(gettimeofday_s()), register("rax"))
    }
    

    所以我开始“./a.out 21 23”,然后运行我的 SystemTap 脚本

    >sudo stap measure_f_2.stp 11564
    Monitoring process 11564
    SystemTap (2), time: Fri Dec 27 13:15:09 2013, the local variable c (rax):45
    SystemTap (2), time: Fri Dec 27 13:15:09 2013, the local variable c (rax):47
    SystemTap (2), time: Fri Dec 27 13:15:14 2013, the local variable c (rax):45
    SystemTap (2), time: Fri Dec 27 13:15:14 2013, the local variable c (rax):47
    

    【讨论】:

    • 感谢 skwllsp。目前拆机对我来说太难了。在俄语的帮助下,我发现如果我们没有关于生产的符号信息,我们可以尝试 systemtap-server。仍在阅读。
    猜你喜欢
    • 2012-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-12
    • 2011-07-01
    • 1970-01-01
    相关资源
    最近更新 更多