GDB和COREDUMP

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhang_yin_liang/article/details/79589356

一、关于GDB

       UNIX下的程序命令行调试工具。要想用GDB调试程序,需要在编译的应用程序中加入-g的选项,如gcc -g hello.c -o hello。否则你将看不到程序的函数名和变量名,看到的全部都是运行时的内存地址。

       在学习GDB调试前,可以先学习了解到我们的函数是如何调用的:栈帧,在这个过程中我们要为函数开辟栈空间,用于临时(局部)变量的保存、现场的保护(函数的返回值和参数、调用前寄存器的状态,调用前栈帧的顶部和底部的地址),这块栈空间我们称之为函数。

       举例子,就是ESP是始终指向栈的顶部的,EBP是指向一个函数栈的栈帧顶部。所以当调用一个函数时,先将EBP的值进栈,此时ESP的指向下一个。这时将ESP的值给EBP,EBP指向新开辟的栈的位置。当调用一个函数结束时,先将EBP的值给到ESP,再出栈此时存储在栈上存储的值给EBP,此时ESP指向上一个。结束调用,回到了上一个函数的调用栈状态。

二、GDB的用途

  •     gdb <program> 

       program也就是你的执行文件,一般在当然目录下。

  •     gdb <program> core

       用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。

  •    gdb <program> <PID>

       如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程ID。gdb会自动attach上去,并调试他。program应该在PATH环境变量中搜索得到。

三、详细使用方法

http://blog.csdn.net/liigo/article/details/582231/

四、coredump   

    在不清楚BUG复现的方法,或是BUG极其罕见,又或是只在特定的机器上发生的情况下,只要获取内核转储,也能够调试。

    要产生core文件,首先要设置产生core文件的大小,ulimit -c命令可以查看当前设置的core文件大小,后面可以设置core文件大小,如命令ulimit -c unlimited,这里就是设置生成的core文件无大小限制。

     然后可以按照GDB的调试步骤看看,产生的核心错误在程序的哪里出错。

4.1 产生和位置

参考来源:https://blog.csdn.net/guanyijun123/article/details/45647247

4.1.1 产生

     在终端中输入以下命令,查看内核转储是否有效。
#ulimit -c
0
-c 表示内核转储文件的大小限制,现在显示为零,表示不能用。
可以改为1G
#ulimit -c 1073741824
也可以改为无限制
#ulimit -c unlimited
上面所述的方法,只是在当前shell中生效,重启之后,就不再有效了。永久生效的办法是:
#vim /etc/profile 然后,在profile中添加:
ulimit -c 1073741824
 (但是,若将产生的转储文件大小大于该数字时,将不会产生转储文件)
或者
ulimit -c unlimited
这样重启机器后生效了。 或者, 使用source命令使之马上生效。
#source /etc/profile

4.1.2 指定内核转储的文件名和目录

       缺省情况下,内核在coredump时所产生的core文件放在与该程序相同的目录中,并且文件名固定为core。很显然,如果有多个程序产生core文件,或者同一个程序多次崩溃,就会重复覆盖同一个core文件。
我们可以通过修改kernel的参数,指定内核转储所生成的core文件的路径和文件名。
可以通过在/etc/sysctl.conf文件中,对sysctl变量kernel.core_pattern的设置。
#vim /etc/sysctl.conf 然后,在sysctl.conf文件中添加下面两句话:
kernel.core_pattern = /var/core/core%t_%e_%p
kernel.core_uses_pid = 0

保存后退出。
需要说明的是, /proc/sys/kernel/core_uses_pid。如果这个文件的内容被配置成1,即使core_pattern中没有设置%p,最后生成的core dump文件名仍会加上进程ID。
这里%e, %p分别表示:
%c 转储文件的大小上限
%e 所dump的文件名
%g 所dump的进程的实际组ID
%h 主机名
%p 所dump的进程PID
%s 导致本次coredump的信号
%t 转储时刻(由1970年1月1日起计的秒数)
%u 所dump进程的实际用户ID
可以使用以下命令,使修改结果马上生效。
#sysctl -p
请在/var目录下先建立core文件夹,然后执行a.out程序,就会在/var/core/下产生以指定格式命名的内核转储文件。查看转储文件的情况:
#ls /var/core
core_a.out_2834

五、BUG复现

-摘自《Debug Hacks》

1、听取收集信息;

2、确认现象、复现概率和时间;

3、分析时尽量缩小范围,也可以根据版本划分问题(版本回退),不要被表象迷惑;

4、问题原因不明时,可以怀疑硬件问题,同类错误,为BUG时刻准备好,和同事讨论,上网搜索;

5、在无法差生coredump的情况下,就只能通过添加打印来实现查找崩溃的地方。不断缩小哪里产生越界导致了访问了不该访问的地址或者访问了空指针。有时候,如果是栈上越界,可以创建一个局部变量,观察这个局部变量是在哪被某个函数给越界的。

参考来源

http://blog.csdn.net/haoel/article/details/2879

六、gdbserver和GDB的调试结合

远程调试环境由宿主机GDB和目标机调试stub共同构成,两者通过串口或TCP连接。使用 GDB标准程串行协议协同工作,实现对目标机上的系统内核和上层应用的监控和调试功能。调试stub是嵌入式系统中的一段代码,作为宿主机GDB和目标机调试程序间的一个媒介而存在。 就目前而言,嵌入式Linux系统中,主要有三种远程调试方法,分别适用于不同场合的调试工作:用ROM Monitor调试目标机程序、用KGDB调试系统内核和用gdbserver调试用户空间程序。这三种调试方法的区别主要在于,目标机远程调试stub 的存在形式的不同,而其设计思路和实现方法则是大致相同的。 而我们最常用的是调试应用程序。就是采用gdb+gdbserver的方式进行调试。在很多情况下,用户需要对一个应用程序进行反复调试,特别是复杂的程序。采用GDB方法调试,由于嵌入式系统资源有限性,一般不能直接在目标系统上进行调试,通常采用gdb+gdbserver的方式进行调试。

猜你喜欢

转载自blog.csdn.net/zhang_yin_liang/article/details/79589356