GDB学习笔记
关于GDB调试工具的学习笔记,学会了纯命令行的调试操作,才能更好地理解例如VSCode提供的图形界面的调试功能等,GDB在WSL2 Ubuntu上进行操作。
调试信息
可执行程序可以被调试的前提就是编译时加上了调试信息,通常是debug模式下,加上-g
选项。
如果强行调试一个没有调试信息的可执行程序,将不能看见程序中的函数名或变量名等,而只是内存地址,并且会显示一条警告
1
(No debugging symbols found in <program>)
加载程序
正常情况下可以通过调试器来加载程序 1
gdb <program>
也可以先启动gdb,然后加载可执行文件 1
2gdb
(gdb) file <program>
加载的程序并不会直接执行,需要使用start
或run
命令来启动程序。
如果是需要调试一个生成core文件并异常终止的程序,可以加上core文件来恢复现场
1
gdb <program> <core dump file>
如果需要调试一个正在运行的程序,可以加上进程ID(一个整数),gdb将会自动以attach模式进行调试
1
gdb <program> <PID>
命令行参数
在程序启动之前可以查看和设置传入main函数的命令行参数args
:
show args
:查看当前采用的main函数命令行参数set args
:设置main函数命令行参数
例如 1
2(gdb) set args 10 20
(gdb) show args
执行控制
关于程序执行的调控命令:
start
:启动程序,在main函数入口处暂停run
:运行(直到遇到断点或错误)continue
:(假设在断点处暂停)继续执行(直到遇到断点或错误)next
:单步逐行执行,如果有函数调用,不会进入调用函数体)step
:单步向下执行,如果有函数调用,则会进入调用函数体finish
:向上执行,直到跳出函数体
断点(break)
设置断点的命令有很多,可以基于行号,函数名,与当前位置偏移等
1
2
3
4
5
6
7
8
9
10
11
12
13(gdb) break <line>
(gdb) break 10
// 在第10行设置断点
(gdb) break <function_name>
(gdb) break hello
// 在函数hello入口处设置断点
(gdb) break <file_name>:<line>
// 在指定源文件的指定行设置断点
(gdb) break <function_name>:<line>
// 在指定函数体的指定行设置断点
注意,如果函数体具有重载,则有多种选择,此时可以加上函数参数类型来指定具体的函数,否则gdb会提供候选函数的列表,需要输入编号来确认。
设置临时断点(断点在触发一次后自动失效) 1
(gdb) tbreak ...
设置条件断点(只有满足一定条件才会触发) 1
2
3(gdb) break ... if <condition>
(gdb) break file_name.cpp:15 if my_variable == 10
// 在指定函数体的指定行设置条件断点,触发要求为my_variable==10
禁用断点(需要首先打印并找到断点的编号) 1
(gdb) disable <breakpoint_id>
启用断点(在禁用之后可以让断点重新生效) 1
(gdb) enable <breakpoint_id>
删除断点(需要首先打印并找到断点的编号) 1
(gdb) delete <breakpoint_id>
查看变量(print)
print可以查看指定表达式的值 1
(gdb) print <expr>
例如 1
2
3
4
5
6
7
8
9(gdb) print my_variable
(gdb) print var1 var2 var3
(gdb) print my_array[5]
(gdb) print my_struct.member
(gdb) print &my_variable
监视点(display)
监视点可以做到在每次程序暂停时,自动打印指定变量的值,可以避免重复调用print查看变量
1 | (gdb) display <expr> |
取消对指定变量的监视 1
(gdb) undisplay <expr>
取消所有的监视点 1
(gdb) undisplay
观察点(watchpoints)
除了断点可以用来暂停程序,我们还可以设置观察点来观察一个表达式(变量也是一种表达式)的值是否有了变化,如果发生变化则立刻暂停
设置普通观察点,当表达式的值发生变化时立刻暂停 1
(gdb) watch <expr>
设置读取观察点,当表达式被读时立刻暂停 1
(gdb) rwatch <expr>
设置读取观察点,当表达式被读或者被写时立刻暂停 1
(gdb) awatch <expr>
查看源码(list)
list
可以查看当前位置附加的源代码,也可以加上行号或函数名等来显示指定位置的代码
1 | (gdb) list |
指定的行数或者函数入口会显示在正中,默认会显示当前位置前后各5行的源代码,也可以查看和修改显示的总行数
1 | (gdb) set listsize <num> |
查看信息(info)
info命令可以查看很多信息,包括断点/变量/监视点/观察点等。
查看所有断点或指定编号的断点 1
2
3
4(gdb) info break
(gdb) info breakpoints
(gdb) info break <breakpoint_id>
列出当前的所有局部变量 1
(gdb) info locals
列出当前的所有变量 1
(gdb) info variables
查看所有的监视点 1
(gdb) info display
列出当前所有的观察点 1
(gdb) info watchpoints
修改变量
在程序暂停时,可以修改指定变量的值 1
(gdb) set var <my_variable> = <new_value>
例如 1
(gdb) set var x=4
GUI界面
gdb的tui相关命令提供了基于命令行的简单GUI支持,可以在上半屏幕显示源码/汇编等,在下半屏幕使用gdb命令行操作。在GUI模式下,上下键操作会移动GUI上显示的行位置。
可以使用快捷键ctrl+x+a
开启和关闭GUI界面。
命令缩写
gdb的很多常见命令都可以等价替换为单个字母的缩写:
- b=break(断点)
- c=continue(继续执行)
- s=step(单步执行,逐语句)
- n=next(逐过程,跳过函数调用)
- r=run(运行程序)
- p=print(打印变量值)
- d=delete(删除断点)
- l=list(显示源代码)
- i=info(显示信息)
- q=quit(退出 GDB)
退出
quit
或exit
可以退出gdb,如果有正在调试的程序,则会终止程序(需要确认终止)
1 | (gdb) quit |