Gdb调试命令

基本用法

在使用gdb调试前,以c程序为例,若需要对c代码进行 gdb 调试,那么在生成目标文件时要注意加入-g,代表支持 gdb 调试。样例如下:

如下为 test.c 的代码内容:

#include <stdio.h>
#define N 100
int func(int num){
num += 10;
return num;
}
int main(){
for(int i = 0; i < N; i++){
printf("current number is : %d\n", func(i));
}
return 0;
}

 


首先用 gcc 对代码进行编译,生成可执行文件 test :

$ gcc test.c -g -o test
然后使用如下命令启动 gdb 调试。

$ gdb [options] [executable_file [core_file | process_id]]
# 直接指定可执行文件
$ gdb test
# 在程序名称后面附加参数,可以指定要调试的进程ID,或者指定核心转储文件的名称
$ gdb test 1001

接下来,就可以通过一系列的操作对程序进行调试

# 显示所有处理器寄存器的内容,包括浮点和向量寄存器
$ (gdb) info all-reg
# 显示当前的源文件
$ (gdb) info source
# 显示 radius 变量的地址信息
$ (gdb) info address radius
#显示GDB当前日志的相关信息
$ (gdb) show loggin
# 将GDB的日志重定向到gdb.txt文件
$ (gdb) set logging on
#如果gdb在启动时没有指定被调试程序,可以通过file指定被调试的程序
$ (gdb) file filename
# 重新指定被调试程序的命令行参数。
$ (gdb) set args [arguments]
# 显示被调试程序的命令行参数
$ (gdb) show args
# 开始执行一个程序,并可选的为其指定命令行参数
$ (gdb) run / r [arguments]
# 终止被调试的程序 (不会销毁当前设置的参数)
$ (gdb) kill
# 显示源代码,并以指定的行作为中心
$ (gdb) list filename:line_number
# 跳转到指定的行(为中心)
$ (gdb) line_number
# 显示特定范围内的源代码
$ (gdb) from  , [to]
# 把指定函数开始的第一行作为中心,显示源代码
$ (gdb) function_name
# 显示更多的行(遇到断点中止)
$ (gdb) list / l
# 设置list命令默认输出行数
$ (gdb) set listsize number
# 显示list命令默认输出的行数
$ (gdb) listsize
# 在(指定文件或当前文件)指定行设置断点
$ (gdb) break [filename:] line_number
# 在指定函数的第一行设置断点
$ (gdb) break function
# 在当前栈帧的下一行设置断点
$ (gdb) break
# 显示断点信息,包括断点编号、断点位置等
$ (gdb) info breakpoints 
# 设置临时断点
$ (gdb) tbreak 16
# 继续执行到下一个断点,passes表示忽略几次中断
$ (gdb) continue / c [passes]
# 执行多少行后再次被中断,如果遇到函数,将会进入函数,并在函数第一行停下来
$ (gdb) step / s [lines]
# 执行多少行后再次被中断,不会进入函数
$ (gdb) next / n [lines]
# 删除指定编号或指定范围的断点,不带参数会删除所有断点。例如"delete 1-3"
$ (gdb) delete / d [bp_number | range]
# 禁用断点
$ (gdb) disable [bp_number | range]
# 启用断点
$ (gdb) enable [bp_number | range]
# 忽略断点,并指定忽略次数为iterations
$ (gdb) ignore bp_number iterations
# 将当前函数执行结束,控制权返回给函数调用者
$ (gdb) finish
# 多个命令都可以显示程序的调用轨迹
$ (gdb) backtrace, bt, where, info stack
# 显示当前栈帧,或者选择不同的栈帧
$ (gdb) frame [number]
# 显示当前栈帧的相关信息
$ (gdb) info frame
# 当前栈帧的局部变量
$ (gdb) info locals
# 列出对应函数调用的参数值
$ (gdb) info args

 

断点类型

查看当前已建好的断点

对于当前调试环境中已经建好且尚未删除的断点,可以通过以下  2 种方式查看它们。

1) 借助如下指令,可以查看当前调试环境中存在的所有断点,包括普通断点、观察断点以及捕捉断点:

(gdb) info breakpoint [n]
(gdb) info break [n]

参数 n 作为可选参数,为某个断点的编号,表示查看指定断点而非全部断点。

要知道,任何类型的断点在建立时,GDB 调试器都会为其分配一个独一无二的断点编号。以 main.exe 为例,我们尝试建立如下断点:

(gdb) b 1
Breakpoint 1 at 0x1189: file main.c, line 2.
(gdb) r
Starting program: ~/demo/main.exe

Breakpoint 1, main () at main.c:2
2 int main(){
(gdb) watch num
Hardware watchpoint 2: num
(gdb) catch throw int
Catchpoint 3 (throw)

可以看到,我们通过 break 命令建立了一个普通断点,其编号为 1;通过 watch 命令建立了一个观察断点,其编号为 2;通过 catch 命令建立了一个捕捉断点,其编号为 3。

在此基础上,可以通过执行 info break 或者 info breakpoint 命令,查看所有断点的具体信息:

(gdb) info break
Num     Type                      Disp Enb Address                                                             What
1           breakpoint            keep y     0x0000555555555189 in main at main.c:2       breakpoint already hit 1 time
2           hw watchpoint      keep y                                                                               num
3           catchpoint             keep y     exception throw                                                matching: int
(gdb)

借助每个断点不同的编号,也可以进行精准查询:

(gdb) info break 1
Num     Type              Disp  Enb  Address                                                                What
1           breakpoint     keep y     0x000000000040053c in main at main.c:2            breakpoint already hit 1 time

以上输出信息中各列的含义分别是:断点编号(Num)、断点类型(Type)、是临时断点还是永久断点(Disp)、目前是启用状态还是禁用状态(Enb)、断点的位置(Address)、断点当前的状态(作用的行号、已经命中的次数等,用 What 列表示)。


2) 除此之外,对于调试环境中已经建好且未删除的观察断点,也可以使用 info watchpoint 命令进行查看,语法格式如下:

(gdb) info watchpoint [n]

n 为可选参数,为某个观察断点的编号,功能是只查看该编号的观察断点的信息,而不是全部的观察断点。

继续在上面的调试环境中,执行如下指令:

(gdb) info watchpoint
Num     Type                  Disp Enb Address            What
2           hw watchpoint  keep y                              num
(gdb) info watchpoint 1
No watchpoint number 1.

由于当前环境中仅有 1 个观察断点,因此 info watchpoint 命令仅罗列了编号为 2 的观察断点的信息。需要注意的是,该命令仅能用于查看观察断点,普通断点和捕捉断点无法使用该命令。

GDB删除断点

无论是普通断点、观察断点还是捕捉断点,都可以使用 clear 或者 delete 命令进行删除。

1) clear命令

clear 命令可以删除指定位置处的所有断点,常用的语法格式如下所示:

(gdb) clear location

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

在上面调试环境中,继续执行如下命令:

(gdb) clear 2

(gdb) info break
Deleted breakpoint 1
Num     Type                   Disp Enb Address               What
2            hw watchpoint  keep y                                 num
3            catchpoint         keep y     exception throw  matching: int
(gdb)

可以看到,断点编号为 1、位于程序第 2 行代码处的普通断点已经被删除了。

2) delete 命令

delete 命令(可以缩写为 d )通常用来删除所有断点,也可以删除指定编号的各类型断点,语法格式如下:

delete [breakpoints] [num]

其中,breakpoints 参数可有可无,num 参数为指定断点的编号,其可以是 delete 删除某一个断点,而非全部。

举个例子:

(gdb) delete 2
(gdb) info break
Num     Type              Disp Enb Address                 What
3           catchpoint     keep y    exception throw     matching: int

可以看到,delete 命令删除了编号为 2 的观察断点。

如果不指定 num 参数,则 delete 命令会删除当前程序中存在的所有断点。例如:

(gdb) delete
Delete all breakpoints? (y or n) y
(gdb) info break
No breakpoints or watchpoints.

GDB禁用断点

所谓禁用,就是使目标断点暂时失去作用,必要时可以再将其激活,恢复断点原有的功能。

禁用断点可以使用 disable 命令,语法格式如下:

disable [breakpoints] [num...]

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

举个例子:

(gdb) info break
Num     Type                   Disp Enb    Address                                     What
1           breakpoint         keep y        0x0000555555555189 in main  at main.c:2 breakpoint already hit 1 time
2           hw watchpoint   keep y                                                          num
3           catchpoint          keep y        exception throw                       matching: int
(gdb) disable 1 2
(gdb) info break
Num     Type                  Disp Enb    Address                                      What
1           breakpoint        keep n       0x0000555555555189 in main    at main.c:2 breakpoint already hit 1 time
2           hw watchpoint  keep n                                                           num
3           catchpoint         keep y       exception throw                          matching: int
(gdb)

可以看到,对于用 disable 命令禁用的断点,Enb 列用 n 表示其处于禁用状态,用 y 表示该断点处于激活状态。

对于禁用的断点,可以使用 enable 命令激活,该命令的语法格式有多种,分别对应有不同的功能:

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

其中,breakpoints 参数可有可无;num... 表示可以提供多个断点的编号,enable 命令可以同时激活多个断点。

仍以上面的调试环境为例,当下程序停止在第 2 行(main() 函数开头处),此时执行如下命令:

(gdb) info break
Num     Type                  Disp Enb  Address                                       What
1           breakpoint        keep n     0x0000555555555189 in main    at main.c:2 breakpoint already hit 1 time
2           hw watchpoint  keep n                                                         num
3           catchpoint         keep y     exception throw                          matching: int
(gdb) enable delete 2
(gdb) info break
Num     Type                   Disp   Enb  Address                                       What
1           breakpoint         keep   n     0x0000555555555189 in main    at main.c:2 breakpoint already hit 1 time
2           hw watchpoint   del      y                                                          num
3           catchpoint          keep y       exception throw                           matching: int
(gdb) c
Continuing.

Hardware watchpoint 2: num

Old value = 32767
New value = 0
main () at main.c:4
4     scanf("%d", &num);
(gdb) info break
Num     Type               Disp Enb    Address                                      What
1           breakpoint     keep n        0x0000555555555189 in main   at main.c:2  breakpoint already hit 1 time
3           catchpoint     keep y         exception throw                         matching: int
(gdb)

可以看到,通过借助 enable delete 命令,我们激活了编号为 2 的观察断点,但其只能作用 1 次,因此当继续执行程序时,其会在程序第 4 行暂停,随时该断点会被删除。

 

gdb查看指定地址的内存地址的值:

examine 简写 x-----使用gdb> help x 来查看使用方式


x/ (n,f,u为可选参数)

n: 需要显示的内存单元个数,也就是从当前地址向后显示几个内存单元的内容(就是要显示多少个地址),一个内存单元的大小由后面的u定义

 

 

f:显示格式(取值范围)

 

  • x(hex) 按十六进制格式显示变量。
  • d(decimal) 按十进制格式显示变量。
  • u(unsigned decimal) 按十进制格式显示无符号整型。
  • o(octal) 按八进制格式显示变量。
  • t(binary) 按二进制格式显示变量。
  • a(address) 按十六进制格式显示变量。
  • c(char) 按字符格式显示变量。
  • f(float) 按浮点数格式显示变量

 


u:每个单元的大小,按字节数来计算。默认是4 bytes。GDB会从指定内存地址开始读取指定字节,并把其当作一个值取出来,并使用格式f来显示

  • b:1 byte
  • h:2 bytes
  • w:4 bytes
  • g:8 bytes


比如x/3uh 0x54320 表示从内存地址0x54320读取内容,h表示以双字节为单位,3表示输出3个单位,u表示按照十六进制显示。

 

gdb打印表达式的值:print/f 表达式
f是输出的格式,x/d/u/o/t/a/c/f


表达式可以是当前程序的const常量,变量,函数等内容,但是GDB不能使用程序中所定义的宏


查看当前程序栈的内容: x/10x $sp-->打印stack的前10个元素
查看当前程序栈的信息: info frame----list general info about the frame
查看当前程序栈的参数: info args---lists arguments to the function
查看当前程序栈的局部变量: info locals---list variables stored in the frame
查看当前寄存器的值:info registers(不包括浮点寄存器) info all-registers(包括浮点寄存器)
查看当前栈帧中的异常处理器:info catch(exception handlers)


 

posted @ 2022-11-02 15:46  方东信  阅读(1668)  评论(0编辑  收藏  举报