GDB常用命令

常用命令
命令(缩写)功 能
run(r)启动或者重启一个程序,在第一个断点处暂停。
start执行至main()起始位置前
attach调试正在运行的程序或多进程调试。
break(b)[linenum]打断点
list(l)[linenum]显示带有行号的源码。
continue(c)运行至下一个断点。
next(n)单步(单行)调试程序。
nexti执行一条机器指令
step(s)如果有调用函数,进入调用的函数内部;否则,和 next 命令的功能一样。
stepi执行一条机器指令
until(u)
until location
在循环体最后一行使用 until 命令,快速退出循环体。 until n 命令中,n 为行号,该命令会使程序运行至第 n 行代码处停止。
finish(fi)结束当前正在执行的函数,并在跳出函数后暂停程序的执行。
return(return)结束当前调用函数(剩余代码不会执行)并返回指定值,到上一层函数调用处停止程序执行。
jump(j)使程序从当前要执行的代码处,直接跳转到指定位置处继续执行后续的代码(中间代码不执行)。
print(p)[val]打印指定变量的值。
quit(q)退出 GDB 调试器。
启动GDB

g++ main.cpp -o main.exe -g

-O0~-O4为优化等级,-Og可自动优化

 

1

# 调试正在执行的程序

2

3

pidof main.exe # 获取进程号

4

5

gdb attach PID # 通过进程号来调试进程

6

gdb 文件名 PID

7

gdb -p PID

8

9

# 连接后该程序会暂停

10

# 结束后令程序继续执行,需手动分离GDB与程序

11

1. detach

12

2. q

13

14

15

# 调试执行异常崩溃的程序

16

# 系统崩溃的内存数据、调用堆栈会存储到core文件,该功能称为核心转储(core dump)

17

# 段错误又称为访问权限冲突,指的是当前程序访问了不可访问的存储空间,比如访问的不存在的空间,又或者是受系统保护的内存空间

18

19

ulimit -a # 查看core file size

20

# core file size (blocks, -c) 0

21

ulimit -c unlimited

22

ulimit -a

23

# core file size (blocks, -c) unlimited

24

25

gdb main.exe core

启动GDB调试器常用参数

参 数功 能
-pid number
-p number
调试进程 ID 为 number 的程序。
-symbols file
-s file
仅从指定 file 文件中读取符号表。
-q
-quiet
-silent
取消启动 GDB 调试器时打印的介绍信息和版权信息
-cd directory以 directory 作为启动 GDB 调试器的工作目录,而非当前所在目录。
–args 参数1 参数2…向可执行文件传递执行所需要的参数。
启动程序
 

1

run # 执weii行至第一个断点,若无断点则执行完毕

2

start # 执行至main()起始位置前

3

# 过程中使用run或start表示重新启动程序

向目标程序传递参数

 

1

gdb --args main.exe param # 被argv[]接收

2

3

(gdb)

4

set args param

5

run param

6

start param

7

8

# 将程序结果重定向输出到a.txt

9

run > a.txt
 

1

file ../main.exe # 指定文件

2

cd ../ # 修改工作目录

3

path /demo # 临时修改环境变量,退出gdb失效
设置普通断点
 

1

b location [if cond]

2

# b 7 if num>10 # 每次程序执行到第7行都计算num的值,if num>10则在第7行打断点,else 程序继续执行

3

4

tbreak # 断点只执行1次,程序暂停后断点消失

5

rbreak regex # 给所有满足正则表达式的函数开头都打上断点,非临时
location 的值含 义
linenumlinenum 行号。通过 l 命令看代码。
filename:linenum某文件的某一行
+ offset - offset当前程序暂停位置向后(+)或向前(-)第几行
functionfunction 函数名,在该函数内部第一行打断点
filename:function远程文件的函数名
 

1

# 条件断点

2

condition bnum expression

3

condition bnum

4

# 参数 bnum 用于代指目标断点的编号;参数 expression 表示为断点添加或修改的条件表达式。

5

info break

6

# 通过此命令得到断点编号

7

8

# 使某断点失效count次

9

ignore bnum count
设置观察断点
 

1

watch cond # 监控【变量或表达式】,只有cond值发生改变,程序暂停

2

rwatch cond # 只要出现读取cond操作,程序暂停

3

awatch cond # 只要出现读取cond或更改值的操作,程序暂停

4

5

info watchpoints # 查看当前建立的观察点

cond为局部变量时,cond失效则watch失效

监控*p是指针p所指的数据,监控p是指针本身有无改变指向

数组中有任一数据改变,都能监测到并停止程序

watch命令分为硬件观察点和软件观察点。软件观察点,即GDB会单步执行程序,每行代码结束都会检测cond;硬件观察点不会影响效率,但限制个数。awatch和rwatch只能设置为硬件观察点。

设置捕捉断点
 

1

catch event # 监控程序中某一事件的发生,例如程序发生某种异常时、某一动态库被加载时等等,一旦目标事件发生,则程序停止执行

2

tcatch # 前者是永久,后者是只监测一次
event 事件含 义
throw [exception]当程序中抛出 exception 指定类型异常时,程序停止执行。如果不指定异常类型(即省略 exception),则表示只要程序发生异常,程序就停止执行。
catch [exception]当程序中捕获到 exception 异常时,程序停止执行。exception 参数也可以省略,表示无论程序中捕获到哪种异常,程序都暂停执行。
load [regexp] unload [regexp]其中,regexp 表示目标动态库的名称,load 命令表示当 regexp 动态库加载时程序停止执行;unload 命令表示当 regexp 动态库被卸载时,程序暂停执行。regexp 参数也可以省略,此时只要程序中某一动态库被加载或卸载,程序就会暂停执行。

当 catch 命令捕获到指定的 event 事件时,程序暂停执行的位置往往位于某个系统库(例如 libstdc++)中。这种情况下,通过执行 up 命令,即可返回发生 event 事件的源代码处。

catch 无法捕获以交互方式引发的异常。

查看删除禁用断点
 

1

info breakpoint [n]

2

info break [n]

3

info watchpoint [n]
 

1

clear location # 删除指定位置处的所有断点

2

delete [breakpoints] [num] # 删除所有断点或指定断点编号
 

1

disable [breakpoints] [num...]

2

enable [breakpoints] [num...]

3

enable [breakpoints] once num... # 临时激活以 num... 为编号的多个断点,但断点只能使用 1 次,之后会自动回到禁用状态

4

enable [breakpoints] count num... # 临时激活以 num... 为编号的多个断点,断点可以使用 count 次,之后进入禁用状态

5

enable [breakpoints] delete num... # 激活 num.. 为编号的多个断点,但断点只能使用 1 次,之后会被永久删除。
调试命令
 

1

next [count] # n,执行count行代码,调用函数只视为单行

2

step [count] # s,会进入函数,并在第一行暂停

3

until [location] # u,只有执行至循环体最后一行,才会快速运行完当前循环体然后停止,否则和next一样为单步执行;跟行号则表示执行至指定位置
 

1

print [options --] [/fmt] expr

2

# 输出和修改

3

print num

4

print num=4

5

6

print first@len # 输出数组指定区域

7

有:int array[5] = {1,2,3,4};

8

执行:print array[0]@2

9

得:$1 = {1, 2}

10

11

print file::variable # 支持域运算符

12

13

# 执行一次,则每次程序暂停时都会打印该表达式的值

14

display[/fmt] expr # display与参数间无空格

15

info display # 所有display过的表达式

16

17

undisplay num # 删除表达式

18

delete display num

19

20

enable display num # 激活和禁用表达式

21

disable display num
options 参数功 能
-address on|off查看某一指针变量的值时,是否同时打印其占用的内存地址,默认值为 on。该选项等同于单独执行 set print address on|off 命令。
-array on|off是否以便于阅读的格式输出数组中的元素,默认值为 off。该选项等同于单独执行 set printf array on|off 命令。
-array-indexes on|off对于非字符类型数组,在打印数组中每个元素值的同时,是否同时显示每个元素对应的数组下标,默认值为 off。该选项等同于单独执行 set print array-indexes on|off 命令。
-pretty on|off以便于阅读的格式打印某个结构体变量的值,默认值为 off。该选项等同于单独执行 set print pretty on|off 命令。
/fmt功 能
/x以十六进制的形式打印出整数。
/d以有符号、十进制的形式打印出整数。
/u以无符号、十进制的形式打印出整数。
/o以八进制的形式打印出整数。
/t以二进制的形式打印出整数。
/f以浮点数的形式打印变量或表达式的值。
/c以字符形式打印变量或表达式的值。
多线程调试

多线程编译命令

g++ main.cpp -o main.exe -g -lpthread

调试命令功 能
info threads查看当前调试环境中包含多少个线程,并打印出各个线程的相关信息,包括线程编号(ID)、线程名称等。
thread id将线程编号为 id 的线程设置为当前线程。
thread apply id… commandid… 表示线程的编号;command 代指 GDB 命令,如 next、continue 等。整个命令的功能是将 command 命令作用于指定编号的线程。当然,如果想将 command 命令作用于所有线程,id… 可以用 all 代替。
break location thread id在 location 指定的位置建立普通断点,并且该断点仅用于暂停编号为 id 的线程。
set scheduler-locking off|on|step默认情况下,当程序中某一线程暂停执行时,所有执行的线程都会暂停;同样,当执行 continue 命令时,默认所有暂停的程序都会继续执行。该命令可以打破此默认设置,即只继续执行当前线程,其它线程仍停止执行。

默认情况下,无论哪个线程暂停执行,其它线程都会随即暂停;反之,一旦某个线程启动(借助 next、step、continue 命令),其它线程也随即启动。GDB 调试默认的这种调试模式(称为全停止模式 all stop),一定程序上可以帮助我们更好地监控程序中各个线程的执行。

non-stop模式:调试个别线程时,不影响其他线程的执行。

  • 保持其它线程继续执行的状态下,单独调试某个线程;
  • 在所有线程都暂停执行的状态下,单步调试某个线程;
  • 单独执行多个线程等等。

在 all-stop 模式下,continue、next、step 命令的作用对象并不是当前线程,而是所有的线程;但在 non-stop 模式下,continue、next、step 命令只作用于当前线程。在 non-stop 模式下,如果想要 continue 命令作用于所有线程,可以为 continue 命令添加一个 -a 选项,即执行 continue -a 或者 c -a 命令,即可实现令所有线程继续执行的目的。

 

1

set non-stop on|off # on表示启用non-stop模式

2

show non-stop # 查看是否开启

后台异步调试:command&

暂停后台执行线程:interrupt

反向调试

回退

命 令功 能
(gdb) record (gdb) record btrace让程序开始记录反向调试所必要的信息,其中包括保存程序每一步运行的结果等等信息。进行反向调试之前(启动程序之后),需执行此命令,否则是无法进行反向调试的。
(gdb) reverse-continue (gdb) rc反向运行程序,直到遇到使程序中断的事件,比如断点或者已经退回到 record 命令开启时程序执行到的位置。
(gdb) reverse-step反向执行一行代码,并在上一行代码的开头处暂停。和 step 命令类似,当反向遇到函数时,该命令会回退到函数内部,并在函数最后一行代码的开头处(通常为 return 0; )暂停执行。
(gdb) reverse-next反向执行一行代码,并在上一行代码的开头处暂停。和 reverse-step 命令不同,该命令不会进入函数内部,而仅将被调用函数视为一行代码。
(gdb) reverse-finish当在函数内部进行反向调试时,该命令可以回退到调用当前函数的代码处。
(gdb) set exec-direction modemode 参数值可以为 forward (默认值)和 reverse:forward 表示 GDB 以正常的方式执行所有命令;reverse 表示 GDB 将反向执行所有命令,由此我们直接只用step、next、continue、finish 命令来反向调试程序。注意,return 命令不能在 reverse 模式中使用。
查看栈信息

每个被调用的函数在执行时,都会生成:

  • 函数调用发生在程序中的具体位置;
  • 调用函数时的参数;
  • 函数体内部各局部变量的值等等。

这些信息会集中存储在一块称为“栈帧”的内存空间中。也就是说,程序执行时调用了多少个函数,就会相应产生多少个栈帧,其中每个栈帧自函数调用时生成,函数调用结束后自动销毁。

main() 主函数对应的栈帧,又称为初始帧或者最外层的帧。多调用一个函数,执行过程中就会生成一个新的栈帧。更甚者,如果该函数是一个递归函数,则会生成多个栈帧。每个栈帧用地址来作标识符(非栈帧本身起始地址),GDB用编号来管理。

 

1

frame spec # spec参数指定栈帧。spec 参数的值,常用指定方法:
  1. 通过栈帧的编号指定。0 为当前被调用函数对应的栈帧号,最大编号的栈帧对应的函数通常就是 main() 主函数;
  2. 借助栈帧的地址指定。栈帧地址可以通过 info frame 命令打印出的信息中看到;
  3. 通过函数的函数名指定。注意,如果是类似递归函数,其对应多个栈帧的话,通过此方法指定的是编号最小的那个栈帧。
 

1

# 对于选定一个栈帧作为当前栈帧,有

2

up n # n 为整数,默认值为 1。该命令表示在当前栈帧编号(假设为 m)的基础上,选定 m+n 为编号的栈帧作为新的当前栈帧

3

down n # 选定 m-n 为编号的栈帧

4

5

info frame # 打印栈帧信息
  • 当前栈帧的编号,以及栈帧的地址;
  • 当前栈帧对应函数的存储地址,以及该函数被调用时的代码存储的地址
  • 当前函数的调用者,对应的栈帧的地址;
  • 编写此栈帧所用的编程语言;
  • 函数参数的存储地址以及值;
  • 函数中局部变量的存储地址;
  • 栈帧中存储的寄存器变量,例如指令寄存器(64位环境中用 rip 表示,32为环境中用 eip 表示)、堆栈基指针寄存器(64位环境用 rbp 表示,32位环境用 ebp 表示)等。
 

1

info args # 查看当前函数各个参数的值

2

info locals # 查看当前函数中各局部变量的值
 

1

# 打印当前调试环境中所有栈帧的信息

2

backtrace [-full] [n]
  • n:一个整数值,当为正整数时,表示打印最里层的 n 个栈帧的信息;n 为负整数时,那么表示打印最外层 n 个栈帧的信息;
  • -full:打印栈帧信息的同时,打印出局部变量的值。
编辑和搜索源码
 

1

edit [location]

2

edit [filename :] [location]

3

4

# gdb默认编辑器为ex,临时指定编辑器为vim,退出shell失效

5

export EDITOR=/usr/bin/vim
 

1

list [n]

2

search <regexp> # 从当前行开始向前搜索,regexp为字符串正则表达式

3

reverse-search <regexp> # 从当前行开始向后搜索
help

help 命令/参数

自动补全

<TAB> 补全

<双TAB> 罗列所有同前缀的命令

完成命令后 <双TAB> 罗列所有参数

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值