如何在没有gdb的情况下获得崩溃函数的回溯(调用堆栈)或死锁?

时间:2015-04-01 18:28:43

标签: c++ linux gdb

我试图找到一个随机错误(我没有特定的senario),这会导致我的C ++ linux程序崩溃。 我知道如果我使用gdb并且应用程序崩溃,我可以使用" bt"命令并获取崩溃的调用堆栈。 我不能使用gdb(logisitic问题),崩溃是随机的。

  1. 在Linux中是否有办法获取崩溃的C ++应用程序的调用堆栈,而不使用gdb?
  2. 有没有办法知道是否有死锁(有和没有gdb)?
  3. 由于

2 个答案:

答案 0 :(得分:1)

您可以使用__cxa_demangle()来获取堆栈消息,如下所示:

string OException::strGetSourceCode(const string& p_strFileName,const string& p_strAddressInfo) throw()
{
    char l_acBuf[CBUFFLEN] = {0};
    char l_acAddress[CBUFFLEN] = {0};
    memcpy(l_acBuf, p_strAddressInfo.c_str(), p_strAddressInfo.length());
    if(sscanf(l_acBuf,"%*[^[][0x%[^]]", l_acAddress)==1)
    {   
        FILE *l_pFp;
        stringstream l_ss;
        if(p_strFileName.find(".so")!=string::npos)
        {   
            unsigned int l_lOffset=strtol(l_acAddress,NULL,16)-strtol(strGetBaseAddress(p_strFileName).c_str(),NULL,16);
            snprintf(l_acAddress,sizeof(l_acAddress),"%x",l_lOffset);
        }   

        l_ss << "addr2line 0x" << l_acAddress<< " -i -e " << p_strFileName;
        if((l_pFp = popen(l_ss.str().c_str(), "r"))) {
            if(fgets(l_acAddress, CBUFFLEN, l_pFp) != NULL) {
                l_acAddress[strlen(l_acAddress) - 1] = '\0';
            }   
        }   
        return l_acAddress;
    }   
    return  l_acBuf;
}
string OException::strGetBaseAddress(const string& p_soFileName) throw()
{
    int l_iPid=getpid();
    char l_acFileName[CBUFFLEN]={0};
    char l_acCmd[CBUFFLEN]={0};
#ifdef __linux__ 
    snprintf(l_acFileName,sizeof(l_acFileName),"/proc/%d/maps",l_iPid);
    snprintf(l_acCmd,sizeof(l_acCmd),"grep %s %s | head -1 | awk -F- \'{print $1}\'",p_soFileName.c_str(),l_acFileName);
#endif
    FILE* l_pFile=popen(l_acCmd,"r");
    char l_acBaseAddress[CBUFFLEN]={0};
    if(fgets(l_acBaseAddress,CBUFFLEN,l_pFile)!=NULL)
        return l_acBaseAddress;
    return "";
}
void OException::vSaveStackTrace() throw()
{
    void* l_acBuffer[CBUFFLEN];
    int l_iStackCount = ::backtrace(l_acBuffer, CBUFFLEN); //get the trace list    //cout<<"l_iStackCount="<<l_iStackCount<<endl;
    //translate trace message 
    char** l_pacStackResult = ::backtrace_symbols(l_acBuffer, l_iStackCount);
    if (l_pacStackResult)
    {
        string l_strFormat="";
        string l_binFile="";
        m_sStack="==============BackTrace===========\n";
        for (int i = 0;i<l_iStackCount-1; i++)//
        {

            l_binFile=l_pacStackResult[i];//get the exe filename
            l_binFile=l_binFile.substr(0,l_binFile.find('(',0));
            m_sStack.append(l_strFormat+"["+l_binFile+"]:"+strDemangle(l_pacStackResult[i])+"-->");
            m_sStack.append(strGetSourceCode(l_binFile,l_pacStackResult[i]));
            m_sStack.push_back('\n');
            l_strFormat+="  ";
        }
        free(l_pacStackResult);
    }

}
string  OException::strDemangle(const char* p_acSymbol) throw()
{
    size_t size;
    int status;
    char l_acTmp[CBUFFLEN]={0};
    char* l_pDemangled;
    //first, try to demangle a c++ name
    if (1 == sscanf(p_acSymbol, "%*[^(](%256[^)+]", l_acTmp)) {
        if (NULL != (l_pDemangled = abi::__cxa_demangle(l_acTmp, NULL, &size, &status))) {
            string l_strResult(l_pDemangled);
            free(l_pDemangled);
            return l_strResult;
        }
    }
    //if that didn't work, try to get a regular c p_acSymbol
    if (1 == sscanf(p_acSymbol, "%256s", l_acTmp)) {
        return l_acTmp;
    }
    return p_acSymbol;
}

答案 1 :(得分:0)

还有另一种方法来获取崩溃程序的回溯,但是当然它不如gdb的回溯,这里描述了该解决方案:https://stackoverflow.com/a/24573266/4442731

简而言之,您需要使用以下选项编译程序:

-g -rdynamic

然后您需要注册信号处理程序(SIGSEGV可能是您需要的信号):

signal(SIGSEGV, callbackWhenSignalOccures);

在函数callbackWhenSignal中,您可以使用函数显示回溯: How to automatically generate a stacktrace when my program crashes

关于gdb -我不知道您所说的“我不能使用gdb(逻辑问题)”是什么意思,但是您不必以交互方式运行gdb,您只需显示从核心回溯,然后gdb将自动退出:

ulimit -c unlimited
./program # it crashes
gdb -silent ./program core --eval-command=backtrace --batch

关于死锁,我找到了解决方法:http://man7.org/linux/man-pages/man3/backtrace.3.html