通过valgrind、gdb定位程序问题的几个方法小结

来源:互联网 发布:网络歌曲2015 编辑:程序博客网 时间:2024/05/11 20:37

通过valgrind、gdb定位程序问题的几个方法小结

 

一,用valgrind定位程序问题

   在排查程序问题时候,我们会经常用到gdb。gdb确实是定位程序问题的很有用的工具。但是很多时候我们用gdb来定位问题,会发现不好定位,花了很多时候把发生core的地方找到了,可是还是不知道为何会发生该错误-----因为常常产生core的地方是由于在core之前的错误导致的。

   这时候别忘了另一个工具,那就是valgrind,根据我定位程序问题的经验,valgrind经常能给我惊喜。所以我觉得很有必要重视该工具,因为它确实能带给我们很多便利。

   我这里不具体说valgrind的原理和使用,网上有一大堆相关文档,大家感兴趣的话可以在网上找相关资料。我这里只是具体针对我们QQ秀的情况做介绍:

   1:使用valgrind定位cgi、fastcgi:

      1)使用valgrind来定位cgi问题:

       有两个前提条件:

       A)cgi必须是可执行程序,这意味着定位fastcgi(动态库)时,需要把它编译成cgi(可执行文件)形式;

       B)运行cgi时,需要配置环境变量(cgi的获取客户端请求是通过环境变量来读取请求包信息的),在qzthhp里面,对于cgi的环境变量,由qzhhtp来设置,现在我们需要单独跑cgi时,就需要我们自己配置环境变量了:

        设置方法:

Ø                首先我们通过httpwatch获取请求包:

Ø                根据请求包配置环境变量:

export REQUEST_METHOD=POST

export QUERY_STRING="parm1=1&parm2=2&…"

exportHTTP_COOKIE="vid=1011255824;flv=9.0;pt2gguin=o0249694429;airkey=c14101efd87eb……"

export CONTENT_TYPE=""

export CONTENT_LENGTH=""       

Ø                把cgi编译成可执行文件,运行:(譬如:qqshow_user_info)

valgrind --log-file-exactly=allen.log --tool=memcheck --leak-check=yes ./qqshow_user_info

  PS: 如果是post方式,那run后会等待输入,直接把参数拷贝过来输入就ok了,如“parm1=1&parm2=2&…”,         输入完按Ctrl+D或回车键表示输入完成,程序继续run

Ø                分析allen.log,定位程序问题。

       2)利用封装的valgrind工具leakscan来定位cgi、fastcgi

 大家每天都会收到一封邮件《CGI内存泄漏扫描(QQShow)》,里面大概是报告下cgi/fasctgi的内存使用情况,尽管标题是“内存泄漏”,但是不单单报告内存泄漏情况;其实该邮件用到的检测工具就是valgrind,只是封装过的,它就是运维同学开发的工具leakscan。

 前面讲到,我们自己手动配置运行cgi比较麻烦:1)fastcgi得重编成cgi;2)要配置一大堆环境变量;

 而使用leakscan就不需要这些。该工具我已经安装在开发QQshow开发环境了,运行文件是:

 /usr/local/services/leakscan/leakscan

 运行该程序前,需要做的一件事就是把httpwatch的请求包另存为一个文件,譬如

 qqshow_user_info.txt,通过crt上传到开发机,譬如在/home/user_00/下面,然后

 cd  /usr/local/services/leakscan/

 ./leakscan /usr/local/qqshow/cgi/cgi-bin/qqshow_user_info /home/user_00/qqshow_user_info.txt

   2:使用valgrind定位server问题:

QQShow 的server,一般都是用servrbeach++(简称S++)平台组件来搭建,我们根据业务编写相应的插件。

通过修改S++配置文件能做到嵌入valgrind来分析server的问题;

以qqmail中转server为例子:

qqmail开发环境(172.23.2.199)server目录:/usr/local/services/qqmailserver/

配置文件:/usr/local/services/qqmailserver/etc/

qqmail_ctrl.xml

qqmail_proxy.xml

qqmail_worker.xml

如果我们要定位业务代码的问题,通过修改qqmail_ctrl.xml就可以做到,如图所示:

 

修改点:

1)加入valgrind:

exe="./_valgrind --log-file=allen.log --tool=memcheck --leak-check=yes ./qqmail_worker"

PS:因为配置文件上basepath是bin目录,所以如果直接用valgrind会提示找不到该命令,我简单的在bin下面做个符号链接:

 

 

2)修改worker的个数:

因为我们只是定位问题,把worker的数目配置为1,便于我们定位问题,通过修改成 maxprocnum="2" minprocnum="1"就可以。

3)启动server,就能通过分析log-file来定位程序问题

 

PS:

1)运行valgrind会影响server的性能,并且输出valgrind分析日志,所以最好不要在外网这么做;

2)通过修改qqshow_ctrl.xml的方式嵌入valgrind时,可能在停止server时,该valgrind没法停止,这时候需要手动kill掉。

3)分析完毕后,记得把配置文件还原

 

二,外网cgi core文件分析:发生段错误导致堆栈破坏的core文件分析

外网的cgi一般都是非debug编译,而且经常由于段错误导致core,这时候用gdb来分析,会发现尽管有core文件,但是貌似给不了信息给我们,因为gdb分析没法知道core发生在哪。很多人做法是编译一个debug版本,然后通过打印日志来定位,这种方法相对来说有点消极。因为就算是破坏了堆栈的core文件,通过一些方式还是很有可能定位到core的地方的。下面介绍下分析的方法:

PS:该方法是km上的同学贡献的,我这里把他的文章汇总在这里:(robertyu发表于 2008-12-19 21:08)

如果有调试信息,gdb program core是很容易定位到位置的,除非把stack写乱。

但目前我们的cgi一般都没有调试信息(即编译时优化过,或者strip过),或者有时堆栈被写坏了,此时,上面的gdb program core不太容易定义到具体位置。

这里介绍一下通过异常点地址定义的方法:

 

1,gdb找到core的地址;

 

 

2,通过存活的同批/proc/PID/maps(linux2.6以后每次启动,地址有一点点随机,所以必须是同批次,除非禁止了此特性),或者info file找到cgi所在so的加载地址。如果不是cgi.so的问题,从这里也可以看的到。

 

注意,第一个是可执行段,属性为r-xp.第二个rw的为数据段。如果是其它段的异常,可以通过查看异常地址位于哪一个段里确定所属模块。

 

3,上述1-2得到异常的偏移;

0xb79c844f - 0xb7985000 = 0x4344f

 

4,objdump -D cgi-so >cgi.s反汇编。

 

5,用3的偏移(16进制)查找,即可找到异常的位置。

 

从上面可以看出,问题处在CFrameTTCClient::Get函数里。在gdb prog core里的最后一层,可以通过info reg命令看到当时的 esi=0,这是core的直接原因。根本原因这个bug上溯一层就查到了。

6,函数很小的化,很容易定位到问题。如果很大的话,看阅读asm的水平。所以建议多写小函数。

上述函数比较小,所以很快就定位到了问题。如果函数实在比较大,可以从asm里比较有特征的代码找到具体C/C++错误位置。如函数,比较,赋值等涉及的常数,字符串,典型C/C++代码编译为asm的特征等。

7,一般core的位置都不是错误的源头,但找到错误的位置及其特征之后,有助于定位问题的根源。

另外,由于优化过的代码(包括strip过),没有符号信息,尤其没有局部变量的信息,此时可以通过当时的reg及asm确定局部变量等的地址从而查看出变量的内容。这些内容有时非常有用。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/macky0668/archive/2009/07/07/4328959.aspx

原创粉丝点击