<2012年5月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

文章分类

导航

订阅

在Linux下调试应用程序崩溃

好久没有写博客了,忙忙碌碌,无所作为,甚是惭愧啊。今天有些空,写点与以前不一样的吧。这几年,偶尔也在Linux下写些程序,比如虚拟化系统,驱动程序,偶尔也写应用程序。有软件的地方就有BUG,于是就要Debug。Linux下的调试还是有些不同。今天先聊聊因为内存访问违例而导致应用程序崩溃吧。以下面的小程序为例:
int main(int argc, char **argv){
    char *s;
    *s = 0;
    printf("should never see this message\n"); 
    return 0;
}
当其运行时,屏幕上会留下一句Segmentation fault就结束了,没有对话框,没有发送错误报告,闪都不闪一下就没了,干脆利落。如何调试呢?习惯了Windows下的自动启动调试器,到了Linux下还真有点无从下手。
到底从哪查起呢?可以先用dmesg搜一下,在控制台窗口执行如下命令:
dmesg | grep segfault
应该会得到下面这样一条信息: [57.583572] segfault[1667]: segfault at 265ff4 ip 080486c3 sp bffc8110 error 7 in segfault[8048000+1000]
其含义依次是:
[时间] 程序名[进程号]: 程序名 at 被访问的内存地址 ip 发起访问的指令地址 sp 栈指针 error 7 in segfault[模块起始地址+1000]
这个错误信息,相当于知道了导致错误的指令地址,但是通常这还不够,如何进一步调试这样的问题呢?可以尝试如下方法。

方法一:修改编译选项,产生MAP文件,然后根据MAP文件查找错误指令说对应的源代码。

方法二: 使用调试器做交互式调试 最常用的调试器便是GDB。如果系统中没有GDB,那么可以尝试从其它Linux机器复制,依赖的文件并不是很多,曾经两次抱着试一试看的想法这样做,都成功了。对于调试应用程序崩溃,需要在GDB中启动被调试程序,或者在崩溃前把GDB附加上去。或者修改源程序,在程序收到异常信号后,创建调试器进程,这相当于模仿JIT调试。如果想尝试,那么可以参考下面这个页面中的代码:

http://osdir.com/ml/gdb.devel/2002-06/msg00069.html
或者参看这一篇:
http://stackoverflow.com/questions/17965/generate-a-core-dump-in-linux

附加GDB后,如果再发生非法访问,会中断到GDB,然后可以使用GDB的bt命令来观察栈回溯,寻找崩溃的原因,这与WinDBG调试就很相似了。

方法三:产生CORE Dump 有时可能需要使用ulimit命令启用core dump,比如ulimit -c unlimited;如果设置后还不能产生dump,那么可能是编译内核时禁止了这项功能。产生core文件后,可以使用GDB来分析。

因为Linux机器不在手边,有些细节只好略去了...

posted on 2011年4月4日 21:50 由 Raymond

Powered by Community Server Powered by CnForums.Net