您的位置:首页 > 运维架构 > Linux

linux下gdb调试解决core dumped问题

2017-07-07 21:54 441 查看
      最近因为忙于期末考试,前面学习过程中遇到的问题一直没有总结,现在考试考完了,终于有时间搞自己的事情,开兴ing.今天把自己写代码遇到的问题总结一下!之前在学习C语言编程操作sqlite3数据库遇到了Segmentation fault(core dumped)错误,但是因为代码有点长直接肉眼找到错误所在,比较浪费时间,所以就上网查找有没有相关快速调试的方法,网上一搜,果然有大神写过类似的文章。其实之前早就听说过linux下可以使用GDB工具来调试代码,但是由于自己写的代码不算多,所以用到gdb就很少,这次用到了,感觉调试代码还是比较快速的,能够快速定位问题所在。下面就讲讲自己遇到的问题及解决方法:
上代码:
60       /* 查询数据 */
61       sql="select *from SensorData";
62       sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg     );
63       printf("nrow=%d ncolumn=%d\n",nrow,ncolumn);
64       printf("the result is:\n");
65       for(i=0;i<(nrow+1)*ncolumn;i++)
66         {
67           printf("azResult[%d]=%s\n",azResult[i]);
68         }

这只是其中的部分代码,然而元凶就在这段代码里面,由于我已经追踪到问题所在,肉眼一看就知道罪魁祸首就是printf函数少参,然而对于代码较长,具体的调试方法如下:
[zoulei@CentOS test]$ gcc -g sqlite.c -l sqlite3
[zoulei@CentOS test]$ls
a.out   sqlite.c
[zoulei@CentOS test]$./a.out
You have opened a sqlite3 database named user successfully!
table SensorData already exists
nrow=9 ncolumn=5
the result is:
段错误 (core dumped)
[zoulei@CentOS test]$ulimit -c
0
[zoulei@CentOS test]$ulimit -c 999
[zoulei@CentOS test]$ulimit -c
999
[zoulei@CentOS test]$ ls
a.out  core.6501  sqlite.c
[zoulei@CentOS test]$gdb a.out core.6501
[zoulei@CentOS test]$ gdb a.out core.6501
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-92.el6)
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 "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/zoulei/test/a.out...done.
[New Thread 6501]
Reading symbols from /usr/lib/libsqlite3.so.0...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libsqlite3.so.0
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/libdl.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/libdl.so.2
Reading symbols from /lib/libpthread.so.0...(no debugging symbols found)...done.
[Thread debugging using libthread_db enabled]
Loaded symbols for /lib/libpthread.so.0
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0  0x00bc7a4f in __strlen_ia32 () from /lib/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.166.el6_7.3.i686 sqlite-3.6.20-1.el6.i686
(gdb) bt
#0  0x00bc7a4f in __strlen_ia32 () from /lib/libc.so.6
#1  0x00b9223f in vfprintf () from /lib/libc.so.6
#2  0x00b99210 in printf () from /lib/libc.so.6
#3  0x080488de in main (argc=1, argv=0xbfc17ed4) at sqlite.c:67
(gdb) quit

通过上面的操作我们快速的定位到问题出现在sqlite.c文件的第67行,果然是printf函数少参的原因。
****************************************************************************************************************************************************************************************************
注意:
        1.ulimit命令是用于shell启动进程 所占用的资源,ulimit后面再跟一些参数就能对相应的资源进行修改。比如:shell所占用的硬资源,软资源,core文件最大值等等。这次我使用到的ulimit -c是用来查询所设定的core文件大小的, 可以看到, 在默认情况下为0, 所以执行./a.out的时候, 并没有core文件生成。 我们把它设置为999,
然后在执行./a.out, 可以看到, 有core文件(core.6501)生成。 然后利用gdb来调试core文件,此时用gdb的bt命令来看堆栈,就可以看出问题出现在sqlite.c文件的67行。
        2.还要注意的一点是上面我用gcc调试的时候加上了参数-g,这个参数对于使用gdb调试代码很重要。因为加上-g参数的话就可以将调试所需的调试信息保存下来。如果没有-g, 那么只能知道程序出错的堆栈地址, 却无法知道对应的代码行。
        3. 使用gdb调试的时候后面跟的是可执行文件,不能搞错。
*************************************************************************************************************************************************************************
下面再来看一个例子:
/*********************************************************************************
*      Copyright:  (C) 2017 zoulei
*                  All rights reserved.
*
*       Filename:  test.c
*    Description:  This file
*
*        Version:  1.0.0(2017年07月06日)
*         Author:  zoulei <zoulei121@gmail.com>
*      ChangeLog:  1, Release initial version on "2017年07月06日 19时22分38秒"
*
********************************************************************************/

#include<stdio.h>
int main(int argc,char**argv)
{
int *p = NULL;
*p = 0;

printf("bad\n");
return 0;
}


C语言学的比较好的人一眼就知道哪里不对!不过大型项目中可不能通过肉眼来观看,借助工具是最佳选择!最近逛csdn发现一位大神用addr2line命令来调试代码感觉蛮实用的,下面演示一下:
[zoulei@CentOS test]$ ls
a.out  test.c
[zoulei@CentOS test]$ ./a.out
段错误 (core dumped)
[zoulei@CentOS test]$ dmesg |grep a.out
virtual kernel memory layout:
a.out[2888]: segfault at 5 ip 00bc7a4f sp bfc86818 error 4 in libc-2.12.so[b4e000+190000]
a.out[4129]: segfault at 0 ip 080483c9 sp bfeae680 error 6 in a.out[8048000+1000]
a.out[4137]: segfault at 0 ip 080483c9 sp bfedc790 error 6 in a.out[8048000+1000]
[zoulei@CentOS test]$ addr2line -e a.out 080483c9
/home/zoulei/test/test.c:18
[zoulei@CentOS test]$

通过运行程序知道出现了段错误(core dumped),用dmesg命令查出程序core dumped对应的地址为:080483c9,然后利用addr2line命令转换为对应的代码行。通过使用addr2line命令后,可以知道问题出现在/home/zoulei/test/test.c:18行,回头再看代码,果然是18行指针赋值出错问题!
******************************************************************************************************************************
4000
*******************************************
注意:
        Addr2line 工具(它是标准的 GNU Binutils 中的一部分)是一个可以将指令的地址和可执行映像转换成文件名、函数名和源代码行数的工具。
        在调用 Addr2line 工具时,要使用 
-e
 选项来指定可执行映像是
a.out

在使用该addr2line工具之前,必须了解两个概念:
     1. epc:在学校我们学习汇编的时候知道pc是CPU保存当前运行指令地址的寄存器,那么这个epc就是error pc。保存的是当程序崩溃时,造成指令异常的那条指令的地址。也就是问题的第一现场。比如,程序因为非法地址访问造成了死机,那么epc保存的就是直接造成非法地址访问的那条指令的地址。
     2. ra:当前程序返回地址。当程序进行函数调用时更新该寄存器。当程序死机时,该地址就是第二现场。
        一般程序崩溃时都有epc、ra的地址打印出来。
*************************************************************************************************************************************************************************

    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: