gdb调试程序之查看运行时数据【五】

时间:2022-02-16 16:40:55

在用gdb调试程序时,当程序运行到之前设置的断点时,很容易想到的操作就是查看当前变量的值,而gdb可以很轻易地满足的你的需求的~~

在gdb中最常用的命令就是print(简写p),具体格式如下:

print <expr>
print/f <expr>  f代表输出的格式
 x 按十六进制格式显示变量
 d 按十进制格式显示变量
 u 按十六进制格式显示无符号整型
 o 按八进制格式显示变量
 t 按二进制格式显示变量
 a 按十六进制格式显示变量
 c 按字符格式显示变量
 f 按浮点数格式显示变量

表达式

print命令可以接受表达式,其中表达式的定义遵循C/C++语法,需要注意的是表达式中不能出现程序中定义的宏表达式;同时在gdb表达式中,还支持以下三种特殊的操作符:

@       是一个和数组有关的操作符,在后面会有更详细的说明
::      指定一个在文件或是一个函数中的变量,注意与C++语法中的::操作符的区分
{}      表示一个指向内存地址的类型为type的一个对象

 

程序变量的定位

在GDB中,查看以下三种变量的值:
1、全局变量(所有文件可见的)
2、静态全局变量(当前文件可见的)
3、局部变量(当前Scope可见的)

如果出现局部变量和全局变量相互冲突时,局部变量会覆盖全局变量,可以使用::限制符来查看全局变量

file::variable
function::variable

注意事项:如果在编译时加入了编译优化选项,即-O3选项,编译器会修改你的程序,同时可能查看不同某些变量,这时在调试时建议把优化选项关掉,即-O0

动态数组

你需要查看一段连续的内存空间的值。比如数组的一段,或是动态分配的数据的大小。你可以使用GDB的“@”操作符,“@”的左边是第一个内存的地址的值,“@”的右边则你你想查看内存的长度。例如,你的程序中有这样的语句:

int *array = (int *) malloc (len * sizeof (int));

于是,在GDB调试过程中,你可以以如下命令显示出这个动态数组的取值:

p *array@len

@的左边是数组的首地址的值,也就是变量array所指向的内容,右边则是数据的长度,其保存在变量len中,其输出结果,大约是下面这个样子的:

(gdb) p *array@len
$1 = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40}

查看内存

gdb中可以使用examine命令来查看内存内容,简写为x,使用方法如下:

x/<n/f/u> <addr>
  n、f、u是可选的参数。
  n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容。
  f 表示显示的格式,参见上面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。
  u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字节,g表示八字节。
    当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。
  <addr>表示一个内存地址。

例如

x/3uh 0x54320  从内存地址0x54320读取内容,h表示以双字节为一个单位,3表示三个单位,u表示按十六进制显示

自动显示

在gdb中,你可以设置当程序停在断点处时,自动显示变量的内容,即display命令,使用如下:

 display <expr>
 display/<fmt> <expr>
 display/<fmt> <addr>
 expr是一个表达式,fmt表示显示的格式,addr表示内存地址

一个非常有用的命令,显示源码与机器码的对应:

display/i $pc
$pc是GDB的环境变量,表示着指令的地址,/i则表示输出格式为机器指令码,也就是汇编。于是当程序停下后,就会出现源代码和机器指令码相对应的情形

与display管理相关的命令:

undisplay
delete display
disable display
enable display
info display  查看display设置的自动显示的信息

查看寄存器

info registers            查看寄存器的情况。(除了浮点寄存器)
info all-registers        查看所有寄存器的情况。(包括浮点寄存器)
info registers       查看所指定的寄存器的情况