gdb的一些常用用法

版权声明:本文为博主原创文章,可以转载但必须注明出处。 https://blog.csdn.net/nirendao/article/details/85864050

gdb笔记

gdb的命令非常多,以下是在整理网上的几篇文章并结合自己的实践的基础上,罗列一些常用的用法,包括了多线程和多进程的调试。

  1. Linux命令行运行
  • gdb -q 进入gdb,不打印版本信息
  • gdb <program> 直接装载程序,但没有运行
  • gdb <program> <core_file> 该core文件是该program非法执行后dump出的
  • gdb -d <directory> 加入一个源程序搜索路径
  1. 挂接正在运行的程序
  • gdb <program> <pid>
  • gdb attach <pid>
  • detach 取消挂接
  1. gdb中运行的常用命令
  • help 查看帮助信息
  • file <program> 进入gdb之后再装载程序
  • set <args> 可指定运行参数,类似于 run <args> 但没有立即run
  • show args 查看设置好的运行参数
  • next 或 n 不进入函数,仅把函数调用当成一条语句执行
  • step 或 s 进入函数
  • nexti 或 stepi 执行一条机器指令
  • finish 运行程序,直到当前函数完成返回;并打印函数返回时的堆栈地址和返回值及参数值等信息。
  • until 或 u 当不想在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。
  • shell <shell_command> 即可运行shell命令
  • set environment <varname>=<varvalue> 设置环境变量
    show environment
    show environment <varname>
    unset environment <varname>
  1. 查看源代码
  • list - 显示当前行前面的源程序。
  • set listsize <count> 设置一次显示源代码的行数。
  • show listsize 查看当前listsize的设置。
  • directory <dirname … > = dir <dirname … > 指定源文件的路径
    加一个源文件路径到当前路径的前面。如果你要指定多个路径,UNIX下你可以使用“:”,Windows下你可以使用“;”。
  • directory 清除所有的自定义的源文件搜索路径信息。
  • show directories 显示定义了的源文件搜索路径。
  1. 恢复/暂停程序在gdb中,有以下几种暂停方式。如果要恢复程序运行,可以使用c或是continue命令。
  • 断点(BreakPoint)
  • 观察点(WatchPoint)
  • 捕捉点(CatchPoint)
  • 信号(Signals)
  • 线程停止(Thread Stops)。

5.1 断点

  • info breakpoints
  • break <function>
  • break <line num>
  • break <line/function> if <condition>
  • clear 删除所有断点
  • clear <line num>
  • clear <function>
  • delete <breakpoint num> 删除该断点编号的断点
  • disable <breakpoint num> 暂时失效
  • enable <breakpoint num> 再次使能

5.2 watch(观察点)

  • info watchpoints
  • watch <expr> 为表达式或变量设置一个观察点,一旦表达式值有变化时,停住程序
  • rwatch <expr> 当表达式或变量被读时,停住程序
  • awatch <expr> 当表达式或变量被读或被写时,停住程序

5.3 捕捉点(CatchPoint)
可设置捕捉点来补捉程序运行时的一些事件。如:载入共享库(动态链接库)或是C++的异常。
设置捕捉点的格式为:

  • catch <event>

当event发生时,停住程序。event可以是下面的内容:

  • throw 一个C++抛出的异常。(throw为关键字)
  • catch 一个C++捕捉到的异常。(catch为关键字)
  • 等等
  1. 查看栈信息
  • bt = backtrace
  • bt <n> n是一个正整数,表示只打印栈顶上n层的栈信息。
  • bt <-n> -n表一个负整数,表示只打印栈底下n层的栈信息。
  1. 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
  1. 信号

可以告诉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检测中。
  1. 用gdb简单分析死锁

当发生死锁时,进程会僵住,这时只需要杀死进程,让系统产生一个 core dump 文件,然后再对这个 core dump 文件进行分析即可。
比如,系统生成了core dump 文件,放在了/var/crash目录下,此时就可以使用 gdb 进行分析:

gdb /var/crash/<core_dump_file>

然后再:
info threads
thread <tid>
bt
即能发现死锁的位置

  1. 多线程调试
  • info thread 查看当前进程的线程。

  • thread <tid> 切换调试的线程为指定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 <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   
    
  1. gdb调试多进程
  • follow-fork-mode

    set follow-fork-mode parent|child
    show follow-fork-mode

    parent:fork之后继续调试父进程,子进程不受影响。
    child:fork之后调试子进程,父进程不受影响。

  • inferior
    gdb称任何执行中的进程为inferior

    • inferior <pid>:切换到指定的inferior
    • info inferiors:列出当前被gdb调试的每个inferior信息
    • detach inferior <pid>: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;
}

猜你喜欢

转载自blog.csdn.net/nirendao/article/details/85864050
今日推荐