最近要调试PHP源代码,使用工具GDB.
1. GDB简介
GDB是Linux/Unix下一个GNU调试程序,是用来调试C与C++程序的强力调试器。能够让用户在程序运行时观察程序的内部结构和内存的使用情况。
作用:
1)按照自定义的方式启动运行需要调试的程序。
2)可以使用指定位置和条件表达式的方式来设置断点。
3)程序暂停时的值的监视。
4)动态改变程序的执行环境。
2. 基本操作命令:
这里只介绍常用命令的简单用法,如需读者想更加深入的了解,还请读者参照gdb手册。也可以使用--help查看。
基本命令列表:
命令
|
解释
|
简写
|
file
|
装入想要调试的可执行文件
|
无
|
list
|
列出产生执行文件源代码的一部分
|
l
|
next
|
执行一行源代码但不进入函数内部
|
n
|
step
|
执行一行源代码而且进入函数内部
|
s
|
run
|
执行当前被调试的程序
|
r
|
continue
|
继续执行程序
|
c
|
quit
|
终止GDB
|
q
|
print
|
输出当前指定变量的值
|
p
|
break
|
在代码里设置断点
|
b
|
info break
|
查看设置断点的信息
|
i b
|
delete
|
删除设置的断点
|
d
|
watch
|
监视一个变量的值,一旦值有变化,程序停住
|
wa
|
help
|
GDB中的帮助命令
|
h
|
3,编程实例
创建c文件:test.c
- #include<stdio.h>
- #include<string.h>
- void prints(int i)
- {
- printf("hello %d\n", i);
- }
- void main ()
- {
- int i =0;
- for(i=1;i<6;i++){
- prints(i);
- }
- }
#include<stdio.h>
#include<string.h>
void prints(int i)
{
printf("hello %d\n", i);
}
void main ()
{
int i =0;
for(i=1;i<6;i++){
prints(i);
}
}
编译,其目标文件为test
gcc -o test test.c
这个程序执行
- ./test
./test
时显示如下结果:
hello 1
hello 2
hello 3
hello 4
hello 5
4 gdb调试程序
如果需要使用gdb调试
在编译test.c的时候,并把调试选项打开:
- gcc -o -ggdb test test.c
gcc -o -ggdb test test.c
(调试选项资料:
调试选项(DEBUGGING OPTION)
GNU CC拥有许多特别选项,既可以调试用户的程序,也可以对GCC排错:-g
以操作系统的本地格式(stabs, COFF, XCOFF,或DWARF).产生调试信息. GDB能够使用这些调试信息.
在大多数使用stabs格式的系统上, `-g'选项启动只有GDB才使用的额外调试信息;这些信息使GDB 调试效果更好,但是有可能导致其他调试器崩溃,或拒绝读入程序.如果你确定要控制是否生成额外的信息, 使用`-gstabs+', `-gstabs', `-gxcoff+', `-gxcoff', `-gdwarf+',或`-gdwarf' (见下文).
和大多数C编译器不同, GNU CC允许结合使用`-g'和`-O'选项.优化的代码偶尔制造 一些惊异的结果:某些声明过的变量根本不存在;控制流程直接跑到没有预料到的地方;某些语句因为计算结果是常量或已经确定而 没有执行;某些语句在其他地方执行,因为他们被移到循环外面了.
然而它证明了调试优化的输出是可能的.对可能含有错误的程序使用优化器是合理的.
如果GNU CC支持输出多种调试信息,下面的选项则非常有用.
-ggdb
以本地格式(如果支持)输出调试信息,尽可能包括GDB扩展.
)
1)启动
2)载入文件:file命令
file test
结果:
- gcc -o -ggdb test test.c
gcc -o -ggdb test test.c
也可以通过直接启动的方式载入文件:
- root@ubuntu:/opt/c++# gdb test
- GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
- Copyright (C) 2010 Free Software Foundation, Inc.
- License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
- This is free software: you are free to change and redistribute it.
- There is NO WARRANTY, to the extent permitted by law. Type "show copying"
- and "show warranty" for details.
- This GDB was configured as "i686-linux-gnu".
- For bug reporting instructions, please see:
- <http://www.gnu.org/software/gdb/bugs/>...
- Reading symbols from /opt/c++/test...done.
root@ubuntu:/opt/c++# gdb test
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /opt/c++/test...done.
3)list命令
也可以过回车查看源代码
- (gdb) list
- 1 #include<stdio.h>
- 2 #include<string.h>
- 3 void prints(int i)
- 4 {
- 5 printf("hello %d\n", i);
- 6 }
- 7 void main ()
- 8
- 9 {
- 10 int i =0;
- (gdb)
(gdb) list
1 #include<stdio.h>
2 #include<string.h>
3 void prints(int i)
4 {
5 printf("hello %d\n", i);
6 }
7 void main ()
8
9 {
10 int i =0;
(gdb)
一次只列10行,如果要从11行开始继续列源代码可以输入
(gdb) list
也可以什么都不输直接敲回车,gdb提供了一个很方便的功能,在提示符下直接敲回车表示用适当的参数重复上一条命令。
回车:
- (gdb) list
- 1 #include<stdio.h>
- 2 #include<string.h>
- 3 void prints(int i)
- 4 {
- 5 printf("hello %d\n", i);
- 6 }
- 7 void main ()
- 8
- 9 {
- 10 int i =0;
- (gdb)
- 11 for(i=1;i<6;i++){
- 12 prints(i);
- 13 }
- 14
- 15 }
- 16
- (gdb)
(gdb) list
1 #include<stdio.h>
2 #include<string.h>
3 void prints(int i)
4 {
5 printf("hello %d\n", i);
6 }
7 void main ()
8
9 {
10 int i =0;
(gdb)
11 for(i=1;i<6;i++){
12 prints(i);
13 }
14
15 }
16
(gdb)
4)单步逐条执行 next
首先用start命令开始执行程序:
- (gdb) start
- Temporary breakpoint 1 at 0x80483e9: file test1.c, line 10.
- Starting program: /opt/c++/test1
- Temporary breakpoint 1, main () at test1.c:10
- 10 int i =0;
- (gdb)
(gdb) start
Temporary breakpoint 1 at 0x80483e9: file test1.c, line 10.
Starting program: /opt/c++/test1
Temporary breakpoint 1, main () at test1.c:10
10 int i =0;
(gdb)
这表示停在main
函数中变量定义之后的第一条语句处等待我们发命令,gdb列出这条语句表示它还没执行,并且马上要执行我们可以用next命令(简写为n)控制这些语句一条一条地执行:
- (gdb) next
- 11 for(i=1;i<6;i++){
- (gdb) (直接回车)
- 12 prints(i);
- (gdb)
- hello 1
- 11 for(i=1;i<6;i++){
- (gdb)
- 12 prints(i);
- (gdb)
- hello 2
- 11 for(i=1;i<6;i++){
- (gdb)
- 12 prints(i);
- (gdb)
- hello 3
- 11 for(i=1;i<6;i++){
- (gdb)
- 12 prints(i);
- (gdb)
- hello 4
- 11 for(i=1;i<6;i++){
- (gdb)
- 12 prints(i);
- (gdb)
- hello 5
- 11 for(i=1;i<6;i++){
- (gdb)
- 15 }
- (gdb)
(gdb) next
11 for(i=1;i<6;i++){
(gdb) (直接回车)
12 prints(i);
(gdb)
hello 1
11 for(i=1;i<6;i++){
(gdb)
12 prints(i);
(gdb)
hello 2
11 for(i=1;i<6;i++){
(gdb)
12 prints(i);
(gdb)
hello 3
11 for(i=1;i<6;i++){
(gdb)
12 prints(i);
(gdb)
hello 4
11 for(i=1;i<6;i++){
(gdb)
12 prints(i);
(gdb)
hello 5
11 for(i=1;i<6;i++){
(gdb)
15 }
(gdb)
5)逐条执行并进入函数:
用start命令重新来过,step命令(简写为s)进入 函数中去执行:
- (gdb) start
- Temporary breakpoint 2 at 0x80483e9: file test1.c, line 10.
- Starting program: /opt/c++/test1
- Temporary breakpoint 2, main () at test1.c:10
- 10 int i =0;
- (gdb) next
- 11 for(i=1;i<6;i++){
- (gdb) next
- 12 prints(i);
- (gdb) step
- prints (i=1) at test1.c:5
- 5 printf("hello %d\n", i);
- (gdb)
(gdb) start
Temporary breakpoint 2 at 0x80483e9: file test1.c, line 10.
Starting program: /opt/c++/test1
Temporary breakpoint 2, main () at test1.c:10
10 int i =0;
(gdb) next
11 for(i=1;i<6;i++){
(gdb) next
12 prints(i);
(gdb) step
prints (i=1) at test1.c:5
5 printf("hello %d\n", i);
(gdb)
进入到了函数
prints
在函数中有几种查看状态的办法,backtrace命令(简写为bt)可以查看函数调用的栈帧:
- (gdb) bt
- #0 prints (i=1) at test1.c:5
- #1 0x08048407 in main () at test1.c:12
- (gdb)
(gdb) bt
#0 prints (i=1) at test1.c:5
#1 0x08048407 in main () at test1.c:12
(gdb)
main传进来的参数是i=1。main函数的栈帧编号为1,prints的栈帧编号为0。
6)在可以用info命令(简写为i)查看局部变量
- i locals
i locals
如果想查看main函数当前局部变量的值也可以做到,先用frame命令(简写为f)选择1号栈帧然后再查看局部变量:
- (gdb) f 1
- #1 0x08048407 in main () at test1.c:12
- 12 prints(i);
- (gdb)
(gdb) f 1
#1 0x08048407 in main () at test1.c:12
12 prints(i);
(gdb)
7)输出当前指定变量的值 print
- (gdb) p i
- $1 = 1
- (gdb)