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)
java新手自学群 626070845
java/springboot/hadoop/JVM 群 4915800
Hadoop/mongodb(搭建/开发/运维)Q群481975850
GOLang Q1群:6848027
GOLang Q2群:450509103
GOLang Q3群:436173132
GOLang Q4群:141984758
GOLang Q5群:215535604
C/C++/QT群 1414577
单片机嵌入式/电子电路入门群群 306312845
MUD/LIB/交流群 391486684
Electron/koa/Nodejs/express 214737701
大前端群vue/js/ts 165150391
操作系统研发群:15375777
汇编/辅助/破解新手群:755783453
大数据 elasticsearch 群 481975850
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。