Linux C ————17、gdb使用详解

通过使用gdb的逐步调试代码,可以看到程序内部是如何运行的,还可以查看程序中变量的值、内存使用情况、栈信息以及其他一些细节问题。

下面通过一个实例来详细的接收gdb的调试的具体步骤。

源程序——计算两个整数的平方和:


这段代码的功能是输入两个整数,求他们的平方的和,当两个数全为0的时候退出运算。

通过阅读代码可以发现,程序使用了一个while(1)的死循序,使其可以一直接受终端的输入,并运行运算后产生输出。运算部分调用了子函数calculate(),并通过参数的值传递方式将输入的两个整数传递给他。

编译并运行程序如下:


接下来使用gdb查看程序内部的情况!

调用gdb


使用断点

断点指出了gdb将要在改电触中断程序的执行,从而便于程序员单步跟踪调试代码。可通过使用break命令,指定一个特定的位置设置断点,当程序运行到断点处就暂停程序,然后把程序的控制权交给调试员和程序员。

用break命令设置断点的方法有多种,下面列出了一些:

break命令的用法
命令含义描述
break <function>在进入指定函数时停住。C++中可以使用class::function或function(type,,type)格式来指定函数名
break <linenum>在指定行号停住
break +offset在当前行号的前面的offset行停住。offset为自然数
break -offset在当前行号的后门的offset行停住。offset为自然数
break filename:linenum在源文件filename的linenum行停住
break filename:function在源文件filename的function函数的入口处停住
break*address在程序运行的内容地址出停住
break该命令没有参数时,表示在下一条指令处停住
break.....if<confdition>condition表示条件,在条件成立的时候停住。比如在循环中,可以设置break if i=100,表示当i=100的时候停住

一般来说,gdb下的命令(例如break,和下面建议提到的list、jump等)后面都可以跟不同的参数,是命令变得更加灵活。这些参数如下表所示:

gdb常用命令的参数
参数含义描述
<linenum>行号
<function>函数名
<+offset>当前行号的正偏移量
<-offset>当前行号的负偏移量
<filename:linenum>某个文件的某一行
<filename:function>某个文件的某个子函数
<*address>程序运行时的语句在内存中的地址

现在回到程序的调试过程中,我们可以在main函数处设置断点

然后使用run命令运行该程序


由此可见,程序在设置的断点处停住运行了,gdb会指出所遇到的断点,然后显示将要执行的下一行程序。

接下来可以使用单步调试命令step(简写为s)来跟踪调试程序,它一次只执行程序中的一行代码。命令如下:


查看运行时数据

在调试程序的过程中,往往需要查看程序中某些表达式或变量的值,以判断程序运行是否正确,使用gdb调试时,常用到的是print、display命令,以及查看内存、寄存器的信息等。

1、print命令

在调试程序时,当程序被停住是,可以使用print命令(简写为p),或是同义命令inspect来查看当前程序的运行数据。print命令的格式为:

print  <expr>
print /<f> <expr>

<expr>是表达式,是所调试程序的语言表达式(gdb可以调试多种编程语言);

<f>是输出的格式,比如,如果要把表达式按十六进制的格式输出,那么就是/x


2、输出格式

gdb的命令会根据变量的类型输出变量的值,但也可以自定义gdb的输出变量的格式:

gdb的数据显示格式
符号含义
x按十六进制格式显示变量
d按十进制格式显示变量
u按十六进制格式显示无符号整型
o按八进制格式显示变量
t按二进制格式显示变量
a按十六进制格式显示变量
c按字符格式显示变量
f按浮点数格式显示变量
  

3、自动显示命令display

可以设置一些自动显示的变量,当程序停住时,或是在单步跟踪时,这些变量会自动显示。相关gdb命令式display

格式如下:

display <expr>
display /<fmt> <expr>
display /<fmt> <addr>

4、查看内存

可以使用examine命令(简写是x)来查看内存地址中的值。x命令的语法如下所示:

x /<n/f/u> <addr>

对于该命令解释如下:

  • n\f\u是可选参数,可以独立使用,也可以联合使用
  • n是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容
  • f表示现实的格式,参加上面。如果地址所指的是字符串,那么格式可以是s;如果是指令地址,那么格式可以是i
  • u表示从当前地址往后请求的字节数,如果不指定的话,gdb默认是4个bytes.u参数可用下面的字符来代替:b表示单字节,h表示双字节,w表示四字节,g表示8字节。当指定了长度之后,gdb会从指定的内存地址开始,读写指定字节并把其当做一个值取出来。
  • <addr>表示一个内存地址。

例如:

x /4uh 0x48723

此处只是做一个示例而已哈!

5、gdb环境变量

可以在gdb的调试环境中自定义字节的变量。用来保存一些调试程序中的运行数据。

要定义一个gdb的变量很简单,只需要使用gdb的set命令。gdb的环境变量和UNIX一样,也是以$起始。例如:

set $foo=*object_ptr

使用环境变量时,gdb会在第一次使用时创建这个变量,而在以后的使用中,则直接对其赋值。环境变量没有类型,可以给环境变量定义任意的类型,包括结构体和数组。

show convenience

该命令用来查看当前所设置的所有的环境变量。

正是一个比较强大的功能,环境变量和程序变量的交互使用将会使得程序调试更为灵活便捷。

例如:

set $i=0
print bar[$i++]->contents

输入这样的命令之后,只需要按下回车键,重复执行上一条语句,环境变量就会自动累加,从而完成逐个输出的功能。

6、查看寄存器

在调试程序的工程中,有时候也需要查看某些寄存器中的值。寄存器中放置了程序运行时的数据,比如程序当前运行的指令地址IP,程序当前堆栈地址SP等。

可以使用info来查看这些内容:

查看寄存器常用命令
命令含义描述
info registers查看寄存器的情况(除了浮点寄存器)
info all-registers查看所有寄存器的情况(包括浮点寄存器)
info register<regname...>查看所指定的寄存器的情况,regname表示寄存器名,多个寄存器之间用逗号隔开
同样可以使用print命令来访问寄存器的情况,只需要在寄存器名字前加上一个$即可。例如:
print $ip

查看源程序

1、显示源代码

gdb可以打印出所调试程序的源代码,当然,在程序编译时一定要加上“-g”参数,吧源程序信息编译到执行文件中,不然就看不到源程序了。在程序停下来之后,gdb会报告程序停在了程序的第几行。可以使用list来查看源代码:


2、源代码内存

可以使用info line命令来查看源代码在内存中的地址。和大多数gdb命令相同,info line后面也可以跟“行号”、“函数名”、“文件名:函数名”的参数形式,这个命令会显示出所指定的源代码在运行时的内存的地址。

下面来查看一下子函数名calculate()在内存中的地址


改变程序的执行

1、修改变量值

2、跳转执行

jump <linespec>

jump <address>

3、产生信号量

signal 《singal》

4、强制返回

return

return  <expression>

5、强制调用函数

call  <expression>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FLy_鹏程万里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值