GDB调试

参考GDB

特别好的一家网站,推荐食用。

查看GDB版本
gdb -v # 看信息返回结果,如果没有安装,执行下一步,安装GDB

sudo apt-get install gdb
调试开始
  • 只有当源程序编译成可执行文件时,GDB才可以调试,并且仅仅使用(gcc、g++)命令编译生成的可执行文件,也是无法借助GDB进行调试的。

    gcc main.c -o main # 不可以调试
    
  • 只需要使用 gcc -g 选项编译源文件,即可生成满足 GDB 要求的可执行文件,该文件中必须包含必要的调试信息(比如各行代码所在的行号、包含程序中所有变量名称的列表(又称为符号表)等)

    gcc main.c -o main -g
    
  • 第一步,利用编译指令,生产可以debug的可执行文件

    gcc/g++ 源程序 -o 可执行文件名 -g # 举例
    
  • 第二步,启动调试器

    # 打开终端,切换到可执行文件所在的路径
    gdb 可执行文件名 # 这样启动GDB,会打印一堆免责条款
    或者:
    gdb 可执行文件名 --silent # 这样会省略免责条款
    
    直到最后出现下面的显示,表示启动成功:
    (gdb)
    
  • GDB常用调试指令

    调试指令 作用
    (gdb) break xxx
    (gdb) b xxx
    在源代码指定的某一行设置断点,其中 xxx 用于指定具体打断点的位置(行号)。
    (gdb) run
    (gdb) r
    执行被调试的程序,其会自动在第一个断点处暂停执行。
    (gdb) continue
    (gdb) c
    当程序在某一断点处停止运行后,使用该指令可以继续执行,直至遇到下一个断点或者程序结束。
    (gdb) next
    (gdb) n
    令程序一行代码一行代码的执行。
    (gdb) print xxx
    (gdb) p xxx
    打印指定变量的值,其中 xxx 指的就是某一变量名。
    (gdb) list
    (gdb) l
    显示源程序代码的内容,包括各行代码所在的行号。
    (gdb) quit
    (gdb) q
    终止调试。
GDB查看命令

启动 GDB 调试器之后,可以使用 help 命令查看 GDB 指令

  • help 单独使用是查看命令的种类

  • help 添加命令的种类,表示使用这条命令查看各个种类中具体命令选项

  • help 添加具体的一条命令,表示查看命令的使用方式

  • 举例:

    # 1、使用 help 命令,向我们展示了命令总体被划分成了12种,其中每一种又会包含许多的命令
    (gdb) help 
    List of classes of commands:
     
    aliases -- Aliases of other commands
    breakpoints -- Making program stop at certain points
    data -- Examining data
    files -- Specifying and examining files
    internals -- Maintenance commands
    obscure -- Obscure features
    running -- Running the program
    stack -- Examining the stack
    status -- Status inquiries
    support -- Support facilities
    tracepoints -- Tracing of program execution without stopping the program
    user-defined -- User-defined commands
    
    # 2、查看各个种类种的命令使用方法:
    (gdb) help <class>
    # 其中  表示 help 命令显示的 GDB 中的命令的种类
    # 比如:
    (gdb) help breakpoints
    Making program stop at certain points.
     
    List of commands:
     
    awatch -- Set a watchpoint for an expression
    break -- Set breakpoint at specified location
    break-range -- Set a breakpoint for an address range
    catch -- Set catchpoints to catch events
    catch assert -- Catch failed Ada assertions
    catch catch -- Catch an exception
    ……
    
    # 3、命令的具体使用方式
    (gdb) help <command>
    # 其中, 表示的是具体的一条命令
    # 比如:
    (gdb) help break
    Set breakpoint at specified location.
    break [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]
    
调用GDB调试器的四种方式
  • 直接使用 gdb 指令启动 GDB 调试器,由于事先未指定要调试的具体程序,因此需启动后借助 file 或者 exec-file 命令指定

    举例:

    # 启动GDB调试器
    gdb
    # 然后指定可执行文件
    file demo.exe # 路径自己选择
    # 可以切换 GDB调试器所处的工作路径
    cd /root/... # 可以自己更改路径
    

    run 和 start 指令都可以用来在 GDB 调试器中启动程序,它们之间的区别是:

    • 默认情况下,run 指令会一直执行程序,直到断点执行结束。如果程序中手动设置有断点,则 run 指令会执行程序至第一个断点处;

    • start 指令会执行程序至 main() 主函数的起始位置,即在 main() 函数的第一行语句处停止执行(该行代码尚未执行)。

    程序执行过程中使用 run 或者 start 指令,表示的是重新启动程序。

  • 调试尚未执行的程序

    gdb 可执行文件名
    
  • 调试正在执行的程序

    如果需要使用 GDB 调试正在运行的 C、C++ 程序,需要事先找到该程序运行所对应的进程号。

    pidof 可执行文件名 # 获得进程号
    # 然后开始调试
    gdb -p PID # PID就是进程号
    

    注意,当 GDB 调试器成功连接到指定进程上时,程序执行会暂停,此时可以通过断点调试、逐步运行等方式监控程序的执行过程。

    注意,当调试完成后,如果想令当前程序继续执行,消除调试操作对它的影响,需手动将 GDB 调试器与程序分离,分离过程分为 2 步:

    1、执行 detach 指令,使 GDB 调试器和程序分离;

    2、执行 quit(或 q)指令,退出 GDB 调试。

  • 调试执行异常崩溃的程序

    在 Linux 操作系统中,当程序执行发生异常崩溃时,系统可以将发生崩溃时的内存数据、调用堆栈情况等信息自动记录下载,并存储到一个文件中,该文件通常称为 core 文件,Linux 系统所具备的这种功能又称为核心转储(core dump)。幸运的是,GDB 对 core 文件的分析和调试提供有非常强大的功能支持,当程序发生异常崩溃时,通过 GDB 调试产生的 core 文件,往往可以更快速的解决问题。

    默认情况下,Linux 系统是不开启 core dump 这一功能的,可以用以下指令查看

    # 输入ulimit -a 指令
    ulimit -a
    # 输出
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    ......
    

    其中,如果 core file size(core 文件大小)对应的值为 0,表示当前系统未开启 core dump 功能,可以使用下面的 指令开启 core dump 功能

    ulimit -c unlimited # 开启 core dump 功能
    # 查看是否开启成功
    ulimit -a 
    core file size          (blocks, -c) unlimited
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    ......
    

    举例:

    # 编译一个源程序,出现了错误
    gcc main.c -o main.exe -g
    ./main.exe
    # 下面是报错信息
    Segmentation fault (core dumped)   <--发生段错误,并生成了 core 文件
    
    # 然后系统主动把报错信息 存储了下来
    ls # 可以查看路径里面的内容,多了 core 文件
    core  main.c  main.exe
    

    对于 core 文件的调试,其调用 GDB 调试器的指令为:

    # 输入这个指令
    gdb main.exe core
    # 下面就会有详细的报错信息,可以帮助调试程序
    
  • 启动 GDB调试器可用的参数

    参数 功能
    -pid number
    -p number
    调试进程 ID 为 number 的程序。
    -symbols file
    -s file
    仅从指定 file 文件中读取符号表。
    -q
    -quiet
    -silent
    取消启动 GDB 调试器时打印的介绍信息和版权信息
    -cd directory 以 directory 作为启动 GDB 调试器的工作目录,而非当前所在目录。
    –args 参数1 参数2… 向可执行文件传递执行所需要的参数。
设置普通断点(break)

1、break命令的语法格式有:

1(gdb) break location # b location
2(gdb) break ... if cond # b ... if cond

location 用于指定打断点的具体位置,

... 可以是 1 中所有参数的值,用于指定打断点的具体位置;cond 为某个表达式。整体的含义为:每次程序执行到 ... 位置时都计算 cond 的值,如果为 True,则程序在该位置暂停;反之,程序继续执行。

2、tbreak 命令:tbreakbreak 命令的用法和功能都非常相似,唯一的不同在于,使用 tbreak 命令打的断点仅会作用 1 次,即使程序暂停之后,该断点就会自动消失。

3、rbreak 命令:rbreak 命令的作用对象是 C、C++ 程序中的函数,它会在指定函数的开头位置打断点。和 break 命令打断点的效果是一样的,会一直存在,不会自动消失。

设置观察断点(watch)

watch 命令的功能是:只有当被监控 **变量(或表达式)**的值发生改变,程序才会停止运行。

语法格式:

(gdb) watch cond # cond指的是要监控的变量或表达式

和 watch 命令功能相似的,还有 rwatchawatch 命令。其中:

  • rwatch 命令:只要程序中出现读取目标变量(表达式)的值的操作,程序就会停止运行;
  • awatch 命令:只要程序中出现读取目标变量(表达式)的值或者改变值的操作,程序就会停止运行。
设置捕捉断点(catch)

捕捉断点的作用是,监控程序中某一事件的发生,例如程序发生某种异常时、某一动态库被加载时等等,一旦目标时间发生,则程序停止执行。

(用捕捉断点监控某一事件的发生,等同于在程序中该事件发生的位置打普通断点。)

语法格式:

(gdb) catch event # event参数表示要监控的具体事件
单步调试程序
  • next 命令:

    单步调试的命令,其最大的特点是当遇到包含调用函数的语句时,无论函数内部包含多少行代码,next 指令都会一步执行完。也就是说,对于调用的函数来说,next 命令只会将其视作一行代码。

    语法格式:

    (gdb) next count # count 表示单步执行多少行代码,默认为 1 行
    
  • step 命令:

    step 命令也是单步执行程序。但是 step 命令所执行的代码行中包含函数时,会进入该函数内部,并在函数第一行代码处停止执行,会一行一行执行函数内部的代码

    语法格式:

    (gdb) step count # count 表示一次执行的行数,默认为 1 行
    
  • until 命令:

    语法格式:

    (gdb) until
    (gdb) until location # 参数 location 为某一行代码的行号
    

    不带参数的 until 命令,可以使 GDB 调试器快速运行完当前的循环体,并运行至循环体外停止。注意,until 命令并非任何情况下都会发挥这个作用,只有当执行至循环体尾部(最后一行代码)时,until 命令才会发生此作用;反之,until 命令和 next 命令的功能一样,只是单步执行程序。

    until 命令还可以后跟某行代码的行号,以指示 GDB 调试器直接执行至指定位置后停止。

断点调试常用命令
命令(缩写) 功能
run(r) 启动或者重启一个程序。
list(l) 显示带有行号的源码。
continue(c) 让暂停的程序继续运行。
next(n) 单步调试程序,即手动控制代码一行一行地执行。不进入函数内部
step(s) 如果有调用函数,进入调用的函数内部;否则,和 next 命令的功能一样。
until(u)
until location(u location)
当你厌倦了在一个循环体内单步跟踪时,单纯使用 until 命令,可以运行程序直到退出循环体。
until n 命令中,n 为某一行代码的行号,该命令会使程序运行至第 n 行代码处停止。
finish(fi) 结束当前正在执行的函数,并在跳出函数后暂停程序的执行。
return(return) 结束当前调用函数并返回指定值,到上一层函数调用处停止程序执行。
jump(j) 使程序从当前要执行的代码处,直接跳转到指定位置处继续执行后续的代码。
print(p) 打印指定变量的值。
quit(q) 退出 GDB 调试器。
GDB print和display命令:查看变量的值

1、print 命令,功能就是在 GDB 调试程序的过程中,输出或者修改指定变量或者表达式的值。

语法格式:

(gdb) print num
(gdb) p num 
# 参数 num 用来代指要查看或者修改的目标变量或者表达式。

2、display 命令也用于调试阶段查看某个变量或表达式的值,它们的区别是,使用 display 命令查看变量或表达式的值,每当程序暂停执行(例如单步执行)时,GDB 调试器都会自动帮我们打印出来(每次都打印)

语法格式:

(gdb) display expr
(gdb) display/fmt expr
# expr 表示要查看的目标变量或表达式;参数fmt用于指定输出变量或表达式的格式

/fmt 常用的值

/fmt 功能
/x 以十六进制的形式打印出整数。
/d 以有符号、十进制的形式打印出整数。
/u 以无符号、十进制的形式打印出整数。
/o 以八进制的形式打印出整数。
/t 以二进制的形式打印出整数。
/f 以浮点数的形式打印变量或表达式的值。
/c 以字符形式打印变量或表达式的值。

对于使用 display 命令查看的目标变量或表达式,都会被记录在一张列表(称为自动显示列表)中。通过执行 info dispaly 命令,可以打印出这张表。

GDB禁用和删除断点

GDB 调试器支持 3 种断点,分别为普通断点(用 break 命令创建)、观察断点(用 watch 命令建立)以及捕捉断点(用 catch 命令建立)。并且如果需要的话,我们可以在被调试程序中打多个断点,甚至于 GDB 允许在同一位置打多个断点。

如果之前建立的断点不再需要或者暂时不需要,该如何删除或者禁用呢?常用的方式有 2 种:

1、使用 quit 命令退出调试,然后重新对目标程序启动调试,此方法会将消除上一次调试操作中建立的所有断点;

2、使用专门删除或禁用断点的命令,既可以删除某一个断点,也可以删除全部断点。

  • 查看当前已经建好的断点

    (gdb) info breakpoint [n]
    (gdb) info break [n]
    # 参数 n 作为可选参数,为某个断点的编号,表示查看指定断点而非全部断点。
    # 不加参数 n,表示查看所有断点
    
  • 删除断点

    • clear 命令

      (gdb) clear location
      # 参数 location 通常为某一行代码的行号或者某个具体的函数名。当 location 参数为某个函数的函数名时,表示删除位于该函数入口处的所有断点。
      
    • delete 命令

      (gdb) delete [breakpoints] [num]
      # breakpoints 参数可有可无,num 参数为指定断点的编号,其可以是 delete 删除某一个断点,而非全部。
      # 如果不指定 num 参数,则会删除当前程序中存在的所有断点
      
  • 禁用断点

    disable [breakpoints] [num...]
    # breakpoints 参数可有可无;num... 表示可以有多个参数,每个参数都为要禁用断点的编号。如果指定 num...,disable 命令会禁用指定编号的断点;反之若不设定 num...,则 disable 会禁用当前程序中所有的断点。
    

    激活断点

    # 激活用 num... 参数指定的多个断点,如果不设定 num...,表示激活所有禁用的断点
    enable [breakpoints] [num...]
    # 临时激活以 num... 为编号的多个断点,但断点只能使用 1 次,之后会自动回到禁用状态
    enable [breakpoints] once num…   
    # 临时激活以 num... 为编号的多个断点,断点可以使用 count 次,之后进入禁用状态
    enable [breakpoints] count num...
    # 激活 num.. 为编号的多个断点,但断点只能使用 1 次,之后会被永久删除。
    enable [breakpoints] delete num…               
    

你可能感兴趣的:(GCC/GDB,c++,linux,gdb)