gdb常用技巧

3种启用gdb的方法

1
2
3
1.gdb <program>
2.gdb <program> core
3.gdb <program> <PID>

命令行参数

  • gdb命令行的 -args 参数
  • gdb环境中 set args 命令

gdb中变量

可以查看运行时的变量,也可以直接设置程序中的变量,以模拟一些很难在测试中出现的情况,比较一些出错,或是switch的分支语句。使用set命令可以修改程序中的变量。

另外gdb也有变量,gdb的变量以$开头,比如打印数组中的每个元素,可以:

1
2
3
(gdb) set $i = 0
(gdb) p a[$i++]
.......

然后一路回车下去了。

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
r                        ============>运行程序, run 命令简写
c ============>继续运行程序,continue命令缩写
l ============>列出源码, list 命令简写
b ============>设置断点,具体请看下面一节
info break ============>查看断点信息
n ============>单条语句执行,不进入函数,next 命令缩写
s ============>单条语句执行,进入函数,step命令缩写
p i ============>打印变量值,print命令缩写
display i ============>显示变量值,后面每行都会显示
bt ============>查看函数堆栈,backtrace命令缩写
shell <command string> ============>在gdb中运行shell脚本
finish ============>退出函数
q ============>退出gdb
<enter> ============>重复上一条命令
ptype ============>显示变量的数据类型
jump line ============>跳到指定行开始调试
set var=exp ============>设置变量var的值为exp
kill ============>结束当前程序的调试
x/[n][format][size] address ============>查看内存


断点相关
break func ===============>在函数func入口处设置断点
break file.c:100 ===============>在file.c第100行设置断点
break [where] if [condition] ===============>设置条件断点
break file.c:100 thread all ===============>在file.c文件第100行处,为所有经过这里的线程设置断点
info break ===============>查看断点列表,会显示id
delete id ===============>删除断点
clear func ===============>删除断点,不需要id,格式同break
break xxxxx if a==1 ===============>条件断点
condition N COND ===============>条件断点,N为断点号码,COND为条件
info thread ===============>查看thread信息
t <thread id> ===============>切换到id进程,thread命令缩写

在gdb中,有几种暂停方式: 断点(breakpoint),观察点(watchpoint),捕捉点(catchpoint),信号(signals),线程停止(Thread Stops)
在gdb停住时,可以用info program来查看程序是否在运行,进程号,被暂停的原因。可以用continue来恢复程序运行

watch *(type *) addr ================>watch地址addr的改变, type为addr实际指向的数据类型
watch var ================>watch变量var的改变

多线程调试

1.调试已运行的程序
1)ps查看PID,然后gdb <program PID>挂接正在运行的程序
2)gdb <program>关联上源代码,并进行gdb,在gdb中用attach命令来挂接进程的PID, 用detach来取消挂接的进程。

1
2
3
4
5
6
7
info thread 查看当前进程的线程
thread <id> 切换调试的线程为指定id的线程,t <id>
break file.c:100 thread all ===============>在file.c文件第100行处,为所有经过这里的线程设置断点
set scheduler-locking off|on|step,在使用step或者continue命令调试当前被调试线程的时候,其他线程也是同时执行的,怎么只让被调试线程执行呢?通过这个命令就可以实现这个需求。
off 不锁定任何线程,也就是所有线程都执行,这是默认值。
on 只有当前被调试程序会执行。
step 在单步的时候,除了next过一个函数的情况(熟悉情况的人可能知道,这其实是一个设置断点然后continue的行为)以外,只有当前线程会执行。

调试宏

在gcc编译的时候,加上-ggdb3参数,就可以调试宏了。

1
2
info macro - 查看这个宏在那些文件被引用了,以及宏定义是什么样子的。
macro - 查看宏展开的样子

自动化调试

使用command命令,简单的理解一下,其就是把一组gdb的命令打包,有点像字处理软件的“宏”。下面是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12

(gdb) break func
Breakpoint 1 at 0x3475678: file test.c, line 12.
(gdb) commands 1 // 1 是断点号
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>print arg1
>print arg2
>print arg3
>end
(gdb)
当我们的断点到达时,自动执行command中的三个命令,把func的三个参数值打出来。

gdb server

这个主要是针对一些没有安装gdb的嵌入式设备

1)在目标target host上开启gdbserver

1
> gdbserver <target host ip>:2345[这个端口可以自己根据需要设置] test

2)到host端,也就是安装有gdb的主机

1
2
3
4
> gdb test
[> set solib-absolute-prefix <gdb directory>]
[> set solib-search-path <gdb directory/lib或者其他库文件的路径>]
> target remote <target host ip>:2345

然后在host端来调试target上的程序