美文网首页
使用GDB调试C++程序

使用GDB调试C++程序

作者: 番茄沙司a | 来源:发表于2020-03-06 21:25 被阅读0次

    GDB调试利器

    GDB, the GNU Project debugger, allows you to see what is going on `inside' another program while it executes -- or what another program was doing at the moment it crashed.

    翻译成中文为 "GDB是the GNU Project debugger的简称,支持查看程序运行时或程序崩溃时正在执行的操作。"

    上面这句话出自GDB官网,认真阅读后就会明白使用提供图形化界面的IDE为什么不满足一些Linux程序员的日常使用,还需要使用GDB调试程序。

    作为一个C++程序员日常工作中会经常使用GDB进行调试,也思考出GDB作为命令行调试利器频繁出场的两大理由:

    1. 线上问题:线上环境一般只部署可执行文件,没有IDE的支持,只有命令行可以使用。多数使用GDB的情况是线上出core或有些case需要倒叙追溯,当前的log信息看不到中间过程的执行结果,这时使用GDB调试可以一步步的看结果。
      1)使用 gdb 调试 core 文件:
      gdb [可执行文件] [core文件]
      
      2)进入交互模式后,输入bt显示当前调用堆栈,准确定位问题。使用up/down可以改变堆栈显示的深度。

      当程序运行过程中出现段错误 Segmentation Fault,程序将停止运行,由操作系统把程序当前的内存状况存储在一个 core 文件中,即核心转储文件 Coredump File,core 文件是程序运行状态的内存映象。

    2. 效率和个人习惯的培养:程序调试的思路一般为: 分析现象 -> 假设错误原因 -> 产生新的现象去验证。IDE的断点调试,点击鼠标就可以设置断点,使用GDB调试像拿着胶卷相机去拍照,调试的步骤要经过仔细考虑,一定程度上会加深思考,长期养成好习惯,工作效率也会提高。

    支持GDB调试的编程语言

    Ada
    Assembly
    C
    C++
    D
    Fortran
    Go
    Objective-C
    OpenCL
    Modula-2
    Pascal
    Rust

    常用命令

    启动gdb

    要调试C/C++的程序,首先在编译时,必须要把调试信息加到可执行文件中。

    1. 对C/C++程序的调试,需要在编译前就加上-g选项
    g++ -g hello.cpp -o hello
    
    1. docker 中开启gdb调试,需要在docker run后追加--security-opt seccomp=unconfined,不然打断点会断不住
    docker run --security-opt seccomp=unconfined -it -v [cvm宿主机目录]:[容器目录]  --name [容器名] [镜像名] /bin/bash
    
    1. makefile编写
    CFLAGS+= -O2 -g
    CFLAGS+=-DNS_BUILD_METHOD="\"-O2 -g\"" -DNDEBUG
    

    将代码中的-O2替换为-O0,关闭O2优化

    1. 开始调试
    gdb <program> 调试可执行文件
    gdb <program> <core dump file> 调试core文件
    gdb <program> <PID> 调试服务程序
    

    交互模式

    1. 设置参数
    set args [arg1] [arg2] [arg3] ...
    
    1. 查看参数
    show args
    
    1. 设置断点,可以带上代码路径和代码名称
    b [filename].cpp:578
    
    1. 运行程序
    r //若有断点则停在断点处,等待下一步操作
    
    1. 查看程序是否在运行,进程号,断在何处
    info program
    
    1. 打印出变量i当前的值 = x &i (有x命令时,查看一片内存区域)
    p i
    
    1. 单字节16进制打印address地址处的长度为16的空间的内存
    x/16bx address
    
    1. c : 继续执行,若有断点,程序会停在下一个断点处
    2. n: 单步跟踪程序,遇到函数调用时,不进入此函数体
    3. s: 单步跟踪程序,遇到函数调用时,进入函数体
    4. 退出循环体
    until
    until + 行号 //退出循环体,运行至某行
    
    1. 调用程序中可见的函数,并传参
    call function_name(args)
    
    1. q: 退出gdb调试

    设置断点

    1. b n: 单文件设置断点
    2. b <filename>:n: 指定文件
    3. b n(function) if expr: 设置条件断点
    4. b func: 在函数func()的入口处设置断点
    5. delete n(断点序号): 删除断点号n
    6. disable n: 暂停断点号n
    7. enable n: 开启断点号n
    8. clear n: 清除第n行的断点
    9. info b: 显示当前程序的断点设置情况
    10. delete breakpoints: 清除所有断点

    查看源码

    1. l: 接着上一次list指令,输出之后的内容,默认列出10行程序源码
    2. l n: 显示以行号为中心的前后10行源码
    3. list func: 显示函数名所在函数的源代码

    打印表达式

    print 表达式:简记为 p ,其中表达式可以是任何当前正在被测试程序的有效表达式,比如当前正在调试C语言的程序,那么表达式可以是任何C语言的有效表达式,包括数字变量甚至是函数调用。

    1. print a:将显示整数 a 的值
    2. print ++a:将把 a 中的值加1,并显示出来
    3. print name:将显示字符串 name 的值
    4. print gdb_test(22):将以整数22作为参数调用 gdb_test() 函数
    5. print gdb_test(a):将以变量 a 作为参数调用 gdb_test() 函数
    6. display a: display 表达式在单步运行时将非常有用,使用display命令设置一个表达式后,它将在每次单步进行指令后,紧接着输出被设置的表达式及值。
    7. watch a: watch 表达式设置一个监视点,一旦被监视的值改变,gdb将强行终止正在被调试的程序。
    8. whatis: 查询变量或函数的类型
    9. info function: 查询函数
    10. info locals: 显示当前堆栈页的所有变量

    窗口

    1. layout: 用于分割窗口,支持一边查看代码一边调试
    2. layout src: 显示源代码窗口
    3. layout asm: 显示反汇编窗口
    4. Ctrl + L: 刷新窗口

    结尾

    GDB是不是功能强大的调试利器呢,建议在日常和工作中多多练习,这样常用命令会很快形成肌肉记忆,做到 Learning by Doing。

    相关文章

      网友评论

          本文标题:使用GDB调试C++程序

          本文链接:https://www.haomeiwen.com/subject/prygrhtx.html