gdb调试与Coredump

avatar
作者
筋斗云
阅读量:0

目录

一、gdb概述

1、gdb的调试以及常用参数解析

二、Coredump调试以及常用参数解析

1、coredump是什么?

2、前期设置

3、调试

三、其它方式(打印堆栈)


一、gdb概述

gdb是GNU 发布的一个强大的程序调试工具,也是Linux 程序员不可或缺的一大利器。

本章我们将给出gdb 常用的命令的操作说明。

1、gdb的调试以及常用参数解析

使用gdb的前提:

$ gcc -g hello.c  -o hello                                                              

启动gdb 调试:

$ gdb hello                                                                          

注意:

如果系统没有安装gdb 的同学,可以体验使用源码安装的方式来安装:

wget http://ftp.gnu.org/gnu/gdb/gdb-8.1.tar.gz tar -zxvf gdb-8.1.1.tar.gz cd gdb-8.1.1 ./configure make make install

然后就可以进入命令行操作,和 Shell 一样,gdb 支持命令补全。输入几个字母,按Tab键,gdb 会补全命令。按两次Tab ,会提示所有可能的命令。

另外,其还支持命令缩写,如, h 代表 help ,

常用命令如下:

获取帮组命令 help

gdb将命令分为12个大类,使用命令: “help 子类别”可以查看没类下面的详细帮助。

如: help breakpoints

设置断点

break 命令用于设置断点,命令接受行号或者函数名作为参数。

break也可设置条件断点:

如: break sayHello if count<1

使用info break 可以查看断点

使用 clear 可以清除断点

运行程序和单步执行

设置完断点后,就可以运行调试程序了,使用run命令(缩写为 r)运行程序至断点。

此时,程序中断,gdb 等待用户发出下一步操作的指令。设用next 命令(缩写为 n)单步执行程序。也可以指定一个数字。下面这条命令让gdb 连续执行两行,然后停下。

如果想继续运行,可以使用continue 命令(缩写为 c )指导 gdb 继续运行程序,直至遇到下一个断点。

如果想继续单步执行,可以继续使用 next,也是以使用 step (缩写为 s), step 和 next 的最大的区别在于,step 遇到函数是会进入到内部,而next 不会进入内部.

监视变量

调试程序最基本的需求就是监视变量的值,可以使用 print 命令(缩写为 p) 显示指定变量的值。

如果要时刻监视某个变量的值,那么每次使用 print 就不方便。比较人性化的是,gdb 提供了watch 命令,用于设置另一种断点:“观察点”。

用法是:  watch 变量名或表达式作为参数,一但值发生变化,就停下来。

临时修改变量

当某些特殊情况下,我们想让程序进入一些特殊的流程时,gdb允许用户在程序运行时改变变量的值,通过 set var 命令实现这一点。

 

查看堆栈情况

每次程序调用一个函数,函数的地址、参数、函数内部变量都会被压入“栈”(Stack) 中,运行时堆栈信息对于程序员非常重要,使用 “bt”命令可以看到当前运行时栈的情况。

退出 gdb

调试完毕,使用quit命令(缩写为q) 退出 gdb程序。

二、Coredump调试以及常用参数解析

1、coredump是什么?

程序异常退出时,会产生一个core文件,该文件记录了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息还有各种函数调用堆栈信息等,我们可以理解为是程序工作当前状态存储生成的一个文件,通过工具分析这个文件,我们可以定位到程序异常退出的时候对应的堆栈调用等信息,找出问题所在并进行及时解决。

2、前期设置

1) 设置core文件生成的目录,其中%e表示程序文件名,%p表示进程ID,否则会在程序的当前目录生成dore文件;echo /data/coredump/core.%e.%p >/proc/sys/kernel/core_pattern

2) 当前执行程序的用户对core目录有写权限且有足够的空间存储core文件;

3) 生成不受限制的core文件;

      ulimit  -c unlimited

什么情况下会导致程序异常退出

非法指针的访问,堆栈溢出

3、调试

编译的时候添加-g选项,增加调试信息

gdb program core_file

bt或者where查看调用栈信息

如果你要查看某一层的信息,你需要切换当前的栈,一般来说,程序停止时,最顶层的栈就是当前栈,如果你要查看栈下面层的详细信息,首先要做的是切换当前栈。     frame <n>     f <n>         n是一个从0开始的整数,是栈中的层编号。比如:frame 0,表示栈顶,frame 1,表示栈的第二层。     up <n>         表示向栈的上面移动n层,可以不打n,表示向上移动一层。     down <n>         表示向栈的下面移动n层,可以不打n,表示向下移动一层。     上面的命令,都会打印出移动到的栈层的信息。如果你不想让其打出信息。你可以使用这三个命令:             select-frame <n> 对应于 frame 命令。             up-silently <n> 对应于 up 命令。             down-silently <n> 对应于 down 命令。 查看当前栈层的信息,你可以用以下GDB命令:     frame 或 f         会打印出这些信息:栈的层编号,当前的函数名,函数参数值,函数所在文件及行号,函数执行到的语句。     info frame     info f

        这个命令会打印出更为详细的当前栈层的信息,只不过,大多数都是运行时的内内地址。比如:函数地址,调用函数的地址,被调用函数的地址,目前的函数是由什么样的程序语言写成的、函数参数地址及值、局部变量的地址等等。如:

info args         打印出当前函数的参数名及其值。 info locals         打印出当前函数中所有局部变量及其值。 

三、其它方式(打印堆栈)

/信号钩子函数,获取栈信息,然后在日志中打印 void handle_segv(int signum) {     void *array[100];     size_t size;     char **strings;     size_t i;      signal(signum, SIG_DFL); /* 还原默认的信号处理handler */      size = backtrace (array, 100);     strings = (char **)backtrace_symbols (array, size);      fprintf(stderr,"Launcher received SIG: %d Stack trace:\n", signum);     for (i = 0; i < size; i++)     {         fprintf(stderr,"%d %s \n",i,strings[i]);     }      free (strings); }  在main 函数中加入:  signal(SIGSEGV, handle_segv); // SIGSEGV    11       Core Invalid memory reference  signal(SIGABRT, handle_segv); // SIGABRT     6       Core Abort signal from  注意:编译时一定要带上 -g 选项   使用addr2line命令检测: addr2line -a 0x4007fa -e demo_log 

    广告一刻

    为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!