java环境单步跟踪,gdb使用指南:单步执行和跟踪函数调用

2

3int add_range(int low, int high)

4{

5int i, sum;

6for (i = low; i <= high; i++)

7sum = sum + i;

8return sum;

9}

10

现在退出gdb的环境:(gdb) quit

我们做一个实验,把源代码改名或移到别处再用gdb调试,这样就列不出源代码了:$ mv main.c mian.c

$ gdb main

...

(gdb) l

5main.c: No such file or directory.

in main.c

可见gcc的-g选项并不是把源代码嵌入到可执行文件中的,在调试时也需要源文件。现在把源代码恢复原样,我们继续调试。首先用start命令开始执行程序:$ gdb main

...

(gdb) start

Breakpoint 1 at 0x80483ad: file main.c, line 14.

Starting program: /home/akaedu/main

main () at main.c:14

14result[0] = add_range(1, 10);

(gdb)

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

15result[1] = add_range(1, 100);

(gdb) (直接回车)

16printf("result[0]=%d\nresult[1]=%d\n", result[0], result[1]);

(gdb) (直接回车)

result[0]=55

result[1]=5105

17return 0;

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

The program being debugged has been started already.

Start it from the beginning? (y or n) y

Breakpoint 2 at 0x80483ad: file main.c, line 14.

Starting program: /home/akaedu/main

main () at main.c:14

14result[0] = add_range(1, 10);

(gdb) s

add_range (low=1, high=10) at main.c:6

6for (i = low; i <= high; i++)

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

#0 add_range (low=1, high=10) at main.c:6

#1 0x080483c1 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

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

#1 0x080483c1 in main () at main.c:14

14result[0] = add_range(1, 10);

(gdb) i locals

result = {0, 0, 0, 0, 0, 0, 134513196, 225011984, -1208685768, -1081160480,

...

-1208623680}

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

7sum = sum + i;

(gdb) (直接回车)

6for (i = low; i <= high; i++)

(gdb) (直接回车)

7sum = sum + i;

(gdb) (直接回车)

6for (i = low; i <= high; i++)

(gdb) p sum

$1 = 3

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

Run till exit from #0 add_range (low=1, high=10) at main.c:6

0x080483c1 in main () at main.c:14

14result[0] = add_range(1, 10);

Value returned is $2 = 55

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

15result[1] = add_range(1, 100);

(gdb) p result

$3 = {55, 0, 0, 0, 0, 0, 134513196, 225011984, -1208685768, -1081160480,

...

-1208623680}

第一个值55确实赋给了result数组的第0个元素。下面用s命令进入第二次add_range调用,进入之后首先查看参数和局部变量:(gdb) s

add_range (low=1, high=100) at main.c:6

6for (i = low; i <= high; i++)

(gdb) bt

#0 add_range (low=1, high=100) at main.c:6

#1 0x080483db in main () at main.c:15

(gdb) i locals

i = 11

sum = 55

由于局部变量i和sum没初始化,所以具有不确定的值,又由于两次调用是挨着的,i和sum正好取了上次调用时的值,原来这跟是一样的道理,只不过我这次举的例子设法让局部变量sum在第一次调用时初值为0了。i的初值不确定倒没关系,在for循环中首先会把i赋值为low的,但sum如果初值不是0,累加得到的结果就错了。好了,我们已经找到错误原因,可以退出gdb修改源代码了。如果我们不想浪费这次调试机会,可以在gdb中马上把sum的初值改为0继续运行,看看这一处改了之后还有没有别的Bug:(gdb) set var sum=0

(gdb) finish

Run till exit from #0 add_range (low=1, high=100) at main.c:6

0x080483db in main () at main.c:15

15result[1] = add_range(1, 100);

Value returned is $4 = 5050

(gdb) n

16printf("result[0]=%d\nresult[1]=%d\n", result[0], result[1]);

(gdb) (直接回车)

result[0]=55

result[1]=5050

17return 0;

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

$5 = 33

(gdb) p printf("result[2]=%d\n", result[2])

result[2]=33

$6 = 13

我们讲过,printf的返回值表示实际打印的字符数,所以$6的结果是13。总结一下本节用到的gdb命令:

表 10.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)执行下一行语句,如果有函数调用则进入到函数中

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值