本文档主要参看«Debugging with GDB» Tenth Edition, for gdb version 8.0.1
。
本文我们主要会介绍通过GDB打印程序中的各种数据类型。
1. 打印ASCII字符串和宽字符串
1) 示例程序
2) 调试技巧
用GDB调试程序时,可以使用x/s
命令打印ASCII字符串。以上面程序为例:
可以看到打印出了str1字符串的值。
打印宽字符字符串时,要根据宽字符的长度决定如何打印。仍以上面程序为例:
由于当前平台宽字符的长度为4个字节,则用x/ws
命令; 如果是2个字节,则用x/hs
命令。
2. 打印大数组中的内容
1) 示例程序
2) 调试技巧
在gdb中,如果要打印大数组的内容,缺省最多会显示200个元素:
可以使用如下命令设置这个最大限制数:
(gdb) set print elements number-of-elements
也可以使用如下命令,设置为没有限制:
(gdb) set print elements 0
或者
(gdb) set print elements unlimited
另外,如果要打印数组中任意连续元素的值,可以使用p array[index]@num
命令。其中index
是数组索引(从0开始计数),num
是连续多少个元素。以上面代码为例:
可见打印了array
数组的第10~19功10个元素。
如果要打印从数组开头连续元素的值,也可以使用命令p *array@num
。例如:
(gdb) p *array@10
$7 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
3. 打印数组的索引下标
1) 示例程序
2) 调试技巧
在gdb中,当打印一个数组时,缺省是不打印索引下标的:
如果要打印索引下标,则可以通过如下命令进行设置:
(gdb) set print array-indexes on
(gdb) p num
$2 = {[0] = 1, [1] = 2, [2] = 4, [3] = 8, [4] = 16, [5] = 32, [6] = 64, [7] = 128, [8] = 256, [9] = 512}
(gdb)
4. 打印函数局部变量的值
1) 示例程序
2) 调试技巧1
如果要打印函数局部变量的值,可以使用bt full
命令。首先我们在函数fun_a()中打上断点,当程序断住时,显示调用栈信息:
接下来,用bt full
命令显示各个函数的局部变量值:
也可以使用如下bt full n
,意思是从内向外显示n个栈帧,及其局部变量,例如:
而bt full -n
,意思是从外向内显示n个栈桢,及其局部变量,例如:
3) 调试技巧2
如果只是想打印当前函数局部变量的值,可以使用如下命令:
5. 打印进程内存信息
用gdb调试程序时,如果想查看进程的内存映射信息,可以使用info proc mappings
命令,例如:
首先输出了进程的flags,接着是进程的内存映射信息。
此外,也可以用info files
(还有一个同样作用的命令: info target
)命令,它可以更详细地输出进程的内存信息,包括引用的动态链接库等等。例如:
6. 打印变量的类型和所在文件
1) 示例程序
2) 调试技巧
在gdb中,可以使用如下命令查看变量的类型:
如果想查看详细的类型信息:
如果想查看定义该变量的文件:
上面我们看到, GDB会显示所有包含(匹配)该表达式的变量。如果只想查看完全匹配给定名字的变量,则:
注意: info variables
不会显示局部变量,即使是static的也没有太多的信息。
7. 打印内存的值
1) 示例程序
2) 调试技巧
GDB中使用x
命令来打印内存的值,格式为x/nfu addr
。含义为以f
格式打印从addr开始的n
个长度单元为u
的内存在。参数具体含义如下:
n: 输出单元的个数;
f: 是输出格式。比如x是以16进制形式输出,o是以8进制形式输出,等等;
u: 标明一个单元的长度。b是一个byte, h是2个byte(halfword),w是4个byte(word),g是8个byte(giant word);
以上面程序为例:
- 以无符号10进制格式打印数组a的前16个byte的值
- 以16进制格式打印数组a的前16个word(4个byte)的值
8. 打印源代码行
1) 示例程序
2) 调试技巧
在GDB中可以使用list命令来显示源代码以及行号。list命令可以指定行号、函数:
还可以指定向前或向后打印:
还可以指定打印范围:
9. 每行打印一个结构体成员
1) 示例程序
2) 调试技巧
默认情况下,GDB是以一种紧凑
的方式打印结构体。以上面代码为例:
可以看到结构体显示很混乱,尤其是结构体里还嵌套着其他结构体时。
可以执行set print pretty on
命令,这样每行只会显示结构体的一名成员,而且还会根据成员的定义层次进行缩进:
10. 按照派生类型打印对象
1) 示例程序
2) 调试技巧
在GDB中,当打印一个对象时,缺省是按照声明的类型进行打印:
在这个例子中,p虽然声明为class Shape
,但它实际的派生类型可能为class Circle
和class Square
。如果要缺省按照派生类型进行打印,则可以通过如下命令进行设置:
当打印对象类型信息时,该设置也会起作用:
11. 指定程序的输入输出设备
1) 示例程序
2) 调试技巧
在GDB中,缺省情况下程序的输入输出是和GDB使用同一个终端。你也可以为程序指定一个单独的输入输出终端。首先我们查看当前终端设备文件名:
# tty
/dev/pts/0
然后,打开一个新终端,使用如下命令获得设备文件名:
# tty
/dev/pts/1
接着,我们在/dev/pts/0
终端下启动程序,通过命令行选项指定程序的输入输出设备:
这时,我们可以看到在/dev/pts/1
终端下输出了打印值。
另外,我们也可以在GDB中通过使用如下命令来切换终端:
(gdb) tty /dev/pts/1
12. 打印调用栈帧中的变量值
1) 示例程序
2) 调试技巧
在GDB中,如果想查看调用栈帧中的变量,可以先切换到该栈帧中,然后打印:
也可以不进行切换,直接打印:
同样,对于C++的函数名,需要使用单引号括起来,比如:
[参看]
-
100个gdb小技巧
-
设置 GDB 代码搜索路径