WangYu::Space

Study, think, create, and grow. Teach yourself and teach others.

GDB 常见用法

分类:工具创建时间:2021-04-23 00:00:00修改时间:2024-10-30 16:22:52

GDB QUICK REFERENCE 这个 PDF 中罗列了 GDB 常用的命令及其用法,推荐收藏。

启动 GDB

下面是一些启动 GDB 的实际例子:

# 启动可执行文件并执行调试
$ gdb ./a.out

# 调试正在运行的程序
$ gdb
(gdb) attach <pid>

# 根据 core 文件调试
$ gdb <program> <core>

# 启动调试时指定参数
$ gdb --args ./build/nutcracker --version

断点(break)

常规用法:

# 在函数 foo 处设置断点,break 可以简写为 b
(gdb) break foo
(gdb) b foo

# 在 foo.c 中的 foo 处设置断点
(gdb) b foo.c:foo

# 在 foo.c 中的第 100 行设置断点
(gdb) b foo.c:100

# 在当前位置后的第 10 行处设置断点
(gdb) b +10
# 在当前位置前的第 10 行处设置断点
(gdb) b -10

# 在当前源文件的第 100 行设置断点
(gdb) b 100

# 在指令地址处设置断点
# 下面的两行命令在 main 函数后 20 个字节处设置断点
(gdb) p main
$1 = {int (int, char **)} 0x47e300 <main>
(gdb)  b *0x47e300 + 20
# 也可以写做
(gdb)  b *main + 20

临时断点:

# 该断点进入一次后会自动删除,tbreak 可以简写为 tb
(gdb)  tbreak foo
(gdb)  tb foo

使用正则表达式设置断点:

# 在匹配 foo* 的函数处设置断点
(gdb)  rbreak foo*

给断点增加条件:

# 条件成立时才进入断点
(gdb) b foo if num == 1001

# 也可以使用 condition 命令,语法为:
# condition <breakpoint_number> <condition>
# 如下命令给断点 1 增加条件
(gdb) condition 1  num == 101

# 也可以使用入门命令删除条件
(gdb) condition <breakpoint_number>

给 C++ 重载函数加断点:

因为 C++ 中存在函数重载,比如:

int add(int i,int j){...}
int add(float i,float j){...}

使用函数名加断点时,无法确定要加到那个函数上,此时可以使用如下命令:

(gdb)  b add(int, int)

观察断点:

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000000000047e300 in main at foo.c:1002
2       breakpoint     keep y   0x000000000047e30a in main at foo.c:1002
3       breakpoint     del  y   0x000000000047e300 in main at foo.c:1002

删除断点:

# 删除编号为 1 的断点
(gdb) d 1

观察点(watch)

观察点用来观察某个表达式的值是否有变化了,如果有变化,马上停住程序。

# 表达式值有变化时,马上停住程序
(gdb) watch expr

# 当变量被读时,停住程序。
(gdb) rwatch var

# 变量被读写时,停住程序
(gdb) awatch var

# 列出所有的观察点
(gdb) info watchpoints

捕捉点

你可设置捕捉点来补捉程序运行时的一些事件,比如 C++的异常。

设置捕捉点的语法为:

catch $event

你可以查看帮助获取 event 的可取值:

(gdb) help catch   
Set catchpoints to catch events.

List of catch subcommands:

catch assert -- Catch failed Ada assertions
catch catch -- Catch an exception
catch exception -- Catch Ada exceptions
catch exec -- Catch calls to exec
catch fork -- Catch calls to fork
catch handlers -- Catch Ada exceptions
catch load -- Catch loads of shared libraries
catch rethrow -- Catch an exception
catch signal -- Catch signals by their names and/or numbers
catch syscall -- Catch system calls by their names
catch throw -- Catch an exception
catch unload -- Catch unloads of shared libraries
catch vfork -- Catch calls to vfork

查看源码

启动 gdb 后希望能够看到当前程序的源码,这样才方便调试,此时可以使用 layout 命令。该命令可以帮你看到当前的源码、寄存器、汇编代码等。

layout [src|asm|split|regs]

# src   : Displays source and command windows.
# asm   : Displays disassembly and command windows.
# split : Displays source, disassembly and command windows.
# regs  : Displays register window.

# 在 layout 窗口中按下 ctrl+x a 可以关闭窗口

控制执行

r # Runs the program until a breakpoint or error

c # Continues running the program until the next breakpoint or error

f # Runs until the current function is finished

s # Runs the next line of the program

s N # Runs the next N lines of the program

n # Like s, but it does not step into functions

u N # Runs until you get N lines in front of the current line

打印变量的值

print [Expression] # 打印一个表达式的值
p [Expression]


p {[Type]}[Address] # 将一个地址视为某种类型,然后打印
 
# 打印数组
print [First element]@[Element count]

# nums 是数组或者指针,下面打印前 10 个元素
print nums@10

# 以不同的格式打印
print /[Format] [Expression]

# Format 的取值和解释如下:
# o - octal
# x - hexadecimal
# u - unsigned decimal
# t - binary
# f - floating point
# a - address
# c - char
# s - string


watch <var>      # 在 <var> 改变时打印此变量

display <var>    # 在程序每次暂停时都自动打印 <var>
undisplay <var>  # 取消 display


# 设置打印内容的最大长度
set print elements 100

查看堆栈情况

查看调用栈,在不同的函数帧中切换,可以方便地观察调用过程,以及不同栈帧中的变量。

bt # 查看当前调用栈

up # 跳到上一帧

down # 跳到下一帧

return # 返回当前函数帧

current # 查看当前帧

f n     # 回到第 n 帧

线程

(gdb) info threads  # 查看有那些线程

(gdb) t 2  # 切换至线程 2

评论 (评论内容仅博主可见,不会公开显示)