编写服务器端程序,很容易遇到Crash问题,比较幸运的是Linux提供了core file,保留了Crash的现场。有时候,根据当前的调用栈,并且打印出当前栈的变量就可以分析出crash的原因,但是,有时候看到调用栈却束手无策。下面就介绍自己通过GDB的几个命令的结合,发现一个crash的原因的过程。

下面让我们一起进入现场,来逐步发现其中的原因。

首先,还是运行gdb 命令,gdb wbxgs core.5797,来看看现场。

[root@hfgs126 bin]# gdb wbxgs_crash core.5797  

GNU gdb Red Hat Linux (6.3.0.0-1.132.EL4rh)

……

#0 0x00000038e8d70540 in strlen () from /lib64/tls/libc.so.6

(gdb) bt

#0 0x00000038e8d70540 in strlen () from /lib64/tls/libc.so.6

#1 0x000000000057cfc0 in T120_Trace::Text_Formator::advance (this=0x7e800a70, lpsz=0x1 <Address 0x1 out of bounds>)

at ./t120trace.cpp:1464

#2 0x000000000057ceb1 in T120_Trace::Text_Formator::operator<< (this=0x7e800a70, lpsz=0x1 <Address 0x1 out of bounds>)

at ./t120trace.cpp:1411

#3 0x0000000000407927 in ~func_tracer (this=0x7e804bd0) at ../h/t120trace.h:381

#4 0x00000000004432fd in CGSSocketServer::readHeader (this=0x8e4130, socketfd=1088,

buf=0x7e806cc0 "GET /detectService?cmd=selfcheck HTTP/1.1/r/nConnection: Close/r/nHost: 10.224.122.94/r/n/r/n", bufsize=1024)

at mgr/gssocketserver.cpp:337

#5 0x0000000000443981 in CGSSocketServer::handle (this=0x8e4130, socketfd=1088, strRet=@0x7e807190) at mgr/gssocketserver.cpp:424

#6 0x0000000000442f5e in CGSSocketServer::readThread (pArg=0x9ae9c0) at mgr/gssocketserver.cpp:304

#7 0x00000038e980610a in start_thread () from /lib64/tls/libpthread.so.0

#8 0x00000038e8dc68b3 in clone () from /lib64/tls/libc.so.6

#9 0x0000000000000000 in ?? ()

通过这个调用栈,可以看出,程序crash在打log的时候。虽然遇到过类似的crash,但是,当时的原因是有死循环,通过review code,没有发现死循环。但是当前的调用栈对于分析Crash的原因是一点用也没有,如果分析具体的原因呢?会不会是其他得线程出现错误导致程序Crash在这个线程呢?为了找到深一层的原因,尝试着通过GDB的一些关于线程的命令,来看看其他的线程是否有问题。于是,使用info threads,查看了一下当时线程的情况。

(gdb) info threads  

21 process 5797 0x00000038e8d7186d in memset () from /lib64/tls/libc.so.6

20 process 5839 0x00000038e8dc6c8c in epoll_wait () from /lib64/tls/libc.so.6

19 process 5842 0x00000038e8d8f7d5 in __nanosleep_nocancel () from /lib64/tls/libc.so.6

18 process 5845 0x00000038e8d8f7d5 in __nanosleep_nocancel () from /lib64/tls/libc.so.6

17 process 5846 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0

16 process 5847 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0

15 process 5848 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0

14 process 5849 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0

13 process 5850 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0

12 process 5852 0x00000038e8dbf946 in __select_nocancel () from /lib64/tls/libc.so.6

11 process 5854 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0

10 process 5856 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0

9 process 5857 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0

8 process 5858 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0

7 process 5859 0x00000038e8d8f7d5 in __nanosleep_nocancel () from /lib64/tls/libc.so.6

6 process 5861 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0

5 process 5862 0x00000038e980a66f in sem_wait () from /lib64/tls/libpthread.so.0

4 process 5863 0x00000038e8d8f7d5 in __nanosleep_nocancel () from /lib64/tls/libc.so.6

3 process 5864 0x00000038e8d8f7d5 in __nanosleep_nocancel () from /lib64/tls/libc.so.6

2 process 5883 0x00000038e8d8f7d5 in __nanosleep_nocancel () from /lib64/tls/libc.so.6

* 1 process 5853 0x00000038e8d70540 in strlen () from /lib64/tls/libc.so.6

对于线程如果停止在sleep或者wait的情况,都是正常的,但是我们看到thread 21有些异常,程序停止在memset,不管是否有问题,都需要看看这样的线程具体有没有出错。

于是通过命令thread 21,进入到thread 21的调用栈。

(gdb) thread 21  

[Switching to thread 21 (process 5797)]#0 0x00000038e8d7186d in memset () from /lib64/tls/libc.so.6

(gdb) bt  

#0 0x00000038e8d7186d in memset () from /lib64/tls/libc.so.6

#1 0x000000000049da0d in CGSPduFactory::streamStringFrom (is=@0x7fff9b436360, strFrom=@0x2aaaec979760) at common/pdu/gspdu.cpp:422

#2 0x00000000004d1f25 in CGSOthShardUserRspPdu::streamFrom (this=0x2aaaec951650, is=@0x7fff9b436360) at common/pdu/pdugs.cpp:2707

#3 0x000000000049cb2d in CGSPduFactory::derivePdu (is=@0x7fff9b436360, ulPDULen=30506) at common/pdu/gspdu.cpp:79

#4 0x000000000049c78e in CGSPduFactory::streamPduFrom (pDataPacket=0x2aaaeca31d70) at common/pdu/gspdu.cpp:35

#5 0x0000000000449681 in CGSWDMSManager::on_wdms_message_indication (this=0x8e3680, msg=0x2aaae9894360)

at mgr/gswdmsmanager.cpp:344

……

#18 0x0000000000407733 in main (argc=1, argv=0x7fff9b44ac98) at gsmain.cpp:118

(gdb) f 3  

#3 0x000000000049cb2d in CGSPduFactory::derivePdu (is=@0x7fff9b436360, ulPDULen=30506) at common/pdu/gspdu.cpp:79

79      common/pdu/gspdu.cpp: No such file or directory.

in common/pdu/gspdu.cpp

使用命令 i locals,打印所有的变量的值。

(gdb) i locals  

pPdu = (CBasePdu *) 0x2aaaec951650

pPduHeader = (CPduHeader *) 0x2aaaea1c4190

ulPduType = 50

到现在还没有看出有什么明显的异常,然后再把PDU的头打印出来如下:

(gdb) p *pPduHeader

$1 = {m_ulHeadLen = 61, m_ulVersion = 2080000, m_ulPduType = 50, m_ulSrcSvrType = WEBEX_CONNECT_GS, m_strSrcSvrAddr = {

static npos = 18446744073709551615,

_M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},

_M_p = 0x2aaaeca52a68 "10.224.95.109:9900"}}, m_strSubject = {static npos = 18446744073709551615,

_M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},

_M_p = 0x2aaaec929b28 "qawin.qazone.GS"}}, m_ulSequence = 0}

从蓝色的字的部分可以看出,这个PDU是从10.224.95.109这台server上发过来的。

当时QA测试的环境,都是10.224.122开头的IP的server,怎么会有这个IP的PDU,于是,询问QA,发现10.224.95.109这个server是其他DataCenter的Server,而且还是老的版本,由于当前测试环境的版本删除了两个PDU,同时又增加了四个PDU,导致了老的PDU发来的时候,新的版本的把它当作新的PUD解析,从而导致不能正确解析,最终导致了解析出来的长度不对。可以通过f 1命令进入第一级调用栈查看所有的局部变量。

(gdb) f 1

#1 0x000000000049da0d in CGSPduFactory::streamStringFrom (is=@0x7fff9b436360, strFrom=@0x2aaaec979760) at common/pdu/gspdu.cpp:422

422                  in common/pdu/gspdu.cpp

(gdb) i locals  

strTmp = 0x2aaaf1c00010 ""

iRet = 0

ulLen = 1179995975  

可以看出解析出来的长度是一个很大的值,而线程21正式停止在分配内存之后,使用memset时,停止在那里。从Log中也可以看到,thread 21也一致阻塞在这里,而且没有再继续运行。

由于当时有两台server crash,通过查看另外一台server的core file,发现另外一台server也是和本台server一样的调用栈。在QA更新了10.224.95.109的版本后,crash没有再出现。

通过这个实例,可以看出,当server出现crash的时候,虽然当前的调用栈可能没有什么价值,但是,通过分析所有线程的调用栈,还是可能分析出蛛丝马迹的,从而对于解决Crash的问题带来帮助。

通过这个问题可以得到一个教训,在修改Server之间的接口时,一定要考虑到和老版本的兼容问题,即使这个PDU可能永远也不会使用,仍然需要保留,因为Production上,是先上GSB,然后再上Primary,肯定会存在两个版本同时运行的情况。如果出现删除或者改变PDU顺序的情况,可能会导致整个系统不能工作。

希望本文章,对解决Crash问题和避免类似的Crash问题有一定的借鉴作用。

【Linux】gdb调试core文件的更多相关文章

  1. Linux下交叉编译gdb,gdbserver+gdb的使用以及通过gdb调试core文件

    交叉编译gdb和gdbserver 1.下载gdb:下载地址为:http://ftp.gnu.org/gnu/gdb/按照一般的想法,最新版本越好,因此下载7.2这个版本.当然,凡事无绝对.我们以gd ...

  2. GDB调试core文件(2)

    使用gdb和core dump迅速定位段错误 关键字:gdb.段错误.core dump 一.什么是core dump core:内存.核心的意思: dump:抛出,扔出: core dump:前提: ...

  3. 解决gdb 调试 core 文件函数名显示为问号的问题

    关于gdb调试core文件总是一堆问号的问题 问题描写叙述:已经在编译选项中增加了-g,可是查看core文件时.还是一堆问号,使用的命令为:gdb -c core 解决方式:因为gdb -c core ...

  4. GDB调试core文件(3)

    列出一些常见问题: 一,如何使用core文件 使用core文件 在core文件所在目录下键入: gdb -c core 它会启动GNU的调试器,来调试core文件,并且会显示生成此core文件的程序名 ...

  5. Linux上调试core文件(Good)

    coredump文件 什么是coredump? 通常情况下coredmp包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息等.可以理解为把程序工作的当前状态存储成一个文件.许多程序和操作系统出 ...

  6. gd调试命令,gdb调试core文件

    使用 gcc -g test.c -o test.out 编译程序,只有加-g参数才支持gdb调试: 然后 gdb ./test.out 运行可执行文件,进入gdb调试模式(gdb),在括号后面的输入 ...

  7. gdb调试core文件

    本人最近正在学习调试技术,此处对栈溢出做一些总结. gdb的基本使用就不多扯了. 主要针对发行在外的release版本的软件出现问题时的调试. 一般来讲,查看堆栈就是使用bt,这个时候加上bt ful ...

  8. gdb 调试core文件报错: in free () from /lib64/libc.so.6 找不到原因啊

    运行程序死掉  找不到原因啊..gdb 跟踪与堆栈信息 贴出来了 麻烦大佬们看一下,给个回复,不胜感激!! Core was generated by `./scene_s0037 10037'.Pr ...

  9. gdb 调试coredump文件过程

    gdb 调试coredump文件过程: 第一步:首先需要一个进程的coredump文件,怎么搞出coredump文件呢? 1. ps -fax|grep                 进程名称 找到 ...

随机推荐

  1. 那些不被关注但很重要的html标签

    1.meta标签: <meta> 元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词. <meta> 标签位于文档的头部, ...

  2. Linux编译安装RTL8192CU芯片驱动,使用TP_LINK wn823n无线网卡

    前几天给自己的台式电脑安装了Window 7+CentOS 6.4 Linux双系统,发现在Windows 7下面可以正常使用TP_LINK wn823n无线网卡来连接无线网络,但是在Linux下面, ...

  3. 记一次PHP项目部署过程

    首先介绍一下项目的基本情况:使用PHP语言开发,数据库用的是MySQL 5.5,HTTP服务器用的是Apache 2.2.早上十点到机房看了看服务器的基本情况:Windows 2000操作系统,没有安 ...

  4. C++的优秀特性4:指针

    (转载请注明原创于潘多拉盒子) 其实指针不是C++的特性,而是地地道道的C的特性.有人说C++继承了C的指针,实在是败笔,造成内存泄漏云云,纯粹是不懂.可以这么说,如果没有指针,C++会逊色很多,应用 ...

  5. MySQL中进行树状所有子节点的查询

    在Oracle 中我们知道有一个 Hierarchical Queries 通过CONNECT BY 我们可以方便的查了所有当前节点下的所有子节点.但很遗憾,在MySQL的目前版本中还没有对应的功能. ...

  6. eclipse添加第三方源码

  7. Codeforces Good bye 2015 B. New Year and Old Property dfs 数位DP

    B. New Year and Old Property 题目连接: http://www.codeforces.com/contest/611/problem/B Description The y ...

  8. Oracle 自己主动诊断资料档案库 (ADR)、自己主动诊断工作流、ADRCI工具

    1.自己主动诊断工作流: 通过一个始终处于打开状态的内存中跟踪工具,数据库组件能够在第一次出现严重错误故障时捕获诊断数据.系统将自己主动维护一个称为"自己主动诊断资料档案库"的特殊 ...

  9. linux 内核参数图解

    https://www.suse.com/documentation/sles11/book_sle_tuning/data/part_tuning_kernel.html http://blog.c ...

  10. Linux合并文件、去除重复行的命令

    Linux合并文件命令: awk '{printf("%s\n",$0)}' YQ-*101?.txt >  123.txt   linux去除重复行命令:cat YQ-10 ...