您的位置:首页 > 编程语言 > C语言/C++

GDB 调试 C++ 程序 core dump

2016-08-03 14:47 375 查看


摘要

gdb 的一些常用命令, 及在程序发生段错误后如何通过调试 core dump 迅速定位到出错位置.

不罗列一大堆命令了, 只是把碰到的/用过的整理一下, 以后再使用到新的命令, 再补充. 有几篇总结的比较好的文章可以参考: 《LINUX C/C++ GDB调试(概述)上》、《LINUX
C/C++ GDB调试(概述)下》、《手把手教你玩转GDB(二)——Breakpoint, Watchpoint和Catchpoint》


1. 添加调试信息

为了能使用 gdb 进行调试, 需要添加 -g 选项添加调试信息.

g++ -g test.cpp -o test


2. 常用命令

使用 gdb test 即可以进入调试程序, 以下列出几个常用命 令.
显示图形化代码 Ctrl+x+a
启动程序 r (run)
断点 b (breakpoint)
清除/禁用/启用断点 delete/disable/enable
单步 s (step 碰到函数会进入)
单行 n (next 碰到函数不会进行, 而是整条执行)
执行到下一个断点 c (continue)
查看变量 p (print)
显示变量 display
查看当前调用堆栈 bt (backtrace)
查看某一层调用代码 f (frame)


3. 调试 core dump

程序执行时, 经常会因为段错误(Segment Fault)而退出, 操作系统会把此程序当前内存信息 dump 到磁盘上(详见 wiki), 即生成 core 文件. 对 core 进行分析可以很快分析出导致程序 crash 的地方.


(1). 设置 core 文件大小

系统默认不会生成 core 文件, 需要进一步设置. core 文件的生成依赖于 shell 的设置, 在 shell 中运行命令: ulimit -a, 从第一行的设置项可以看到系统设置的 core file size 为 0, 即不生成 core file.



使用命令: ulimit -c unlimited 可以设置 core file size 为无限.




(2). 生成简单 core 文件

在 C++ 中制造一个 segment falt 太容易了, 直接给一个空指针赋值就可以了.

int main(int argc, char const *argv[]) 



char* p = nullptr; 

*p = ‘a’; 

return 0; 



保存文件为 coreDumpTest.cpp, 编译并运行, 即可以现磁盘上多了一个 core 文件, 就是这个程序发生段错误 dump 下来的进程信息.




(3). 调试简单 core 文件

使用 gdb ./coreDumpTest core 来调试 core, 发现 gdb 直接就定位到了出错的语句(第4行赋值语句), 还可以通过 print 来查看当前上下文变量, 如指针 p 的值为 nullptr.




(4). 生成稍复杂 core 文件

上面的例子太简单了, 下面通过一个稍微复杂的例子来介绍一下 gdb 中命令 backtrace 和 frame 的使用. 下面代码很简单, 就是越界访问, 用 vector 是为了体现调用层次…
<code class="hljs cpp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <vector></span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">using</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">namespace</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">std</span>;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> argc, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> *argv[])
{
<span class="hljs-stl_container" style="box-sizing: border-box;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">vector</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>></span> a;
<span class="hljs-stl_container" style="box-sizing: border-box;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">vector</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>></span> b;

b.push_back(a[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]);

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>


(5). 调试稍复杂 core 文件 

编译运行程序, 生成 core 文件, 使用 gdb 来调试 core, 可以看到此时直接定位到的地方是库函数中的某一行;



库函数都是经过千锤百炼, 基本不可能出错, 所以我们先从自己的程序找起. 这时我们需要知道的是代码是从哪条语句执行到这里的, 使用 backtrace(或者 where) 命令列出当前调用堆栈, 再使用 frame n 命令列出第 n 层堆栈的信息, 就可以直接看到出错的代码语句了, 接下来就是进一步分析了.




4. 简化版步骤

(1). 首先利用file core.19344命令可以得到

core.19344: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from ‘cmm_test_tool’

可以看出core.19344是由cmm_test_tool这个工程产生。

(2). 接着就可以利用命令gdb进行查找,格式为gdb 工程名 core文件名,例如 gdb cmm_test_tool core.19344

(3). 最后一个步骤是输入where,找到错误发生的位置和堆栈,如下:

(gdb) where 

#0 0×4202cec1 in __strtoul_internal () from /lib/i686/libc.so.6 

#1 0×4202d4e7 in strtoul () from /lib/i686/libc.so.6 

#2 0×0804b4da in GetMaxIDFromDB (get_type=2, max_id=0×806fd20) at cmm_test_tool.c:788 

#3 0×0804b9d7 in ConstrctVODProgram (vod_program=0×40345bdc) at cmm_test_tool.c:946 

#4 0×0804a2f4 in TVRequestThread (arg=0×0) at cmm_test_tool.c:372 

#5 0×40021941 in pthread_start_thread () from /lib/i686/libpthread.so.0 (gdb)

至此,可以看出文件出错的位置是函数 GetMaxIDFromDB ,两个参数分别是2和0×806fd20,这个函数位于源代码的788行,基于此,我们就可以有针对性的找到问题的根源,并加以解决。


4. 待添加:

设置 core file size 在所有 shell 都生效, 不要每次打开一个 shell 就要设置一下.

vim /etc/profile

添加:ulimit -c unlimited

【转自:http://my.oschina.net/zenglingfan/blog/169871, 
http://blog.csdn.net/lemonxuexue/article/details/4577413
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  gcc gdb 调试 c++11 c++