GDB调试(1)


(部分摘抄于http://www.cnblogs.com/hankers/archive/2012/12/07/2806836.html)


一.gdb常用命令:

命令

描述

backtrace(或bt

查看各级函数调用及参数

finish

连续运行到当前函数返回为止,然后停下来等待命令

frame(或f) 帧编号

选择栈帧

info(或i) locals

查看当前栈帧局部变量的值

list(或l

列出源代码,接着上次的位置往下列,每次列10

list 行号

列出从第几行开始的源代码

list 函数名

列出某个函数的源代码

next(或n

执行下一行语句

print(或p

打印表达式的值,通过表达式可以修改变量的值或者调用函数

quit(或q

退出gdb调试环境

set var

修改变量的值

start

开始执行程序,停在main函数第一行语句前面等待命令

step(或s

执行下一行语句,如果有函数调用则进入到函数中


1.cpp文件的源码如下:

#include <stdio.h>

int add_range(int low, int high)
{
	int i, sum;
	for (i = low; i <= high; i++)
		sum = sum + i;
	return sum;
}

int main(void)
{
	int result[100];
	result[0] = add_range(1, 10);
	result[1] = add_range(1, 100);
	printf("result[0]=%d\nresult[1]=%d\n", result[0], result[1]);
	return 0;
}




在编译时要加上-g选项,生成的可执行文件才能用gdb进行源码级调试:







-g选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证gdb能找到源文件。gdb提供一个类似Shell的命令行环境,上面的(gdb)就是提示符,在这个提示符下输入help可以查看命令的类别:



list 1列出第一行开始的10行代码 , 显示后,回车则是执行上一次输入的命令。



输入quit退出gdb



源代码改名或移到别处再用gdb调试,这样将列不出源代码(调试时需要用到源文件)。



start命令开始执行程序



(gdb) start
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Temporary breakpoint 3 at 0x80484aa: file 1.cpp, line 15.
Starting program: /share/test/a.out 

Temporary breakpoint 3, main () at 1.cpp:15
15              result[0] = add_range(1, 10);


gdb停在main函数中变量定义之后的第一条语句处等待我们发命令,gdb列出的这条语句是即将执行的下一条语句。我们可以用next命令控制这些语句一条一条地执行:

(gdb) next
16              result[1] = add_range(1, 100);

陆续按下回车键,直到程序运行结束。

(gdb) 
17              printf("result[0]=%d\nresult[1]=%d\n", result[0], result[1]);
(gdb) 
result[0]=1275219
result[1]=1280269
18              return 0;
(gdb) 
19      }
(gdb) 
0x00154cc6 in __libc_start_main () from /lib/libc.so.6
(gdb) 
Single stepping until exit from function __libc_start_main, 
which has no line number information.


Program exited normally.


n命令依次执行两行赋值语句和一行打印语句,在执行打印语句时结果立刻打出来了,然后停在return语句之前等待我们发命令。虽然我们完全控制了程序的执行,但仍然看不出哪里错了,因为错误不在main函数中而在add_range函数中,现在用start命令重新来过,这次用step命令(简写为s)钻进add_range函数中去跟踪执行:


(gdb) start
Temporary breakpoint 4 at 0x80484aa: file 1.cpp, line 15.
Starting program: /share/test/a.out 


Temporary breakpoint 4, main () at 1.cpp:15
15              result[0] = add_range(1, 10);
(gdb) step
add_range (low=1, high=10) at 1.cpp:7
7               for (i = low; i <= high; i++)


这次停在了add_range函数中变量定义之后的第一条语句处。在函数中有几种查看状态的办法,backtrace命令(简写为bt)可以查看函数调用的栈帧:


(gdb) backtrace
#0  add_range (low=1, high=10) at 1.cpp:7
#1  0x080484be in main () at 1.cpp:15
(gdb) 

可见当前的add_range函数是被main函数调用的,main传进来的参数是low=1, high=10main函数的栈帧编号为1add_range的栈帧编号为0。现在可以用info命令(简写为i)查看add_range函数局部变量的值:


(gdb) info locals
i = 1148052
sum = 1275164
(gdb) 


如果想查看main函数当前局部变量的值也可以做到,先用frame命令(简写为f)选择1号栈帧然后再查看局部变量:


(gdb) frame 1
#1  0x080484be in main () at 1.cpp:15
15              result[0] = add_range(1, 10);
(gdb) info locals
result = {4, 1147604, 1147700, 1318352, 1256356, -1073744508, 1331888, 13, 22683471, 1185218, 1378450, 134513341, -1207959784, 
  -1208025086, 1210029, 134513280, -1207960704, 1273796, 1317832, 4, -1073744308, 1187172, 79484788, 1, 1273796, -1073744208, 
  -1207962224, -1073744252, 1187674, -1073744268, 79484788, -1073744280, 1276500, 0, -1208020624, 1, 4, 1, -1207962664, 1318352, 
  1256356, -1073744364, 1353520, 14, 129100401, -1207959828, -163754450, 0, 6, 1276152, 0, 0, 1, 2198, -1207959784, -1207960648, 
  134513312, 1355600, 134513120, 1, 1273796, -1073744064, 1276592, -1073744108, 1187674, -1073744124, 134513120, -1073744136, 
  1276500, 0, -1207959784, 1, 0, 1, 1276152, 79542637, 1, -1073744192, 1206213, -1207962224, -1208020624, 1, 1, 0, -1073744064, 
  134518756, -1073744200, 134513516, 1331888, 134518756, -1073744152, 134513961, 80389456, 134513312, 0, 2908148, 134513936, 
  134513600, 134513947, 2908148}


注意到result数组中有很多元素具有杂乱无章的值,我们知道未经初始化的局部变量具有不确定的值。到目前为止一切正常。用sn往下走几步,然后用print命令(简写为p)打印出变量sum的值:


(gdb) p sum
$1 = 1275170
(gdb) print sum
$2 = 1275170
(gdb) 

第一次循环i1,第二次循环i2,加起来是3,没错。这里的$1表示gdb保存着这些中间结果,$后面的编号会自动增长,在命令中可以用$1$2$3等编号代替相应的值。由于我们本来就知道第一次调用的结果是正确的,再往下跟也没意义了,可以用finish命令让程序一直运行到从当前函数返回为止。


finish命令让程序一直运行到从当前函数返回为止:


(gdb) finish
Run till exit from #0  add_range (low=1, high=10) at 1.cpp:7
0x080484be in main () at 1.cpp:15
15              result[0] = add_range(1, 10);
Value returned is $3 = 1275219


返回值是1275219,当前正准备执行赋值操作,用s命令赋值,然后查看result数组:

Value returned is $3 = 1275219
(gdb) 
(gdb) step
16              result[1] = add_range(1, 100);
(gdb) print result
$4 = {1275219, 1147604, 1147700, 1318352, 1256356, -1073744508, 1331888, 13, 22683471, 


可以在gdb中马上把sum的初值改为0继续运行,看看这一处改了之后还有没有别的Bug


(gdb) step
add_range (low=1, high=100) at 1.cpp:7
7               for (i = low; i <= high; i++)
(gdb) backtrace
#0  add_range (low=1, high=100) at 1.cpp:7
#1  0x080484d6 in main () at 1.cpp:16
(gdb) info locals
i = 11
sum = 1275219
(gdb) set var sum = 0
(gdb) finish
Run till exit from #0  add_range (low=1, high=100) at 1.cpp:7
0x080484d6 in main () at 1.cpp:16
16              result[1] = add_range(1, 100);
Value returned is $5 = 5050
(gdb) 


这样结果就对了。修改变量的值除了用set命令之外也可以用print命令,因为print命令后面跟的是表达式,而我们知道赋值和函数调用也都是表达式,所以也可以用print命令修改变量的值或者调用函数:



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值