gdb(GNU Debugger)它是GNU组织发布的程序调试工具,在UNIX和类UNIX操作系统上都可使用GDB,目前GDB所能支持的编程语言有C,C++,JAVA等语言,主要用于调试C/C++.gdb以纯文本命令行执行,操作者熟悉以后可以利于它方便的调试程序,把程序的BUG找出来,同时它适用于子进程,多线程的调试.
编译选项
在程序源代码进行编译的时候,gcc的选项必须加上-g把调试信息加入到可执行文件中去,这样才可以通过gdb对程序进行调试查错.如:
> gcc -g hello.c -o hello
-g选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证gdb能找到源文件。如果源代码文件不在也是无法对应到源代码的,无法的清晰的对应到程序.另外如果不加入-g,你将看不见程式的函数名、变量名,所代替的全是运行时的内存地址。
gdb的启动
1.>gdb <程序名>
2.>gdb <程序名> <core File> (或者>gdb <进程名> –c <core file>)
3.>gdb <程序名> <pid> (或者>gdb –p <pid>) (或者>gdb attach <pid>)
常见指令
单步调试指令 | |
Start | 启动进程 |
next(n) | 单步运行程序-不进入函数 |
step(s) | 单步运行程序-进入函数体 |
空格 | 重复上次指令 |
断点调试指令 | |
run(r) | 运行进程 |
continue(c) | 继续运行 |
break(b) 行号 | 在指定行号设置断点 |
break(b) 函数名 | 在进入函数前断点停止 |
break(b) 文件名:行名/函数名 | 指定某个文件的断点, |
break(b) 行号 if <condition> | 当条件满足时,在某处发生断点 |
info break | 列出当前断点 |
delete break [n] | 删除指令的断点 |
clear | 清除断点 |
quit(q) | 退出gdb |
调试信息输出 | |
list(l) | 列出源代码 |
backtrace | 显示所有的调用栈桢 |
up | 上移栈桢 |
down | 下移栈桢 |
info stack | 显示所有的调用栈桢 |
info locals | 显示函数中的局部变量 |
whatis <变量名> | 显示指定变量的类型 |
print(p) <变量名> | 打印变量值 |
x | 打印内存内容 |
x/16bx &aa | 从变量aa的内存地址开始读取16字节的内容,16b:16字节,x以16进制显示。 |
x/3hu 0x8054320 | 从内存地址0x8054320读取内容,3h显示3个[双字节]内容,u表示按无符号显示。默认为10进制 |
where | 查看进程运行到哪里了 |
display/undisplay [变量名] | 断点发生时,同时显示变量的值./关闭跟踪显示 |
set variable <变量>=<值> | 设置变量的值进行调试 |
help | 帮助 |
线程指令 | |
info thread | 列出进程的所有线程 |
thread [n] | 进入指定线程 |
|
|
设置 | |
set follow-fork-mode child | 进程直接进入子进程 |
|
|
段错误快速发现
段错误通常发生在内存溢出,非法访问造成,在我们平时程序中经常出现的问题,对问题的发现和跟踪也是非常的麻烦,这里我们通常gdb来快速发现段错误的发生地.
如下进程发现了段错误,如果通过printf去逐行调试是比较麻烦.
[root@host70-151 kernel]# ./gdb_core
段错误
通过gdb来运行,就为我们提供调试程序提供了更的帮助信息.
[root@host70-151 kernel]# gdb ./gdb_core
Program received signal SIGSEGV, Segmentation fault.
main () at kernel/gdb_core.c:9
9 p[6] = 'B';
(gdb)
进程阻塞查询(实战)
联通网关SGIP进程经常出现不工作情况,对它进行调试,首先netstat或者lsof查看当前的网络连接是否还在.发现进程一切进程,如此初步判断进程应该是出现了阻塞.下面使用gdb进入进程调试:
>gdb -p <pid>
(gdb) info stack /*打印所有的栈桢*/
#0 0x001d92e6 in recv () from /lib/i686/libc.so.6
#1 0x0805d555 in CSocket::Receive (this=0xbffff7a8, p_pchBuf=0xbfffed40 "", p_iLen=1024, p_iFlag=0) at lib/Socket.cpp:431
#2 0x0804fccb in SGIPInterface::UnBindSMG (this=0xbffff770) at lib/SGIPInterface.cpp:493
#3 0x08050b05 in SGIPInterface::Start (this=0xbffff770) at lib/SGIPInterface.cpp:617
#4 0x0804ab9e in main () at kernel/SGIPClient.cpp:32
发现进程在调用recv的时候出现阻塞,同时它是UnBindSMG的时候.进入相应代码进行修改.
gdb调试core异常退出
在程序还进入稳定期,进程会在少数情况下出现异常,这种异常情况通常很难模拟,程序的问题也很发现,而且进程还会退出去,这种情况下就是程序员非常头痛的事情.下面我们提出一个core文件的解决办法.
core dump设置
Linux默认情况下是关键了core文件的生成,我们需要将它打开.我们首先通过ulimit观察core的状态.
[root@host70-151 kernel]# ulimit -a
core file size (blocks, -c) 0
这里需要注意的是它的单位是blocks,一个block在磁盘对应一个扇区,每个扇区大小为512字节.如果我们要设置core大小5K,那么如下操作
[root@host70-151 kernel]# ulimit -c 10
core文件调试
gdb <程序名> <core文件名>
注意这里调试的时候一定要加上的程序名,而不只是加上core文件名.下面这个例子会生成core文件,core文件名通常为core.<pid>,如core.19203,后面跟着进程号.
/*
* file name: gdb_core.c
*/
#include "inc.h"
static void fun()
{
unsigned char *p;
p = 0x8048000;
p[6] = 'B';
printf("%s\n", p);
}
int main()
{
printf("%d\n", getpid());
fun();
return 0;
}
运行上面程序会直接退出,同时生成core文件.现在我们对它进行调试,找出问题所在:
[root@host70-151 kernel]# gdb gdb_core core.1670
Core was generated by `./gdb_core'.
Program terminated with signal 11, Segmentation fault.
[New process 1670]
#0 main () at kernel/gdb_core.c:9
9 unsigned char *p;
(gdb) where
#0 main () at kernel/gdb_core.c:9
(gdb) bt
#0 main () at kernel/gdb_core.c:9
如上可以发现进程发生段错误,系统给出了11号信号.程序最后的执行到了第9行.
其他
gdb还可以远程调试android可以查阅相关资料。
Linux下面还可以配合跟踪工具配合调试,如:strace mtrace ltrace
strace –f 进程 : -f 跟踪由fork调用所产生的子进程.