目录
一、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