GDB调试详解

1、简介

GDB(GNU Debugger)是GCC的调试工具,其功能强大,主要帮你完成以下4个方面的功能: 
1.启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。 
2.可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式) 
3.当程序被停住时,可以检查此时你的程序中所发生的事。 
4.动态的改变你程序的执行环境。

2、生成调试信息

一般来说GDB主要调试的是C/C++的程序。要调试C/C++的程序,首先在编译时,我们必须要把调试信息加到可执行文件中。使用编译器(cc/gcc/g++)的 -g 参数可以做到这一点。如:

g++ -g HelloWorld.cpp -o HelloWorld

查看ELF信息(顺带说一下,ELF文件是release还是debug也可通过该命令查看):


可见加了-g参数,可执行文件中包含了调试信息,如果我们不加-g参数,可执行文件中就不会包含这些调试信息,大家可自行验证一下。

3、启动GDB

shell环境下输入命令“gdb”,启动gdb:

输入gdb命令“file HelloWorld”,装载想要调试的可执行程序,也可以执行命令“gdb HelloWorld”在启动gdb时就装载。

4、查看源码

help list                       //查看list命令帮助
list                              //查看当前行附近10行,再次执行查看后10行
list -                           //查看当前行的前10行
list linenum                  //查看第linenum行附近10行 
list numbegin,numend  //查看第numbegin行到第numend行
list function                 //查看function函数附近10行
list file:linenum             //查看file文件第linenum行附近10行
list file:function            //查看file文件function函数附近10行
list *address                //查看地址为address的符号附近的10行

5、断点操作

break linenum                                    //在当前源文件的第linenum行设置断点
break function                                    //在function函数入口处设置断点
break file:linenum                              //在file文件的第linenum行设置断点
break file:function                              //在file文件的function函数入口处设置断点
break class::function                         //在类class的function函数入口处设置断点

break namespace::class::function     //在命名空间为namespace的类class的function函数的入口处设置断点

info break    //查看断点信息

6、调试代码

run 运行程序,可简写为r
next 单步跟踪,函数调用当作一条简单语句执行,可简写为n
step 单步跟踪,函数调进入被调用函数体内,可简写为s
finish 退出函数
until 在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体,可简写为u
continue 继续运行程序,可简写为c
stepi或si, nexti或ni 单步跟踪一条机器指令,一条程序代码有可能由数条机器指令完成,stepi和nexti可以单步执行机器指令
info program 来查看程序的是否在运行,进程号,被暂停的原因

7、查看运行时数据

print 打印变量、字符串、表达式等的值,可简写为p 
p count 打印count的值 
p cou1+cou2+cou3 打印表达式值
print接受一个表达式,GDB会根据当前的程序运行的数据来计算这个表达式,表达式可以是当前程序运行中的const常量、变量、函数等内容。但是GDB不能使用程序中定义的宏。

以上是GDB的常用操作,请参考:http://www.cnblogs.com/ggjucheng/archive/2011/12/14/2288004.html

8、多进程调试

8.1 attach子进程
最近正在调试PostgreSQL数据库,就以此为例。
查看PostgreSQL进程:

终端连接PostgreSQL数据库后,服务端创建了一个子进程来处理,该子进程id为3438。
gdb ./bin/postgres 启动gdb加载可执行程序后执行gdb命令 attach 3438 附加到进程,如下图:


为了调试数据库对SQL的处理流程,我们在函数exec_simple_query入口处设置断点,命令如下:
break exec_simple_query
在终端执行了一个SQL语句后,数据库服务程序停在了断点处,此时我们可以查看源码,执行单步调试,查看变量值等操作,具体参见前面章节。


问题:子进程一直在运行,attach上去后,不知道运行到哪里了。比如上面的例子,子进程阻塞在等待客户端的请求,我们只能调试从这以后的代码的执行,而子进程启动和初始化过程我们已经错过,无法调试了。
解决的办法:在子进程初始化代码中,比如main函数开始处,加入一段特殊代码,使子进程在某个条件成立时循环睡眠等待,attach到该子进程后在该段代码后设置断点,再把成立的条件取消,让代码继续执行下去。

至于这段代码的执行条件,看个人偏好了。比如我们可以检查一个指定的环境变量的值,或者检查一个特定文件是否存在。以文件为例,其代码如下:
void debug_wait(const char* trigger_file)
{
    while (1)
    {
        if (trigger_file 不存在)
        {
            睡眠一段时间;
        }
        else
        {
            break;
        }
    }
}
当attach到该子进程后,在该段代码后设置断点,再创建trigger_file让进程在断点处暂停,便可以调试了。

8.1 catch fork
默认设置下,在调试多进程程序时GDB只会调试主进程。但是GDB(>V7.0)支持多进程的 分别以及同时 调试,换句话说,GDB可以同时调试多个程序。只需要设置follow-fork-mode(默认值:parent)和detach-on-fork(默认值:on)即可。catch fork命令可以捕获进程的创建,inferior命令可以切换进程。这些让GDB的多进程调试变得非常方便。下面分享一篇这方面的博客,对我的工作帮助很大。
http://blog.csdn.net/pbymw8iwm/article/details/7876797

9、多线程调试

GDB多线程调试一个重要的设置参数就是scheduler-locking,取值on、off、step,默认为step。
show scheduler-locking  //显示当前scheduler-locking
set scheduler-locking [on/off/step]  //设置scheduler-locking

注意:set scheduler-locking要处于线程运行环境下才能生效,也就是程序已经运行并且暂停在某个断点处,否则会出现“Target 'exec' cannot support this command.”这样的错误;而且经过测试,设置后的scheduler-locking值在整个进程内有效,不属于某个线程。

下面根据实际测试结果对scheduler-locking的3种取值进行说明:
on:只有当前调试线程运行,其他线程处于暂停状态。
off:当前调试线程外的其他线程一直在正常运行。
step:其他线程跟随当前调试线程运行,但具体怎么协同运行,测试中无法体现。

10、core文件调试



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值