簡體   English   中英

自動在Unix系統上獲取堆棧跟蹤

[英]Getting stack traces on Unix systems, automatically

有哪些方法可以在Unix系統上自動獲取堆棧跟蹤? 我的意思不是只獲取核心文件或與GDB交互附加,而是擁有將回溯記錄轉儲到文本文件的SIGSEGV處理程序。

以下可選功能的加分:

  • 崩潰時收集的其他信息(例如配置文件)。
  • 通過電子郵件將崩潰信息包發送給開發人員。
  • 可以將其添加到dlopen共享庫中
  • 不需要GUI

僅供參考

建議的解決方案(在信號處理程序中使用backtrace_symbols)很危險。 請勿使用-

是的,backtrace和backtrace_symbols將產生一個backtrace並將其轉換為符號名稱,但是:

  1. backtrace_symbols使用malloc分配內存,您可以使用free釋放它-如果由於內存損壞而崩潰,則您的malloc競技場很可能會損壞並導致雙重錯誤。

  2. malloc和free通過內部鎖定來保護malloc競技場。 您可能在malloc / free的中間發生了錯誤並獲得了鎖定,這將導致這些函數或任何將其調用為死鎖的事情。

  3. 您使用的puts使用標准流,該流也受鎖保護。 如果您在printf的中間出現故障,您將再次陷入僵局。

  4. 在32位平台(例如2年前的普通PC)上,內核會將返回地址植入內部glibc函數中,而不是將錯誤函數植入堆棧中,因此您感興趣的是一條最重要的信息-在其中函數確實造成了程序故障,實際上將在那些平台上被破壞。

因此,該示例中的代碼是最嚴重的錯誤-看起來像正在工作,但實際上會使生產中的意外失敗。

順便說一句,有興趣做對嗎? 檢查出。

干杯,吉拉德。

如果您使用的系統具有BSD backtrace功能(當然是Linux,OSX 1.5,BSD),則可以在信號處理程序中以編程方式執行此操作。

例如( 從IBM示例派生的backtrace代碼 ):

#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

這不會為可選功能獲得加分(除非不需要GUI),但是,它的確具有非常簡單的優勢,並且不需要任何其他庫或程序。

這是一個如何使用分解器獲得更多信息的示例。 如您所見,這還將堆棧跟蹤記錄到文件中。

#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);
}

Dereks解決方案可能是最好的,但是無論如何這是一個替代方案:

最新的Linux內核版本允許您將核心轉儲通過管道傳遞到腳本或程序。 您可以編寫腳本來捕獲核心轉儲,收集所需的任何其他信息,然后將所有內容郵寄回去。 但是,這是一個全局設置,因此它適用於系統上所有崩潰的程序。 它還將需要root權限來設置。 可以通過/ proc / sys / kernel / core_pattern文件進行配置。 將其設置為“ | / home / myuser / bin / my-core-handler-script”。

Ubuntu人也使用此功能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM