GDB 调试 C/C++ Project
平时做算法题目, 没少用到 GDB, 但今天才意识到 Project 的调试方法与单个 cpp 文件的不同之处, 比如 gdb list 命令, 在单个 cpp 文件中列出的是源代码, 但在 project 中却什么都不显示
Project Debug 时, file 参数的使用 [1] 有讲解, UP 主问的问题和我遇到的一样, 只不过, 没能解决我的问题(我的问题更2B一些).
出现的错误
1. 执行命令, make, gdb test, gdb l
No symbol table is loaded.
最终解决方法是在 make 里, 每生成一个 .o 文件都需要 -g 参数
2. 段错误 segment fault
段错误是一种内存保护机制, 当进程访问许可空间范围以外的内存时便会引发内核的 "一般保护性异常", 内核向程序发出 SIGSEGV(11) 信号, 而这个信号的 handler 默认工作就是在控制台打出一个 segment fault 并产生内核转储文件(Core), 结束掉当前正在运行的程序.
段错误的成因有一下几种(不完全统计)
2.1 程序访问系统数据区, 比如对为 NULL 的指针解引用, 或写入数据
2.2 内存访问越界 (数组越界)
2.3 对 malloc, new 申请的空间二次释放
2.4 操作系统的段保护机制, 导致因缓冲区溢出而对非法内存访问
2.5 无限递归, 导致堆栈溢出
2.6 fclose 对一个 FILE* 二次释放
调试工具 Valgrind
Valgrind 是一款用于内存调试, 内存泄露检测和性能分析的软件开发工具, 但 Valgrind 只能检测到堆的异常和泄露, 对栈的爱莫能助.
Valgrind 原理与用法
我们刚才提到段错误会引发内核转储(Core), Core 记录了 down 掉程序的映像和一些调试信心, valgrind 需要 core, 但是并不是所有的系统都默认提供 core, 可通过 ulimit -a 查看 core 是否默认设置, 我查了下, 自己的机器是 (blocks, -c) 0, 说明 core 默认不提供, 所以需要通过 ulimit -c 1024 来设置 core 大小. 但通过 ulimit 设置在重启机器后失效.
我们重新编译自己出错程序, 在 g++ 后加上 -g -rdynamic 参数, -g 是添加调试信心, 而 -rdynamic 是通知链接器把所有符号添加到动态符号表, 再次运行程序, ls, 会看到一个 core 开头的文件, 我们用 gdb ./yourprogram core 来查看是哪个文件哪一行, 什么代码出现了异常. 假如你没有看到 core 文件, 那么重新检查下 ulimit 设置.
Reference
[1] http://stackoverflow.com/questions/9245685/gdb-no-symbol-table-is-loaded
[2] http://through-my-eyes.diandian.com/post/2012-11-20/40043131231