代码之家  ›  专栏  ›  技术社区  ›  T Percival Daniel Gehriger

自动获取Unix系统上的堆栈跟踪

  •  7
  • T Percival Daniel Gehriger  · 技术社区  · 16 年前

    在Unix系统上,有哪些方法可以自动获取堆栈跟踪?我的意思不只是获取一个核心文件或与gdb交互附加,而是使用一个sigsegv处理程序将回溯转储到一个文本文件。

    以下可选功能的奖励积分:

    • 崩溃时收集额外信息(如配置文件)。
    • 通过电子邮件将崩溃信息包发送给开发人员。
    • 将此添加到 dlopen ED共享库
    • 不需要图形用户界面
    4 回复  |  直到 9 年前
        1
  •  7
  •   Walery Strauch Lia    9 年前

    如果您使用的是带有BSD的系统 backtrace 可用的功能(当然是Linux、OSX 1.5、BSD),您可以在信号处理程序中以编程方式完成这项工作。

    例如( backtrace code derived from IBM example ):

    #include <execinfo.h>
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    void sig_handler(int sig)
    {
        void * array[25];
        int nSize = backtrace(array, 25);
        char ** symbols = backtrace_symbols(array, nSize);
    
        for (int i = 0; i < nSize; i++)
        {
            puts(symbols[i]);;
        }
    
        free(symbols);
    
        signal(sig, &sig_handler);
    }
    
    void h()
    {
        kill(0, SIGSEGV);
    }
    
    void g()
    {
        h();
    }
    
    void f()
    {
        g();
    }
    
    int main(int argc, char ** argv)
    {
        signal(SIGSEGV, &sig_handler);
        f();
    }
    

    输出:

    0   a.out                               0x00001f2d sig_handler + 35
    1   libSystem.B.dylib                   0x95f8f09b _sigtramp + 43
    2   ???                                 0xffffffff 0x0 + 4294967295
    3   a.out                               0x00001fb1 h + 26
    4   a.out                               0x00001fbe g + 11
    5   a.out                               0x00001fcb f + 11
    6   a.out                               0x00001ff5 main + 40
    7   a.out                               0x00001ede start + 54
    

    但是,它的优点是非常简单,不需要任何额外的库或程序。

        2
  •  15
  •   Gilad Ben-Yossef    16 年前

    FYI

    建议的解决方案(在信号处理程序中使用backtrace_符号)被危险地破坏。不要使用它——

    是的,backtrace和backtrace_符号将生成一个backtrace并将其转换为符号名,但是:

    1. backtrace_符号使用malloc分配内存,并使用free释放内存-如果由于内存损坏而崩溃,则malloc竞技场很可能损坏并导致双重故障。

    2. malloc和free用内部锁保护malloc竞技场。您可能在malloc/free的中间出现了错误,并获取了锁,这将导致这些函数或任何调用它们的函数死锁。

    3. 使用使用标准流的Puts,该流也受锁保护。如果在打印过程中出错,则会再次出现死锁。

    4. 在32位平台上(例如,2年前的普通PC),内核会将返回地址设置到内部glibc函数,而不是堆栈中的错误函数,因此您感兴趣的最重要的信息——哪个函数导致了程序错误——实际上会在这些平台上损坏。

    因此,示例中的代码是最糟糕的错误类型——看起来它在工作,但在生产中它确实会以意想不到的方式使您失败。

    顺便问一下,有兴趣做对吗?检查 this 出来。

    干杯, 吉拉德。

        3
  •  4
  •   Walery Strauch Lia    9 年前

    下面是一个如何使用demangler获取更多信息的示例。如您所见,这个还将stacktrace记录到文件中。

    #include <iostream>
    #include <sstream>
    #include <string>
    #include <fstream>
    #include <cxxabi.h>
    
    void sig_handler(int sig)
    {
        std::stringstream stream;
        void * array[25];
        int nSize = backtrace(array, 25);
        char ** symbols = backtrace_symbols(array, nSize);
        for (unsigned int i = 0; i < size; i++) {
            int status;
            char *realname;
            std::string current = symbols[i];
            size_t start = current.find("(");
            size_t end = current.find("+");
            realname = NULL;
            if (start != std::string::npos && end != std::string::npos) {
                std::string symbol = current.substr(start+1, end-start-1);
                realname = abi::__cxa_demangle(symbol.c_str(), 0, 0, &status);
            }
            if (realname != NULL)
                stream << realname << std::endl;
            else
                stream << symbols[i] << std::endl;
            free(realname);
        }
        free(symbols);
        std::cerr << stream.str();
        std::ofstream file("/tmp/error.log");
        if (file.is_open()) {
            if (file.good())
                file << stream.str();
            file.close();
        }
        signal(sig, &sig_handler);
    }
    
        4
  •  2
  •   Kristof Provost    16 年前

    德雷克斯的解决方案可能是最好的,但无论如何,这里有一个替代方案:

    最新的Linux内核版本允许您通过管道将核心转储发送到脚本或程序。您可以编写一个脚本来捕获核心转储文件,收集您需要的任何额外信息,然后将所有内容发回。 不过,这是一个全局设置,因此它适用于系统上任何崩溃的程序。它还需要根权限来设置。 它可以通过/proc/sys/kernel/core_模式文件进行配置。将其设置为类似于“/home/myuser/bin/my core handler script”。

    Ubuntu人也使用这个功能。

    推荐文章