调试时不要开启任何优化选项
转自:http://mathslinux.org/?p=237
如果在编译的时候开启了一些优化选项, 比如 -O2, -O3 什么的, 有的变量/函数会被 gcc 自动优化掉, 比如以下的代码片段:
for (i = 0; i < msg->num_of_channels; i++) { channel_new_t *c; c = g_new(channel_new_t, 1); c->session = g_object_ref(session); c->type = msg->channels[i].type; c->id = msg->channels[i].id; /* no need to explicitely switch to main context, since synchronous call is not needed. */ /* no need to track idle, session is refed */ g_idle_add((GSourceFunc)_channel_new, c); }
当我 break 到这行, 想查看 i
和 channels[i]
的值时, 开启优化选项和 未开启的区别如下:
// CFLAGS="-g" 1430 c->type = msg->channels[i].type; (gdb) p i $9 = <optimized out> // CFLAGS="-g -O0" 1430 c->type = msg->channels[i].type; (gdb) p i $1 = 0 (gdb) p msg->channels[0] $2 = {type = 5 '\005', id = 0 '\000'}
要关闭 gcc 的优化, 通常可以通过以下途径达到:
- 如果程序的 configure 脚本提供了 “–enable-debug”, 打开它
- 在正式编译代码的的时候, 定制 CFLAGS 参数, 去掉优化选项(使用 -O0), e.g. make CFLAGS=”-O0 -g”
core dump
默认情况下, 当程序发生 Segmentation fault 时, 内核只是简单的把该进程结束, 不做任何事情, 如果想要保留出错时候的上下文, 可以使用 ulimit -c unlimited 设置dump core 文件 的大小, 使其不为0(或者用 setrlimit()设置).
这样, 程序 Segmentation fault 的时候, 会在当前目录下(或者 /var/***) 下 生成一个 名为 core(或者 core.*) 的文件, 用 gdb 工具就可以看到程序到底为什么 Segmentation fault 了.
例如下面的程序, 明显的有一个非法内存访问:
#include <stdio.h> int main(int argc, char *argv[]) { char *s = NULL; sprintf(s, "foo"); return 0; }
编译运行后, 会得到一个 名为 core 的文件, 用 gdb 打开, 然后 gdb 会停在程序 出错的地方, 查看 s 的值, 可以看到 s 的值为 0×0, 即传递了一个非法的内存引用给 sprintf() 函数引发了异常.
$ ulimit -c unlimited $ gcc -o test test.c -g $ ./test Segmentation fault (core dumped) $ gdb test core Core was generated by `./test'. Program terminated with signal 11, Segmentation fault. #0 0x0000000000400512 in main (argc=1, argv=0x7fff7eed3048) at test.c:6 6 sprintf(s, "foo"); (gdb) bt #0 0x0000000000400512 in main (argc=1, argv=0x7fff7eed3048) at test.c:6 (gdb) p s $1 = 0x0