gdb工具详解

一、 Linux命令行运行

gdb -q 进入gdb,不打印版本信息
gdb <program> 直接装载程序,但没有运行
gdb <program> <core_file> 该core文件是该program非法执行后dump出的
gdb -d <directory> 加入一个源程序搜索路径

二、 挂接正在运行的程序
 gdb
 gdb attach
 detach 取消挂接
三、 gdb中运行的常用命令
 help 查看帮助信息
 file 进入gdb之后再装载程序
 set 可指定运行参数,类似于 run 但没有立即run
 show args 查看设置好的运行参数
 next 或 n 不进入函数,仅把函数调用当成一条语句执行
 step 或 s 进入函数
 nexti 或 stepi 执行一条机器指令
 finish 运行程序,直到当前函数完成返回;并打印函数返回时的堆栈地址和返回值及参数值等信息。
 until 或 u 当不想在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。
 shell <shell_command> 即可运行shell命令
 set environment = 设置环境变量
show environment
show environment
unset environment
四、 查看源代码
 list - 显示当前行前面的源程序。
 set listsize 设置一次显示源代码的行数。
 show listsize 查看当前listsize的设置。
 directory <dirname … > = dir <dirname … > 指定源文件的路径
 加一个源文件路径到当前路径的前面。如果你要指定多个路径,UNIX下你可以使用“:”,Windows下你可以使用“;”。
 directory 清除所有的自定义的源文件搜索路径信息。
 show directories 显示定义了的源文件搜索路径。

五、 暂停方式
 断点(BreakPoint)
 观察点(WatchPoint)
 捕捉点(CatchPoint)
 信号(Signals)
 线程停止(Thread Stops)。

  1. 断点
     info breakpoints
     break
     break
     break <line/function> if
     clear 删除所有断点
     clear
     clear
     delete 删除该断点编号的断点
     disable 暂时失效
     enable 再次使能
  2. watch(观察点)
     info watchpoints
     watch 为表达式或变量设置一个观察点,一旦表达式值有变化时,停住程序
     rwatch 当表达式或变量被读时,停住程序
     awatch 当表达式或变量被读或被写时,停住程序
  3. 捕捉点(CatchPoint)
    可设置捕捉点来补捉程序运行时的一些事件。如:载入共享库(动态链接库)或是C++的异常。设置捕捉点的格式为:
     catch
    当event发生时,停住程序。event可以是下面的内容:

 throw 一个C++抛出的异常。(throw为关键字)
 catch 一个C++捕捉到的异常。(catch为关键字)

六、 查看栈信息
 bt = backtrace
 bt n是一个正整数,表示只打印栈顶上n层的栈信息。
 bt <-n> -n表一个负整数,表示只打印栈底下n层的栈信息。

七、 gdb变量
可以在GDB的调试环境中定义自己的变量,用来保存一些调试程序中的运行数据。要定义一个gdb的变量,只需使用GDB的set命令。
GDB的环境变量和UNIX一样,也是以$起头。如:
 set $foo = *object_ptr
使用环境变量时,gdb会在你第一次使用时创建这个变量,而在以后的使用中,则直接对其賦值。环境变量没有类型,你可以给环境变量定义任一的类型。包括结构体和数组。
 show convenience 该命令查看当前所设置的所有的环境变量。
环境变量和程序变量的交互使用,将使得程序调试更为灵活便捷。例如

set $i = 0
print bar[$i++]->contents 

输入这样的命令后,只用敲回车,重复执行上一条语句,环境变量会自动累加,从而完成逐个输出的功能。
于是你就不必像下面这样输入命令了。

print bar[0]->contents
print bar[1]->contents
print bar[2]->contents

八、 信号

可以告诉gdb需要处理哪一种信号。可以要求gdb在收到指定的信号时,立即停住正在运行的程序,以供进行调试。可以用gdb的handle命令来完成这一功能。

handle <signal> <keywords...>

在gdb中定义一个信号处理。信号可以以SIG开头或不以SIG开头,可以用定义一个要处理信号的范围(如:SIGIO-SIGKILL,表示处理从SIGIO信号到SIGKILL的信号,其中包括SIGIO,SIGIOT,SIGKILL三个信号),也可以使用关键字all来标明要处理所有的信号。一旦被调试的程序接收到信号,运行程序马上会被gdb停住,以供调试。其可以是以下几种关键字的一个或多个。
 nostop 当被调试的程序收到信号时,gdb不会停住程序的运行,但会打出消息告诉你收到这种信号。
 stop 当被调试的程序收到信号时,gdb会停住你的程序。
 print 当被调试的程序收到信号时,gdb会显示出一条信息。
 noprint 当被调试的程序收到信号时,gdb不会告诉你收到信号的信息。
 pass
 noignore 当被调试的程序收到信号时,gdb不处理信号。这表示,gdb会把这个信号交给被调试程序会处理。
 nopass
 ignore 当被调试的程序收到信号时,gdb不会让被调试程序来处理这个信号。
 info signals
 info handle 查看有哪些信号在被gdb检测中。
九、 用gdb简单分析死锁
当发生死锁时,进程会僵住,这时只需要杀死进程,让系统产生一个 core dump 文件,然后再对这个 core dump 文件进行分析即可。
比如,系统生成了core dump 文件,放在了/var/crash目录下,此时就可以使用 gdb 进行分析:

gdb /var/crash/<core_dump_file>

然后再:

info threads
thread <tid>
bt

即能发现死锁的位置
十、 多线程调试
 info thread 查看当前进程的线程。
 thread 切换调试的线程为指定tid的线程。
 break file.c:100 thread all 在file.c文件第100行处为所有经过这里的线程设置断点。
 thread applay [thread-id-list]/[all] args 在指定的线程上执行特定的命令args.
 set print thread-events 用于设定是否提示线程启动或停止时的信息。
 set libthread-db-search-path 指定libthread-db 的路径信息。
 set scheduler-locking off|on|step
 off 不锁定任何线程,也就是所有线程都执行,这是默认值。
 on 只有当前被调试线程会执行。
 step 阻止其他线程在当前线程单步调试时,抢占当前线程。
只有当next、continue、util以及finish的时候,其他线程才会获得重新运行的机会。

 non-stop模式
针对“一个线程中断在一个断点上,其他所有的线程都会被freeze”的情况, gdb 7.0引入了non-stop模式,即:除了断点有关的线程会被停下来,其他线程会继续执行。
设置non-stop模式的方法:
运行gdb后,开始run之前,输入下面的指令

    set target-async 1
    set pagination off
    set non-stop on   

十一、 gdb调试多进程

 follow-fork-mode
set follow-fork-mode parent|child
show follow-fork-mode
parent:fork之后继续调试父进程,子进程不受影响。
child:fork之后调试子进程,父进程不受影响。

 inferior
gdb称任何执行中的进程为inferior
 inferior :切换到指定的inferior
 info inferiors:列出当前被gdb调试的每个inferior信息
 detach inferior :detach指定的inferior,允许其正常运行

十二、 一个多线程的代码

#include <pthread.h>
#include <unistd.h>
#include <iostream>
using namespace std;


void * thread_hello(void * arg)
{
    while(1) {
        sleep(2);
        std::cout<< "Hello\n";
    }
}

void * thread_world(void * arg)
{
    while(1) {
        sleep(2);
        std::cout<< "World\n";
    }
}

int main()
{
    pthread_t pid_hello, pid_world;
    int ret = 0;    
    ret = pthread_create(&pid_hello, NULL, thread_hello, NULL);
    if (ret!=0) {cout<<"Failed to start thread_hello!\n"; return -1;}    
    ret = pthread_create(&pid_world, NULL, thread_world, NULL);
    if (ret!=0) {cout<<"Failed to start thread_world!\n"; return -1;}
    
    while(1) {
        sleep(5);
        cout << "In main thread\n";
    }
    
    pthread_join(pid_hello, NULL);
    pthread_join(pid_world, NULL);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值