GDB Core

程序运行发生异常退出,比如segment错误,此时可以利用系统生成的core文件,配合GDB来定位问题。


问题程序

segment.c

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

void func()
{
  char *p = NULL;

  *p = 3;
}

main()
{
  func();

  return;
}


编译:

gcc -g -o segment segment.c

Core文件:

1. 查看系统是否允许生成core文件  

      

#ulimit -a
core file size          (blocks, -c) 0

core文件大小限制为0,不能生成core文件。

2. 使用如下命令取消限制,使系统能生成core文件

ulimit -c unlimited  

或者指定core文件大小,如1K

ulimit -c 1024

执行程序:   
 # ./segment
Segmentation fault (core dumped)

在程序当前目录下生成了core文件


GDB调试:

# gdb ./segment core
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/duanbb/test/segment/segment...done.
[New Thread 3655]

warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib/tls/i686/cmov/libc.so.6...Reading symbols from /usr/lib/debug/lib/tls/i686/cmov/libc-2.11.1.so...done.
done.
Loaded symbols for /lib/tls/i686/cmov/libc.so.6
Reading symbols from /lib/ld-linux.so.2...Reading symbols from /usr/lib/debug/lib/ld-2.11.1.so...done.
done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./segment'.
Program terminated with signal 11, Segmentation fault.
#0  0x080483c4 in func () at segment.c:10
10	  *p = 3;

可以清楚地看到,程序在第10行代码,func()函数内,执行"*p = 3"时发生了segment错误

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------       

Release版 Core的调试

众所周知,发布程序时必须是release版的,杜绝debug版。

下面就来看看如何调试release 版程序生成的core文件

还是如上程序,编译release版:

# gcc -o segment segment.c

运行程序:

./segment
Segmentation fault (core dumped)

调试程序:

$ gdb ./segment core 
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/duanbb/test/segment/segment...(no debugging symbols found)...done.
[New Thread 4711]

warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib/tls/i686/cmov/libc.so.6...Reading symbols from /usr/lib/debug/lib/tls/i686/cmov/libc-2.11.1.so...done.
done.
Loaded symbols for /lib/tls/i686/cmov/libc.so.6
Reading symbols from /lib/ld-linux.so.2...Reading symbols from /usr/lib/debug/lib/ld-2.11.1.so...done.
done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./segment'.
Program terminated with signal 11, Segmentation fault.
<span style="color:#ff0000;">#0  0x080483c4 in func ()
</span>(gdb) 

只能显示出出错时的函数,而看不到出错的具体位置,怎么办?


方法: 用发布时的原代码,在原有的编译选项上(不要改变任何编译参数,即使有"-O2"参数,也不要动),只加上"-g"选项,编译出对应的debug程序

本例:

# gcc -g -o segment_d segment.c

调试:

# gdb ./segment_d core
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/duanbb/test/segment/segment_d...done.

warning: core file may not match specified executable file.
[New Thread 4711]

warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib/tls/i686/cmov/libc.so.6...Reading symbols from /usr/lib/debug/lib/tls/i686/cmov/libc-2.11.1.so...done.
done.
Loaded symbols for /lib/tls/i686/cmov/libc.so.6
Reading symbols from /lib/ld-linux.so.2...Reading symbols from /usr/lib/debug/lib/ld-2.11.1.so...done.
done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./segment'.
Program terminated with signal 11, Segmentation fault.
#0  0x080483c4 in func () at segment.c:10
10	  *p = 3;

即可定位出错误位置


------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Core文件的命名和路径

默认情况下core文件名即为"core",文件路径:运行可执行文件时,环境所在的目录


两个控制文件

(1)    /proc/sys/kernel/core_uses_pid

             0: 默认值,生成的文件名不会带上PID后缀

             1: 文件名带上PID后缀,如"core.2976"

         修改方法: "echo 1 > /proc/sys/kernel/core_uses_pid"

(2)  /proc/sys/kernel/core_pattern

            用来控制文件名格式

            默认值: core   

            假设将其值改变为:"/home/duanbei/corefile/core-%e-%p-%t", 那么所有的core文件将保存在"/home/duanbei/corefile"目录下,文件名格式为“core-程序名-pid-时间戳”

            格式参数列表

%p - insert pid into filename
%u - insert current uid into filename
%g - insert current gid into filename
%s - insert signal that caused the coredump into the filename
%t - insert UNIX time that the coredump occurred into filename
%h - insert hostname where the coredump happened into filename
%e - insert coredumping executable name into filename

注:如果设置了“%p”,而“/proc/sys/kernel/core_uses_pid”值又为1,则不会添加PID后缀,因文件名中已含该信息


PS:

      要生成core文件,就不要在程序中用signal()捕获‘SIGSEGV’信号了,不然生成不了core文件
如果工程很大,头文件很多,而有几个头文件又经常要用的,那么: 1、把这些头文件全部写到一个头文件中,比如:preh.h 2、写一个preh.c,里面的包含库文件,只要一句话#include"preh.h" 3、对于preh.c,在project settings 里面设置creat precompilesd headers ,对于其他.c文件,设置use precompiled header file 。 预编译头文件:就是把一个工程中的那一部分代码,预先编译好放在一个文件里(通常是以.pch为扩展名的),这个文件就成为预编译头文件。这些预先编译好的代码可以是任何的C/C++代码,甚至是inline的函数,但必须是稳定的在工程开发的过程中不会被经常改变。 编译器是以文件为单位编译的,一个文件经过修改后,会重新编译整个文件,当然在这个文件里包含的所有头文件中的东西都要重新处理一遍 预编译头的作用: 根据上文介绍,预编译头文件的作用当然就是提高便宜速度了,有了它你没有必要每次 都编译那些不需要经常改变的代码。编译性能当然就提高了。 预编译头的使用: 要使用预编译头,我们必须指定一个头文件,这个头文件包含我们不会经常改变的 代码和其他的头文件,然后我们用这个头文件来生成一个预编译头文件(.pch文件) 想必大家都知道 StdAfx.h这个文件。很多人都认为这是VC提供的一个“系统级别”的 ,编译器带的一个头文件。其实不是的,这个文件可以是任何名字的。我们来考察一个 典型的由AppWizard生成的MFC Dialog Based 程序的预编译头文件。(因为AppWizard 会为我们指定好如何使用预编译头文件,默认的是StdAfx.h,这是VC起的名字)。我们 会发现这个头文件里包含了以下的头文件: #include // MFC core and standard components #include // MFC extensions #include // MFC Automation classes #include // MFC support for Internet Explorer 4 Common Controls #include 这些正是使用MFC的必须包含的头文件,当然我们不太可能在我们的工程中修改这些头文 件的,所以说他们是稳定的。 那么我们如何指定它来生成预编译头文件。我们知道一个头文件是不能编译的。所以我 们还需要一个cpp文件来生成.pch 文件。这个文件默认的就是StdAfx.cpp。在这个文件 里只有一句代码就是:#include “Stdafx.h”。原因是理所当然的,我们仅仅是要它能 够编译而已?D?D?D也就是说,要的只是它的.cpp的扩展名。 我们可以用/Yc编译开关来指 定StdAfx.cpp来生成一个.pch文件,通过/Fp编译开关来指定生成的pch文件的名字。打 开project ->Setting->C/C++ 对话框。把Category指向Precompiled Header。在左边的 树形视图里选择整个工程  Project Options(右下角的那个白的地方)可以看到 /Fp “debug/PCH.pch”,这就是指 定生成的.pch文件的名字,默认的通常是 .pch(我的示例工程名就是PCH)。 然后,在左边的树形视图里选择StdAfx.cpp.//这时只能选一个cpp文件! 这时原来的Project Option变成了 Source File Option(原来是工程,现在是一个文件 ,当然变了)。在这里我们可以看到 /Yc开关,/Yc的作用就是指定这个文件来创建一个 Pch文件。/Yc后面的文件名是那个包含了稳定代码的头文件,一个工程里只能有一个文 件的可以有YC开关。VC就根据这个选项把 StdAfx.cpp编译成一个Obj文件和一个PCH文件 。 然后我们再选择一个其它的文件来看看,//其他cpp文件 在这里,Precomplier 选择了 Use ⋯⋯⋯一项,头文件是我们指定创建PCH 文件的stda fx.h 文件。事实上,这里是使用工程里的设置,(如图1)/Yu”stdafx.h”。 这样,我们就设置好了预编译头文件。也就是说,我们可以使用预编译头功能了。以 下是注意事项: 1):如果使用了/Yu,就是说使用了预编译,我们在每个.cpp文件的最开头,我强调一遍 是最开头,包含 你指定产生pch文件的.h文件(默认是stdafx.h)不然就会有问题。如 果你没有包含这个文件,就告诉你Unexpected file end. 如果你不是在最开头包含的, 你自己试以下就知道了,绝对有很惊人的效果⋯.. fatal error C1010: unexp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值