- 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