前言
GDB是一个由GNU开源组织发布的、UNIX/Linux操作系统下的、基于命令行的、功能强大的程序调试工具。当程序发生coredump,通过GDB可以从core文件中复现场景,定位问题。
GDB调试常用命令
- file <文件名>
加载被调试的可执行程序文件。因为一般都在被调试程序所在目录下执行GDB,因而文本名不需要带路径。
(gdb) file gdb-sample
- r
Run的简写,运行被调试的程序。如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处。
(gdb) r
- c
Continue的简写,继续执行被调试程序,直至下一个断点或程序结束.
(gdb) c
- b 设置断点
- b <行号>
- b <函数名称>
- b *<函数名称>
- b *<代码地址>
b: Breakpoint的简写,设置断点。两可以使用“行号”“函数名称”“执行地址”等方式指定断点位置。
其中在函数名称前面加“*”符号表示将断点设置在“由编译器生成的prolog代码处”。如果不了解汇编,可以不予理会此用法。
1 | (gdb) b 8 |
d
Delete breakpoint的简写,删除指定编号的某个断点,或删除所有断点。断点编号从1开始递增。
s
s 相当于其它调试器中的“Step Into (单步跟踪进入)。 执行一行源程序代码,如果此行代码中有函数调用,则进入该函数;
n
执行一行源程序代码,此行代码中的函数调用也一并执行。相当于其它调试器中的“Step Over (单步跟踪)”。
这两个命令必须在有源代码调试信息的情况下才可以使用(GCC编译时使用“-g”参数)。
si, ni si命令类似于s命令,ni命令类似于n命令。所不同的是,这两个命令(si/ni)所针对的是汇编指令,而s/n针对的是源代码。
1
2 (gdb) si
(gdb) ni
- p <变量名称>
Print的简写,显示指定变量(临时变量或全局变量)的值。
1 | (gdb) p i |
- display …
display,设置程序中断后欲显示的数据及其格式。
例如,如果希望每次程序中断后可以看到即将被执行的下一条汇编指令,可以使用命令"display /i $pc"
其中 $pc 代表当前汇编指令,/i 表示以十六进行显示。当需要关心汇编代码时,此命令相当有用。 undisplay <编号>
undispaly,取消先前的display设置,编号从1开始递增。
1
2(gdb) display /i $pc
(gdb) undisplay 1i
Info的简写,用于显示各类信息,详情请查阅“help i”。
(gdb) i r
q
Quit的简写,退出GDB调试环境。 (gdb) q
help [命令名称]
GDB帮助命令,提供对GDB名种命令的解释说明。
如果指定了“命令名称”参数,则显示该命令的详细说明;如果没有指定参数,则分类显示所有GDB命令,供用户进一步浏览和查询。
(gdb) help display
实战
GDB调试php
我们在使用GDB调试的时候经常会查看某个变量的信息,如果你的php是开启了编译器优化的,那么是看不到变量信息的,显示<value optimized out>
你需要修改MakeFile禁止编译器优化
####修改方法:
vim MakeFile
88 CFLAGS_CLEAN = -I/usr/include -g -O0 -fvisibility=hidden -DZEND_SIGNALS $(PROF_FLAGS)// 将-O0 修改为-O2
保存修改文件执行make clean && make && make install 来重新编译安装PHP
准备代码test.php
1 |
|
开始进行GDB调试
gdb php
1 | gdb php |
在main函数处设置断点
1 | (gdb) b mainBreakpoint 1 at 0xa4e894: file /home/php7internal/soft/php-7.1.0/sapi/cli/php_cli.c, line 1195. // 断点位置 |
运行test.php
1 | (gdb) r test.php |
从上面的输出我们看到代码在main函数处停止下来,然后使用n命令执行下一步
1 | (gdb) n |
使用p查看变量信息
1 | (gdb) p php_optind |
使用c命令执行到下一个断点,如果没有其余断点则执行到程序结束
1 | (gdb) c |
DBD调试C程序
准备代码文件test.c
1 |
|
gcc编译
使用gdb调试,要使用-g参数保留代码的文字信息,便于调试 输出到test可执行文件
- 创建符号表,符号表包含了程序中使用的变量名称的列表。
- 关闭所有的优化机制,以便程序执行过程中严格按照原来的C代码进行。
gcc -g test.c -o test
gdb 调试
1 | gdb test |
然后就可以愉快的调试啦
扩展阅读
gcc -o 优化等级
-O设置一共有五种:-O0、-O1、-O2、-O3和-Os。
除了-O0以外,每一个-O设置都会多启用几个选项
各个优化等级:
- -O0:这个等级(字母“O”后面跟个零)关闭所有优化选项,也是CFLAGS或CXXFLAGS中没有设置-O等级时的默认等级。这样就不会优化代码,这通常不是我们想要的。
- -O1:这是最基本的优化等级。编译器会在不花费太多编译时间的同时试图生成更快更小的代码。这些优化是非常基础的,但一般这些任务肯定能顺利完成。
- -O2:-O1的进阶。这是推荐的优化等级,除非你有特殊的需求。-O2会比-O1启用多一些标记。设置了-O2后,编译器会试图提高代码性能而不会增大体积和大量占用的编译时间。
- -O3:这是最高最危险的优化等级。用这个选项会延长编译代码的时间,并且在使用gcc4.x的系统里不应全局启用。自从3.x版本以来gcc的行为已经有了极大地改变。在3.x,-O3生成的代码也只是比-O2快一点点而已,而gcc4.x中还未必更快。用-O3来编译所有的软件包将产生更大体积更耗内存的二进制文件,大大增加编译失败的机会或不可预知的程序行为(包括错误)。这样做将得不偿失,记住过犹不及。在gcc 4.x.中使用-O3是不推荐的。
- -Os:这个等级用来优化代码尺寸。其中启用了-O2中不会增加磁盘空间占用的代码生成选项。这对于磁盘空间极其紧张或者CPU缓存较小的机器非常有用。但也可能产生些许问题,因此软件树中的大部分ebuild都过滤掉这个等级的优化。使用-Os是不推荐的。