『Linux』GDB调试

前言

GDB 是由 GNU 软件系统社区提供的调试工具,同 GCC 配套组成了一套完整的开发环境,GDB 是 Linux 和许多类 Unix 系统中的标准开发环境。
一般来说,GDB 主要完成下面四个方面的功能:
启动程序:可以按照自定义的要求随心所欲的运行程序。
设置断点:可让被调试的程序在所指定的调置的断点处停住,断点可以是条件表达式。
打印信息:当程序被停住时,可以检查此时程序中所发生的事。
修改变量:可以通过修改程序中的变量,将一个 BUG 产生的影响修正从而测试其他 BUG。

debug版本与release版本

  • 假设存在一段代码:

    //文件为 gdb_test.cpp
    #include
    
    int GetSum(int n){ //主要是测试 ;其功能为计算1至n之和;
      int ret = 0;
      for(int i = 1;i<=n;++i){
        ret+=i;
      }
       return ret;
     }
     
     int main()
     {
       int n =0;
       std::cin>>n;
      
        int ret = GetSum(n);
        std::cout<<ret<<std::endl;
        return 0;                                                         
      }
    

    再使用g++进行编译:

    g++ gdb_test.cpp -o test 
    

    编译链接过后进行运行确保程序无误;

    在这时若是想使用gdb进行调试:

    gdb test
    

    (前提是得有gdb),若是没有gdb则需要使用yum进行安装:

    sudo yum install -y gdb
    

    将会出现这样的提示:

    (no debugging symbols found) … done.

    没有找到调试符号

    这正是因为,在使用gcc/g++进行编译链接所生成的可执行文件默认是release版本的,无法进行debug调试;

    这里可以再回顾一下gcc/g++的特性;

    链接 生成的可执行程序
    gcc/g++ 在不使用-static修饰的时候默认为动态链接; 默认生成的可执行程序的版本为release版本,若是需要生成debug版本需要在末尾处加上-g

生成debug版本的可执行程序:

g++ gdb_test.cpp -o test_debug -g 

添加-g选项代表该可执行程序为以debug方式发布的

生成debug版本的可执行程序后即可以进行调试;

gdb test_debug

在此之前可以使用readelf来查看ELF格式文件信息;

readelf -S 'filename' #使用-S选项显示节头信息

或者

readelf -S 'filename' | grep -i debug  #使用-S选项显示节头信息,grep debug为找出所有带debug的信息,-i为不区分大小写;

以第二条命令查看release版本的可执行程序的段信息时可以看到

由于没有debug,所以不显示;同时因为没有debug也不能进行调试;

同时使用第二条命令对所生成的debug版本的可执行程序时为

『Linux』GDB调试_第1张图片
debug版本和release版本的大小差是因为在debug版本中多出了许多调试信息

在进行调试之前先使用Makefile以方便构造与清除


GDB操作

启动与退出gdb

gdb 'filename' #使用该命令即可启动gdb调试,其中filename为可执行程序(debug版)
quit #要退出gdb时只要输入quit或者q即可退出

显示代码

list #当然大多数情况下会使用简写 l ,从头开始即为 l 0 并回车至所有代码显示完毕

一般使用list时,gdb将会按照自己的方式将代码进行显示,可能不显示全,单若是希望从头开始显示时则可以使用 l 0 即从头显示代码,单此时也并不会显示完全,所以要用回车至所有代码显示完全;

『Linux』GDB调试_第2张图片

同时在这里该注意,gdb与平时的Linux操作中较为不同的是;

在gdb调试过程中,gdb将会记住你上次的指令,这也是在使用list(或者l)后按照回车能够继续显示代码,在此处按回车时将会继续list的命令;


控制程序执行

命令 功能
run < arguments > 或者 r < arguments > 运行或者重新运行程序,并传递指定的参数。如果设置了断点,程序会在断点处暂停,并显示当前的源代码和寄存器值;
如 : run arg1 arg2 运行程序,并传递arg1和arg2为参数;
continue 或者 c 继续运行程序 (若是有断点则至下一个断点处停止,否则运行至程序结束)
next 或者 n 逐过程调试(不进入函数)
step 或者 s 逐行调试 (会进入函数)
finish 或者 f 执行程序至当前函数结束(返回),并显示返回值;
return < expression >或者 r < expression > 强制当前函数立即返回,并将返回值设定为指定的表达式。如果不指定表达式则返回0;
jump < location >或者 j < location > 强制程序跳转到指定位置,可以是行号、或者是地址;将可能改变程序的正常流程;

断点设置与取消:

命令 功能
(gdb) break main(main的这个位置可以是函数名、文件名: 、行号或者内存地址) 在main函数的第1行的位置设置断点(以此类推,所有的函数都可以像这样进行断点设置)
(gdb) break test.c:10 在同一目录下的test.c源文件设置断点(暂未证实,应该另有)
(gdb) info breakpoints 查看当前节点个数以及编号位置等信息;可以简写为i b 以此类推,但是此处的breakpoints并不能用来进行断点(不能使用breakpoints 10 这类的方式进行断点)
(gdb) delete 1 删除编号为1 的节点 ;delete也可以简写为d;
(gdb) delete 删除所有节点
condition 或者cond 给指定编号的断点添加条件,当条件为真时,起到断点作用

查看(或修改)变量、寄存器与内存

命令 功能
print 或者 p 打印某个变量或者表达式的值。可以使用任何合法的C语言表达式,包括宏、指针、结构体等。
print x 打印变量x的值
print *p 打印指针p所指向的值
print add(10,20); 打印调用add函数并传入10 20作为参数后的返回值;
set < expression> 修改某个变量或者表达式的值,修改规则同上;
set x = 10 将变量x修改为10,同理该方法也同样可以用来修改指针
set add(10,20) = 100 修改调用函数并传递10与20作为参数后修改返回值为100
info registers或者i f 显示所有寄存器的值
info registers < name >或者i f 显示指定的寄存器的值
info registers eax 显示eax寄存器的值
set $< name > = < value > 修改寄存器的值
set $eax = 5 将寄存器eax 的值修改为5

你可能感兴趣的:(Linux,linux,c++,c语言)