最近在做游戏的项目,项目中使用的服务器程序版本是release版本的,最近出现服务器宕机的情况,但是core文件通过gdb查看了一下宕机堆栈结果发现堆栈被破坏,可能的问题就是对指针和数组使用的不规范导致的。然后打算继续通过gdb来调试一下core文件查看一下相关的变量,但是结果令人失望,但是发现debug版本的是可以查看的。比较一下debug和release的区别。
release的编译选项中不包含有调试信息,并且做了代码优化,编译选项中为 -O3。
debug版本发现debug版本是可以查到符号信息的,去看了下debug版本的编译选项 -g3 。
此时就想如何能让版本即拥有符号信息又效率得到保证呢,查看资料发现linux下有个指令是objcopy可以将可执行文件的符号表剥离处理。
下面用一些小例子来演示一下分离过程及分离后效果:
main.cpp文件
#include
using std::cout;
using std::endl;
void my_print();
int main(int argc, char *argv[])
{
my_print();
cout<<"hello!"<
然后我们来编译一下这个内容,
一、[root@localhost testm]# g++ -O3 main.cpp -o mainO3
插曲:g++编译选项的 -O3:-O0 -O1 -O2 -O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
这样编译后的可执行文件是不含有符号表的就是理论我们的release版本,我门使用readelf -S命令查看段
Readelf -S mainO3
里面有有debug调试信息,那么这样的情况下我们能否使用objcopy来产生符号表呢,产生后又有什么效果呢我们一起见证一下:
[root@localhost testm]# objcopy --only-keep-debug mainO3 mainO3.symbol //拷贝出一个符号表文件
[root@localhost testm]# objcopy --strip-debug mainO3 mainO3.bin //拷贝出一个执行文件
我门通过上面的命令生成文件如下
从大小来看我们可以了解到符号表的大小执行文件大小以及原来的release文件大小基本差不多,接下来我们分别看下一下段信息
经过比对我们发现这个三个文件的段一样的。那我们在来执行一下main.bin 这个剥离出来的文件看看(可以正常执行和正常的文件也一样)
这种情况的符号表分离是没有任何作用的。
二、接下来我们要做的就是生成一个有debug信息的的可执行文件
[root@localhost testm]# g++ -g3 -o3 main.cpp -o maingo
同样我们还做上面的操作进行符号表分离
[root@localhost testm]# objcopy --only-keep-debug maingo maingo.symbol
[root@localhost testm]# objcopy --strip-debug maingo maingo.bin
通过查看文件我们可以发现明显debug版本编译的含有debug信息的可执行文件maingo要比正常的版本文件mainO3大很多,在比较一下maingo、maingo.bin、maingo.symbol我们发现符号表文件同样很大,剥离后的可执行文件很小。
接下来我们来看看他们的段信息又是如何呢
含有debug信息的可执行文件在段中我们可以找到debug段信息如上红框
从上面这个被剥离处理的main.bin来看短信息中已经不含有debug段了,证明已经成功被剥离出来了
符号表文件是正常好友所有debug信息的段。
下面我门来执行一下看看这两个文件有没有什么不同
三、接下来我们要验证的就是release版的程序在调试的时候我们能看到什么信息,debug版本我们能看到什么信息
1、我们启动gdb来加载我们的可执行文件断点调试一下:
[root@localhost testm]# gdb //启动gdb
(gdb) file mainO3 //载入可执行文件mainO3
(gdb) b my_print //打断点
(gdb) r //执行
(gdb) info lo //查看局部变量
(gdb) n //下一步
我们发现局部变量和调试的时候报出来的都是(no debugging symbols found)
结论:release版调试时无法看到符号信息,不能定位调试问题
2、再看下debug版本调试如何(操作同上)
我们发我们在debug版本的时候可以清晰的看到文件名以及我们执行的行数以及每一行的代码,局部变量的值我们都可以查到。
3、我们来看下maingo.bin结果如何
结果和release的一样什么信息都看不到
4、这个是我们验证的关键的一点就是我们挂载符号表后看我们执行时候能含有符号信息呢
对于这种符号表与二进程序,可以在gdb 启动时,通过 –s 指定符号表文件来解决. 如下例,通过 –s 指定maingo.symbol 后, gdb 调试时可以看到符号表了.
哈哈,看来我们成功了,挂在符号表后我们能查到函数的信息及局部变量的值。
5、据说有源文件在统一执行目录就能看到更多信息了我们加上源文件看看执行结果如何
嗯,结果是我们看不到源码了但是我们还是可以查看文件中的局部变量的值,嗯,还算满意这样的话我们就可以在外网挂我们的优化的文件并且有不会影响效率,同时我们还挂载了符号表后我们可以查看相关的信息。