GDB学习笔记

一、GDB概述

全称GNU symbolic debugger, 简称GDB调试器,是Linux平台下一款最常用的程序调试器。

GBD是GNU开源组织发布的一个强大的UNIX下的程序调试工具。非图形界面方式。

一般来说,GDB主要帮忙完成一下四个方面的功能:

  1. 启动程序,可以按照自己定义的要求随心所欲的运行程序。
  2. 可以让被调试的程序在你所指定的调试的断点处停住。(断点可以是条件表达式)
  3. 当程序被停住时,可以检查此时你的程序中所发生的事情。
  4. 动态的改变你程序的执行环境。

GDB编译命令:g++ -g tst.c -o tst (注意如果要使用GDB进行调试,需要加上-g,表示把调试信息加到可执行文件中,否则看不到程序的函数名和变量名)

二、常用命令

命令简写形式说明
backtracebt、where查看当前线程的调用堆栈
breakb设置断点
tbreaktb设置临时断点,临时断点只生效一次
info break显示所有断点
continuec、cont让暂停的程序继续运行
deleted删除断点
finishfi结束当前调用函数,到上一层函数调用处
returnreturn结束当前调用函数并返回指定值,到上一层函数调用处
jumpj将当前程序执行流跳转到指定行或地址
disassembledis查看汇编代码
set args设置程序启动命令行参数
show args查看设置的命令行参数
watchwatch监视某一个变量或内存地址的值是否发生变化
display监视的变量或者内存地址,当程序中断后自动输出监控的变量或内存地址
dirdir重定向源码文件的位置
info breakpoints显示断点信息
nextn执行到下一行
printp打印或修改变量或寄存器值
ptypeptype查看变量类型
runr运行程序
steps如果有调用函数,进入调用的函数内部,相当于step into
threadthread切换到指定线程
x显示内存内容
untilu运行到指定行停下来
directorydir插入目录
enableenable启用某个断点
disabledisable禁用某个断点
downdo在当前调用的栈帧中选择要显示的栈帧
edite编辑文件或者函数
framef切换到当前调用线程的指定堆栈
forward-searchfo向前搜索
generate-core-filegcore生成内核转存储
helph显示帮助一览
infoi显示信息,查看断点/线程等信息
listl显示源码
nextini执行下一行(以汇编代码为单位)
print-objectpo显示目标信息
sharelibraryshare加载共享的符号
stepisi执行下一行

三、如何使得程序能被GDB调试

写完代码后,gcc编译代码(如果gcc编译的时候没有加上-g参数,那么就不会保留调试参数,就不能用gdb调试)

创建了test.c源文件

执行编译命令:gcc -g -o test test.c

-g选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证gdb能找到源文件。

四、启动核心转储功能

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

  • 查看是否启动core dump功能

    ulimit -a

    woke@woke-virtual-machine:~/GDBTest$ ulimit -a
    real-time non-blocking time  (microseconds, -R) unlimited
    core file size              (blocks, -c) 0
    data seg size               (kbytes, -d) unlimited
    scheduling priority                 (-e) 0
    file size                   (blocks, -f) unlimited
    pending signals                     (-i) 53100
    max locked memory           (kbytes, -l) 1708744
    max memory size             (kbytes, -m) unlimited
    open files                          (-n) 1024
    pipe size                (512 bytes, -p) 8
    POSIX message queues         (bytes, -q) 819200
    real-time priority                  (-r) 0
    stack size                  (kbytes, -s) 8192
    cpu time                   (seconds, -t) unlimited
    max user processes                  (-u) 53100
    virtual memory              (kbytes, -v) unlimited
    file locks                          (-x) unlimited
    
    # 如果 core file size(core 文件大小)对应的值为 0,表示当前系统未开启 core dump 功能
    
  • 启动 core dump

    ulimit -c unlimited

    woke@woke-virtual-machine:~/GDBTest$ ulimit -c unlimited
    woke@woke-virtual-machine:~/GDBTest$ ulimit -a
    real-time non-blocking time  (microseconds, -R) unlimited
    core file size              (blocks, -c) unlimited
    data seg size               (kbytes, -d) unlimited
    scheduling priority                 (-e) 0
    file size                   (blocks, -f) unlimited
    pending signals                     (-i) 53100
    max locked memory           (kbytes, -l) 1708744
    max memory size             (kbytes, -m) unlimited
    open files                          (-n) 1024
    pipe size                (512 bytes, -p) 8
    POSIX message queues         (bytes, -q) 819200
    real-time priority                  (-r) 0
    stack size                  (kbytes, -s) 8192
    cpu time                   (seconds, -t) unlimited
    max user processes                  (-u) 53100
    virtual memory              (kbytes, -v) unlimited
    file locks                          (-x) unlimited
    
    # unlimited 表示不限制 core 文件的大小
    
  • 转换core dump时core文件的存放位置

      echo "/home/woke/GDBTest/core_%e.%p.%t" | sudo tee /proc/sys/kernel/core_pattern
      
      # 其中/home/woke/GDBTest为自己指定的位置,之后执行该目录下的可执行文件时发生core dump就会将core文件存在该目录下。
    

五、启动GDB

  1. gdb < program >
  2. gdb < program > core;gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。
  3. gdb < program > PID;如果程序是服务程序,那么可以指定这个服务程序运行时的进程ID。该程序应该PATH环境变量中搜索得到。

调试已经运行的程序有两种方法:
4. 在Linux下用ps查看已经运行的程序的PID,然后用gdb PID 的格式把gdb挂接到正在运行的程序。
5. 先用gdb 关联上源代码,执行gdb,在gdb中用attach命令来挂接进程的PID,并用detach来取消挂接的进程。

其中 < program > 是可执行程序的名称,不是源代码文件的名称。

可以通过gdb --help 命令(这是没有进入gdb调试环境的)查看gdb命令的一些参数选项,用来定制gdb的行为。

进入gdb调试环境后,可以使用help命令查看在gdb调试环境中可以使用哪些命令,gdb把命令分为很多类别,可以使用help 来查看具体类别下的每一条命令。help 查看具体命令的帮助文档。

gdb调试环境中可以执行Linux下的shell命令,在gdb调试环境中通过shell 来执行。gdb中的shell命令。

gdb中还有一个make命令,用来在gdb调试环境中通过make < make-args >来重新build自己的程序。

六、通过命令行给main函数传参

有些程序在启动的时候需要在命令行传递参数,这些参数传递给main函数,要调试这类程序,这些参数必须在应用程序启动之前通过调试程序gdb进程传递进去。也就是gdb启动后,通过gdb中设置参数的命令set args … ,查看设置的命令行参数命令是show args。

# 非gdb调试命令行传参
# argc 参数总个数,argv[0] == ./app, argv[1] == "11"  argv[2] == "22"  ...  argv[5] == "55"
$ ./app 11 22 33 44 55		# 这是数据传递给main函数
 
# 使用 gdb 调试
$ gdb app
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
# 通过gdb给应用程序设置命令行参数
(gdb) set args 11 22 33 44 55
# 查看设置的命令行参数
(gdb) show args
Argument list to give program being debugged when it is started is "11 22 33 44 55".

七、启动执行程序

gdb中启动要调试的执行程序有两种方式,一种是run命令,一种是start命令。整个gdb调试过程中,启动执行程序的命令只能使用一次。

run: 可以缩写为 r, 如果程序中设置了断点会停在第一个断点的位置, 如果没有设置断点, 程序就执行完了。
start: 启动程序, 最终会阻塞在main函数的第一行,等待输入后续其它 gdb 指令。

如果想让程序start之后继续执行或者在断点处继续执行,可以使用continue命令,简写c。

八、查看源代码

给调试的程序打断点是调试之前必须做的一项工作。为了方便定位源代码的位置,gdb提供了查看代码的命令,这样就可以轻松定位要调试的代码行的位置了。

查看代码的命令叫做list可以缩写为 l, 通过这个命令我们可以查看项目中任意一个文件中的内容,并且还可以通过文件行号,函数名等方式查看。

# 当前文件
## 一个项目中一般是有很多源文件的, 默认情况下通过list查看到代码信息位于程序入口函数main对应的的那个文件中。因此如果不进行文件切换main函数所在的文件就是当前文件, 如果进行了文件切换, 切换到哪个文件哪个文件就是当前文件。查看文件内容的方式如下:
# 使用 list 和使用 l 都可以
# 从第一行开始显示
(gdb) list 

# 列值这行号对应的上下文代码, 默认情况下只显示10行内容
(gdb) list 行号

# 显示这个函数的上下文内容, 默认显示10行
(gdb) list 函数名
## 通过list去查看文件代码, 默认只显示10行, 如果还想继续查看后边的内容, 可以继续执行list命令, 也可以直接回车(再次执行上一次执行的那个gdb命令)。

# 切换文件
## 在查看文件内容的时候,很多情况下需要进行文件切换,我们只需要在list命令后边将要查看的文件名指定出来就可以了,切换命令执行完毕之后,这个文件就变成了当前文件。文件切换方式如下:
# 切换到指定的文件,并列出这行号对应的上下文代码, 默认情况下只显示10行内容
(gdb) l 文件名:行号

# 切换到指定的文件,并显示这个函数的上下文内容, 默认显示10行
(gdb) l 文件名:函数名

# 设置显示行数
## 默认通过list只能一次查看10行代码, 如果想显示更多, 可以通过set listsize设置, 同样如果想查看当前显示的行数可以通过 show listsize查看, 这里的listsize可以简写为 list。具体语法格式如下:
# 以下两个命令中的 listsize 都可以写成 list
(gdb) set listsize 行数

# 查看当前list一次显示的行数
(gdb) show listsize

九、设置断点

想要通过gdb调试某一行或者得到某个变量在运行状态下的实际值,就需要在在这一行设置断点,程序运行到断点的位置就会阻塞,我们就可以通过gdb的调试命令得到我们想要的信息了。

设置断点的命令叫做break可以缩写为b。

断点的设置有两种方式一种是常规断点,程序只要运行到这个位置就会被阻塞,还有一种叫条件断点,只有指定的条件被满足了程序才会在断点处阻塞。

调试程序的断点可以设置到某个具体的行, 也可以设置到某个函数上,具体的设置方式如下:

  • 根据行号设置断点 break == b

    (gdb) b 5

    (gdb) b test.c:5 // 文件名:行号

  • 设置普通断点到某个非当前文件上

    (gdb) b 文件名:行号
    (gdb) b 文件名:函数名 // 停止在函数的第一行

  • 根据函数名设置断点

    (gdb) b main // 函数名

  • 根据条件设置断点

    (gdb) b test.c:10 if a == 1

  • 根据偏移量设置断点

    (gdb) b +12

  • 根据地址设置断点

    (gdb) b *0x40059b

  • 设置临时断点(临时断点只生效一次)

    (gdb) tbreak test.c:12

break +offset
break -offset
在当前行号的前面或者后面的offset行停住。offset为自然数。

break filename:linenum 在源文件filename的linenum行处停住

break filename:function 在源文件filename的function函数处停住

break *address 在程序运行的内存地址处停住

break 命令没有参数时,表示在下一条指令处停住

break … if …可以是上述参数,condition表示条件,在条件成立时停住。

info breakpoints [n] 、info break [n] 查看断点,n表示断点号。

十、查看断点

通过info break命令查看设置的断点信息,info简写i。

(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000400cb5 in main() at test.cpp:12
2       breakpoint     keep y   0x0000000000400cbd in main() at test.cpp:13
3       breakpoint     keep y   0x0000000000400cec in main() at test.cpp:18
4       breakpoint     keep y   0x00000000004009a5 in insertionSort(int*, int) 
                                                   at insert.cpp:8
5       breakpoint     keep y   0x0000000000400cdd in main() at test.cpp:16
6       breakpoint     keep y   0x00000000004009e5 in insertionSort(int*, int) 
                                                   at insert.cpp:16

# 在显示的断点信息中有一些属性需要在其他操作中被使用, 介绍如下:

## Num: 断点的编号, 删除断点或者设置断点状态的时候都需要使用
## Enb: 当前断点的状态, y表示断点可用, n表示断点不可用
## What: 描述断点被设置在了哪个文件的哪一行或者哪个函数上

十一、删除断点

删除命令是 delete 断点编号, 这个delete可以简写为del也可以再简写为d。

删除断点的方式有两种: 删除(一个或者多个)指定断点或者删除一个连续的断点区间,具体操作如下:

# delete == del == d
# 需要 info b 查看断点的信息, 第一列就是编号
(gdb) d 断点的编号1 [断点编号2 ...]
# 举例: 
(gdb) d 1          # 删除第1个断点
(gdb) d 2 4 6      # 删除第2,4,6个断点

# 删除一个范围, 断点编号 num1 - numN 是一个连续区间
(gdb) d num1-numN
# 举例, 删除第1到第5个断点
(gdb) d 1-5
  • 清除断点

    (gdb) delete 4 # 清楚某个断点

    (gdb) delete # 清除所有断点

    (gdb) clear # 清除当前行断点

十二、设置断点状态

如果某个断点只是临时不需要了,我们可以将其设置为不可用状态, 设置命令为disable 断点编号,当需要的时候再将其设置回可用状态,设置命令为 enable 断点编号。

# 让断点失效之后, gdb调试过程中程序是不会停在这个位置的
# disable == dis
# 设置某一个或者某几个断点无效
(gdb) dis 断点1的编号 [断点2的编号 ...]

# 设置某个区间断点无效
(gdb) dis 断点1编号-断点n编号

# enable == ena
# 设置某一个或者某几个断点有效
(gdb) ena 断点1的编号 [断点2的编号 ...]

# 设置某个区间断点有效
(gdb) ena 断点1编号-断点n编号

# 查看断点信息
(gdb) i b
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x0000000000400cce in main() at test.cpp:14
4       breakpoint     keep y   0x0000000000400cdd in main() at test.cpp:16
5       breakpoint     keep y   0x0000000000400d46 in main() at test.cpp:23
6       breakpoint     keep y   0x0000000000400d4e in main() at test.cpp:25
7       breakpoint     keep y   0x0000000000400d6e in main() at test.cpp:28
8       breakpoint     keep y   0x0000000000400d7d in main() at test.cpp:30

# 设置第2, 第4 个断点无效
(gdb) dis 2 4

# 查看断点信息
(gdb) i b
Num     Type           Disp Enb Address            What
2       breakpoint     keep n   0x0000000000400cce in main() at test.cpp:14
4       breakpoint     keep n   0x0000000000400cdd in main() at test.cpp:16
5       breakpoint     keep y   0x0000000000400d46 in main() at test.cpp:23
6       breakpoint     keep y   0x0000000000400d4e in main() at test.cpp:25
7       breakpoint     keep y   0x0000000000400d6e in main() at test.cpp:28
8       breakpoint     keep y   0x0000000000400d7d in main() at test.cpp:30

# 设置 第5,6,7,8个 断点无效
(gdb) dis 5-8

# 查看断点信息
(gdb) i b
Num     Type           Disp Enb Address            What
2       breakpoint     keep n   0x0000000000400cce in main() at test.cpp:14
4       breakpoint     keep n   0x0000000000400cdd in main() at test.cpp:16
5       breakpoint     keep n   0x0000000000400d46 in main() at test.cpp:23
6       breakpoint     keep n   0x0000000000400d4e in main() at test.cpp:25
7       breakpoint     keep n   0x0000000000400d6e in main() at test.cpp:28
8       breakpoint     keep n   0x0000000000400d7d in main() at test.cpp:30

# 设置第2, 第4个断点有效
(gdb) ena 2 4

# 查看断点信息
(gdb) i b
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x0000000000400cce in main() at test.cpp:14
4       breakpoint     keep y   0x0000000000400cdd in main() at test.cpp:16
5       breakpoint     keep n   0x0000000000400d46 in main() at test.cpp:23
6       breakpoint     keep n   0x0000000000400d4e in main() at test.cpp:25
7       breakpoint     keep n   0x0000000000400d6e in main() at test.cpp:28
8       breakpoint     keep n   0x0000000000400d7d in main() at test.cpp:30

# 设置第5,6,7个断点有效
(gdb) ena 5-7

# 查看断点信息
(gdb) i b
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x0000000000400cce in main() at test.cpp:14
4       breakpoint     keep y   0x0000000000400cdd in main() at test.cpp:16
5       breakpoint     keep y   0x0000000000400d46 in main() at test.cpp:23
6       breakpoint     keep y   0x0000000000400d4e in main() at test.cpp:25
7       breakpoint     keep y   0x0000000000400d6e in main() at test.cpp:28
8       breakpoint     keep n   0x0000000000400d7d in main() at test.cpp:30

十三、设置观察点

观察点一般用来观察某个表达式(变量也是表达式)的值是否发生变化,如果有变化,立马停住程序。

设置观察点的方法:

命令用途
watch < expr >为表达式expr设置一个观察点,一旦表达式的值发生变化,马上停住程序
rwatch < expr >当表达式被读时,停住程序
awatch < expr >当表达式的值被读或者被写时,停住程序
info watchpoints列出当前设置的所有观察点

十四、设置捕捉点

设置捕捉点来捕捉程序运行时的一些事件。
设置捕捉点格式: catch < event >
当event发生时,停住程序。event可以是下面的内容:
在这里插入图片描述

十五、维护停止点

以上的三种点,就是gdb中的三类停止点。如果觉得定义好的停止点没用了,可以使用delete、clear、disable、enable这几个命令来维护。

命令用途
clear清除所有的已定义的停止点
clear < function > ; clear < filename:function >清除所有设置在函数上的停止点
clear < linenum > ; clear < filename : linenum >清楚所有设置在指定行上的停止点
delete [ breakpoints ] [range…]删除指定断点,breakpoints为断点号,如果不指定断点号表示删除所有断点。range表示断点号范围,如:3-7
disable [ breakpoints ] [range…]比删除更好的一种方式是disable停止点,disable之后,gdb不会删除,当还需要,enable即可。简写dis
enable [ breakpoints ] [range…]enbale所指定的停止点
enable [ breakpoints ] once range …enable 指定停止点一次,当程序停止后,该停止点马上被gdb自动disable
enable [ breakpoints ] delete range …enable 指定停止点一次,当程序停止后,该停止点马上被gdb自动删除

十六、停止条件维护

设置条件后,当条件成立时,程序自动停止。使用if关键字,为断点设置条件。条件设置好后,使用condition命令来修改断点条件。(只有break、watch支持if,catch不支持if)

命令用途
condition < bnum > < exp >修改断点号为bnum的停止条件为exp
condition < bnum >清楚断点号bnum的停止条件

十七、断点菜单

可能会出现同一个名字的函数多次,这时,break < function > 不能告诉gdb要停在哪个函数的入口。gdb会列出一个断点菜单供你选择所需要的断点,你只需要输入菜单列表编号就可以。
在这里插入图片描述
以上gdb列出了所有after的重载函数,选择一下列表编号就好了。0表示放弃设置断点,1表示所有函数都设置断点。

十八、查看栈信息

程序被停住,当调用了函数时,函数的地址、函数参数、函数内的局部变量都会被压入栈中。
查看函数调用栈信息的命令:backtrace or bt

命令用途
backtrace < n >n是一个整数表示只打印栈顶上的n层的栈信息
backtrace < -n >-n表示一个负整数,表示只打印栈底n层栈信息

如果要切换当前的栈层,一般来说,程序停止时最顶层就是当前栈,如果要查看栈下面层的信息,首先要做切换当前栈。

命令用途
frame < n >n是一个整数,是栈中层的编号,0表示栈顶,1表示栈的第二层
up < n >表示向栈的上面移动n层,可以不打n,表示向上移动一层
down < n >向下移动

十九、运行

  • 运行 r
  • 继续单步调试 n
  • 继续执行到下一个断点 c
  • 查看源码和行号 l #不断输入 l 并回车会不断显示源码

以下命令都是在程序运行起来才起作用

  • 打印变量

    p a

  • 打印指针

    p p # 第二个p是一个指针

  • 打印main函数中的变量a

    p ‘main’::a

  • 打印指针指向的内容,@后面跟的是打印的长度

    p *p@3 #如果p指向数组,则打印数组前三个元素。

  • 设置变量打印

    set $index = 0

    p p[$index] # p是一个指向数组的指针,其实就是下标取数组元素

  • 设置打印格式

    1. x 按十六进制格式显示变量
    2. d 按十进制格式显示变量
    3. u 按十六进制格式显示无符号整型
    4. o 按八进制格式显示变量
    5. t 按二进制格式显示变量
    6. a 按十六进制格式显示变量
    7. c 按字符格式显示变量
    8. f 按浮点数格式显示变量

    (gdb) p/x a(按十六进制格式显示变量)

    (gdb) p/x a

    $7 = 0x1

二十、调试

如果调试的程序被断点阻塞了又想让程序继续执行,这时候就可以使用continue命令。程序会继续运行, 直到遇到下一个有效的断点。continue可以缩写为 c。

20.1 打印信息

当程序被某个断点阻塞之后, 可以通过一些命令打印变量的名字或者变量的类型,并且还可以跟踪打印某个变量的值。

# 打印变量的值
## 在gdb调试的时候如果需要打印变量的值, 使用的命令是 print, 可缩写为 p。如果打印的变量是整数还可以指定输出的整数的格式, 格式化输出的整数对应的字符表如下:
# 格式化字符(/fmt)	        说明
#    /x	           以十六进制的形式打印出整数。
#    /d	           以有符号、十进制的形式打印出整数。
#    /u	           以无符号、十进制的形式打印出整数。
#    /o	           以八进制的形式打印出整数。
#    /t	           以二进制的形式打印出整数。
#    /f	           以浮点数的形式打印变量或表达式的值。
#    /c	           以字符形式打印变量或表达式的值。

# print == p
(gdb) p 变量名

# 如果变量是一个整形, 默认对应的值是以10进制格式输出, 其他格式请参考上表
(gdb) p/fmt 变量名

# 举例
(gdb) p i       # 10进制
$5 = 3
(gdb) p/x i     # 16进制
$6 = 0x3
(gdb) p/o i     # 8进制
$7 = 03

# 打印变量类型
## 在调试过程中需要查看某个变量的类型, 可以使用命令ptype, 语法格式如下:
(gdb) ptype 变量名
# 打印变量类型
(gdb) ptype i
type = int
(gdb) ptype array[i]
type = int
(gdb) ptype array
type = int [12]

# 自动打印信息
## 设置变量名自动显示
# 和 print 命令一样,display 命令也用于调试阶段查看某个变量或表达式的值,它们的区别是,使用 display 命令查看变量或表达式的值,每当程序暂停执行(例如单步执行)时,GDB 调试器都会自动帮我们打印出来,而 print 命令则不会。因此,当我们想频繁查看某个变量或表达式的值从而观察它的变化情况时,使用 display 命令可以一劳永逸。display 命令没有缩写形式,常用的语法格式如下 2 种:
# 在变量的有效取值范围内, 自动打印变量的值(设置一次, 以后就会自动显示)
(gdb) display 变量名

# 以指定的整形格式打印变量的值, 关于 fmt 的取值, 请参考 print 命令
(gdb) display/fmt 变量名

## 查看自动显示列表
## 对于使用 display 命令查看的目标变量或表达式,都会被记录在一张列表(称为自动显示列表)中。通过执行info dispaly命令,可以打印出这张表:
# info == i
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1:   y  i
2:   y  array[i]
3:   y  /x array[i]

## 在展示出的信息中, 每个列的含义如下:
# Num : 变量或表达式的编号,GDB 调试器为每个变量或表达式都分配有唯一的编号
# Enb : 表示当前变量(表达式)是处于激活状态还是禁用状态,如果处于激活状态(用 y 表示),则每次程序停止执行,该变量的值都会被打印出来;反之,如果处于禁用状态(用 n 表示),则该变量(表达式)的值不会被打印。
# Expression :被自动打印值的变量或表达式的名字。

## 取消自动显示
## 对于不需要再打印值的变量或表达式,可以将其删除或者禁用。
## 删除自动显示列表中的变量或表达式
# 命令中的 num 是通过 info display 得到的编号, 编号可以是一个或者多个
(gdb) undisplay num [num1 ...]  # 删除 是删除
# num1 - numN 表示一个范围
(gdb) undisplay num1-numN

(gdb) delete display num [num1 ...]  # 删除
(gdb) delete display num1-numN

# 查看显示列表
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1:   y  i
2:   y  array[i]
3:   y  /x array[i]

# 删除变量显示, 需要使用 info display 得到的变量/表达式编号
(gdb) undisplay 1 2

# 查看显示列表, 只剩下一个了
(gdb) i display
Auto-display expressions now in effect:
Num Enb Expression
3:   y  /x array[i]

## 如果不想删除自动显示的变量, 也可以禁用自动显示列表中处于激活状态下的变量或表达式、
# 命令中的 num 是通过 info display 得到的编号, 编号可以是一个或者多个
(gdb) disable display num [num1 ...]
# num1 - numN 表示一个范围
(gdb) disable display num1-numN

## 当需要启用自动显示列表中被禁用的变量或表达式时, 可以使用下边的命令
# 命令中的 num 是通过 info display 得到的编号, 编号可以是一个或者多个
(gdb) enable  display num [num1 ...]
# num1 - numN 表示一个范围
(gdb) disable display num1-numN

20.2 单步调试

当程序阻塞到某个断点上之后, 可以通过以下命令对程序进行单步调试:

# step命令
## step命令可以缩写为s, 命令被执行一次代码被向下执行一行,如果这一行是一个函数调用,那么程序会进入到函数体内部。
# 从当前代码行位置, 一次调试当前行下的每一行代码
# step == s
# 如果这一行是函数调用, 执行这个命令, 就可以进入到函数体的内部
(gdb) step

# finish命令
## 如果通过 s 单步调试进入到函数内部, 想要跳出这个函数体, 可以执行finish命令。如果想要跳出函数体必须要保证函数体内不能有有效断点,否则无法跳出。
# 如果通过 s 单步调试进入到函数内部, 想要跳出这个函数体
(gdb) finish

# next命令
## next命令和step命令功能是相似的,只是在使用next调试程序的时候不会进入到函数体内部,next可以缩写为 n
# next == n
# 如果这一行是函数调用, 执行这个命令, 不会进入到函数体的内部
(gdb) next

# util命令
## 通过 until 命令可以直接跳出某个循环体,这样就能提高调试效率了。如果想直接从循环体中跳出, 必须要满足以下的条件,否则命令不会生效:
### 1. 要跳出的循环体内部不能有有效的断点
### 2. 必须要在循环体的开始/结束行执行该命令
(gdb) until

20.3 设置变量值

在调试程序的时候, 我们需要在某个变量等于某个特殊值的时候查看程序的运行状态, 但是通过程序运行让变量等于这个值又非常困难, 这种情况下就可以在 gdb 中直接对这个变量进行值的设置, 或者是在单步调试的时候通过设置循环因子的值直接跳出某个循环, 值设置的命令格式为: set var 变量名=值

# 可以在循环中使用, 直接设置循环因子的值
# 假设某个变量的值在程序中==90的概率是5%, 这时候可以直接通过命令将这个变量值设置为90
(gdb) set var 变量名=

二十一、信号

GDB中handle命令捕获指定的信号,并停止程序。

命令用途
handle < signale > < keywords >signal表示信号,也可以是一个信号范围:SIGIO-SIGKILL

keywords的取值:
在这里插入图片描述
在这里插入图片描述

二十二、退出GDB

quit 简写q

学习资料


张小方 https://zhuanlan.zhihu.com/p/548379635

爱编程的大丙 https://subingwen.cn/linux/gdb/

参考:https://blog.youkuaiyun.com/lovely_dzh/article/details/109160337

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值