gdb调试程序1


  • gdb 基本命令1
命令描述
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)执行下一行语句,如果有函数调用则进入到函数中

运行结果错误的代码:
程序文件(main.c)

  1 #include<stdio.h>
  2 
  3 int add_range(int low,int high)
  4 {
  5     int i,sum;
  6     for (i = low; i <= high; i++)
  7         sum = sum + i;
  8     return sum;
  9 }
 10 
 11 int main(void)
 12 {
 13     int result[1000];
 14     result[0] = add_range(1,10);
 15     result[1] = add_range(1,100);
 16     printf("result[0]=%d\nresult[1]=%d\n",result[0],result[1]);
 17     return 0;
 18 }

以上代码打印结果为:

result[0]=55
result[1]=5105

演示调试代码的过程

第一个结果是正确的,第二个结果是错误的,下面我们通过调试来找出错误的原因。


首先将代码编译成带调试信息的可执行程序,再用gdb工具进行调试.

#gcc -g main.c -o main
#gdb main

注意: -g 是使可执行程序包含调试信息,确切的说,就是在可执行文件中加入源代码信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行程序中,所以调试时必须保证gdb能找到源文件。

  • list命令
//list 命令从第一行开始列出源代码(只列10行):
(gdb) list 1
1   #include<stdio.h>
2   
3   int add_range(int low,int high)
4   {
5       int i,sum;
6       for (i = low; i <= high; i++)
7           sum = sum + i;
8       return sum;
9   }
10  
//上面一次列出10行代码,如果想要看之后的代码,直接使用list命令
(gdb) list
11  int main(void)
12  {
13      int result[1000];
14      result[0] = add_range(1,10);
15      result[1] = add_range(1,100);
16      printf("result[0]=%d\nresult[1]=%d\n",result[0],result[1]);
17      return 0;
18  }
//list可以用简写为l,例如要列出一个函数的源代码:
(gdb) l add_range 
1   #include<stdio.h>
2   
3   int add_range(int low,int high)
4   {
5       int i,sum;
6       for (i = low; i <= high; i++)
7           sum = sum + i;
8       return sum;
9   }
10  
  • 退出gdb
(gdb) quit

如果调试过程中,gdb不能找到源代码文件,则无法执行调试

//将源文件改名
#mv main.c mian.c
#gdb main
...
...
(gdb) list
1   main.c: No such file or directory.

开始调试

  • start 命令开始执行调试
#gdb main
...
...
(gdb) start
Temporary breakpoint 1 at 0x4005ca: file main.c, line 12.
Starting program: /home/liyongfeng/code/gdb_Demo/main 

Temporary breakpoint 1, main () at main.c:12
12  {

此时gdb停在main函数中变量定义之后的第一条语句处等待我们发命令。

  • 使用 next 命令(简写为 n )一句一句的执行
//执行第一条语句,接着执行下一条就直接按回车
(gdb) n
14      result[0] = add_range(1,10);
(gdb)(直接回车)
(gdb) 
15      result[1] = add_range(1,100);
(gdb) 
16      printf("result[0]=%d\nresult[1]=%d\n",result[0],result[1]);
(gdb) 
result[0]=55
result[1]=5105
17      return 0;

  • step 命令 进入函数实体

以上的方式是一句一句执行代码,遇到函数并没有跳进函数内部进行调试。
下面用 step 命令(简写为s)跳到add_range函数中跟踪执行:

(gdb) start
...
...
//跳到调用函数的位置
(gdb) step
14      result[0] = add_range(1,10);

//跳到函数实体
(gdb) s
add_range (low=1, high=10) at main.c:6
6       for (i = low; i <= high; i++)

接着按s或回车就一步一步执行函数内的语句


  • backtrace 命令

进入函数实体后,可以使用backtrace命令(简写为 bt)来查看函数调用的栈帧:

(gdb) backtrace
#0  add_range (low=1, high=10) at main.c:7
#1  0x00000000004005e8 in main () at main.c:14

上面的信息解析:

add_range函数是被main函数调用的,main传进来的参数是low=1,high=10.main函数的栈帧编号为1,add_range的栈帧编号为0.

  • info命令(简写为i) 查看add_range函数的当前状态局部变量的值
(gdb) i locals 
i = 0
sum = 0

  • frame 命令(简写为f) 选择帧栈

如果想查看main函数当前状态的局部变量的值,可以用frame命令先选择1号栈,然后再查看局部变量:

(gdb) f 1
#1  0x00000000004005e8 in main () at main.c:14
14      result[0] = add_range(1,10);
(gdb) i locals 
result = {0 <repeats 278 times>, 3, 0, -10624, 32767, -134253376, 32767, 
  -10392, 32767, 2, 0, 2049, 0, -136453787, 32767, 0, 0, 1835008, 0, 1831440, 
  0, 1831440, 0, 0, 0, 5, 0, 3928064, 0, 3952640, 0, 3950368, 0, 3967488, 0, 
  1830912, 0, 3, 0 <repeats 71 times>, 32, 0, 1, 0, -136434488, 32767, 
  -134253408, 32767, 32, 0, 47, 1, 10, 0, 0, 0, -134225560, 32767, -10624, 
  32767, -136435385, 32767, 2147479968, 3, -10624, 32767, -134253376, 32767, 
  -136454824, 32767, -1, -1, -134225760, 3, -136484352, 32767, -136411148, 
  32767, -11392, 32767, -140359505, 32767, 0, 0, -136447843, 32767, -10464, 1, 
  922964, 0, 6, 0, -11392, 32767, 86379, 3, -134225600, 32767, -134253408, 
  32767, 0, 0, 2049, 0, 922964, 0, 1, 0, 33261, 0, 0, 0, 0, 0, 1864888, 0, 
  4096, 0, 3648, 0, 1466039668, 0, 43971537, 0, 1460672206, 0, 0, 0, 
  1465452945, 0, 671257261, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4195121, 0, -134225560, 
  32767, 0, 0, -134229952, 32767, -10464, 32767, 0, 0, -136447401, 32767, 1, 
  0, 0, 0, -10472, 32767, 0, 0, 0, 1, -134253408, 32767, 0, 0, 10, 0, -10464, 
  32767, -10480, 32767, -134225560, 32767, 0, 0, 0, 0, 0, 0, 0...}

这里可以看到result数组中很多元素具有杂乱无章的值,这是因为数组并没有进行初始化。


  • print 命令(简写p) 打印变量值

到这里,用s或n命令可以继续往下执行代码,接着就可以用print命令打印出变量sum的值:

(gdb) n
7           sum = sum + i;
(gdb) 
6       for (i = low; i <= high; i++)
(gdb) 
7           sum = sum + i;
(gdb) 
6       for (i = low; i <= high; i++)
(gdb) p sum
$1 = 3

第一次循环i是1,第二次循环i是2,加起来是3。

  • finish 命令让程序一直运行到从当前函数返回为止
(gdb) finish
Run till exit from #0  add_range (low=1, high=10) at main.c:7
0x00000000004005e8 in main () at main.c:14
14      result[0] = add_range(1,10);
Value returned is $1 = 55
//查看result数组的值
(gdb) s
15      result[1] = add_range(1,100);
(gdb) p result
$2 = {55, 0 <repeats 277 times>, 3, 0, -10624, 32767, -134253376, 32767, 
  -10392, 32767, 2, 0, 2049, 0, -136453787, 32767, 0, 0, 1835008, 0, 1831440, 
...}

这里可以看到到第一个值被赋为55。下面用s命令进入第二次add_range调用。


用s命令进入第二次add_range调用

(gdb) s
add_range (low=1, high=100) at main.c:6
6       for (i = low; i <= high; i++)
(gdb) bt
#0  add_range (low=1, high=100) at main.c:6
#1  0x00000000004005fd in main () at main.c:15
(gdb) i locals 
i = 11
sum = 55

这里可以看到,第二次调用add_range函数时,由于局部变量i和sum没有初始化,所以具有不确定的值,又由于两次调用是挨着的,i和sum正好取了上次调用时的值。在这里i没有初始化没有关系,因为for循环会给初始值,但是sum没有初始化的话,就会进行累加,使结果不正确。

//将当前的sum变量设置为0,继续运行,可以看到结果正确。
(gdb) set var sum = 0
(gdb) finish
Run till exit from #0  add_range (low=1, high=100) at main.c:6
0x00000000004005fd in main () at main.c:15
15      result[1] = add_range(1,100);
Value returned is $3 = 5050
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值