2014-12-07 60 views
2

我在Mac上,我使用的是鏗鏘聲++(別名爲g ++)。C++漂亮的堆棧跟蹤

我想在C++中打印類似Python的堆棧跟蹤。我打算使用框架和/或其他編譯器,但我需要它在Mac或Ubuntu上運行。

我已經簽出backtrace,但它看起來有點粗糙 - 我寧願不必計算字節數以找出堆棧跟蹤中每行的引用位置。另外,萬一它是相關的,我並不需要任何優化,所以如果它有幫助,我願意關閉優化。另外,如果我可以使用C++ 11功能(如果您建議使用不同的編譯器),我更喜歡它。


由於想什麼,我能夠做一個簡單的例子,最好我會跑

g++ MySource.cpp -o MyProgram <magic options> 

MySource.cpp可能看起來像

#include "MyHeader.hpp" 

int main() { 
    test(); 
} 

MyHeader.hpp可能看起來像

#include <magic_print_stacktrace_library> 

void test() { 
    magic_print_stacktrace_function(); 
} 

而且如果我是跑./MyProgram我想看到類似

File "MyHeader.hpp", line 4, in test 
    magic_print_stack_tracefunction(); 
File "MySource.cpp", line 4, in main 
    test(); 
+0

「我寧願不必計算字節數以找出堆棧跟蹤中每一行的引用位置」 - 然而,由於該語言中沒有此類功能的標準化,因此您需要使用system-像這樣的特定接口。 :( – 2014-12-07 03:26:12

回答

0

下面是一些代碼,我已經用於創建具有回溯回溯(3):

#include <errno.h> 
#include <execinfo.h> 
#include <unistd.h> 

/* 
* call external program addr2line WITHOUT using malloc or stdio or anything 
* else that might be problematic if there's memory corruption or exhaustion 
*/ 
const char *addr2line(void *addr, const char *text) 
{ 
    int pfd[2], len; 
    pid_t child; 
    static char  buffer[1024], *p; 
    const char *argv[5] = { "addr2line", buffer, "-e", program_name, 0 }; 
    uintptr_t a = (uintptr_t)addr; 
    if (pipe(pfd) < 0) return 0; 
    p = buffer + sizeof(buffer) - 1; 
    *p = 0; 
    while (p > buffer) { 
     *--p = "abcdef"[a&0xf]; 
     if (!(a >>= 4)) break; } 
    argv[1] = p; 
    if (text && (p = (char *)strchr(text, '('))) { 
     strncpy(buffer, text, p-text); 
     buffer[p-text] = 0; 
     argv[3] = buffer; } 
    while ((child = fork()) == -1 && errno == EAGAIN); 
    if (child == -1) return 0; 
    if (child == 0) { 
     dup2(pfd[1], 1); 
     dup2(pfd[1], 2); 
     close(pfd[0]); 
     close(pfd[1]); 
     execvp(argv[0], (char*const*)argv); 
     _exit(-1); } 
    close(pfd[1]); 
    p = buffer; 
    while (p < buffer + sizeof(buffer) - 1 && 
      (len = read(pfd[0], p, buffer+sizeof(buffer)-p-1)) > 0 && 
      (p += len) && !memchr(p-len, '\n', len)); 
    close(pfd[0]); 
    waitpid(child, &len, WNOHANG); 
    *p = 0; 
    if ((p = strchr(buffer, '\n'))) *p = 0; 
    if (buffer[0] == 0 || buffer[0] == '?') 
     return 0; 
    return buffer; 
} 


void stacktrace() { 
    static void *buffer[64]; 
    int size = backtrace(buffer, 64); 
    char **strings = backtrace_symbols(buffer, size); 
    for (int i = 1; i < size; i++) { 
     if (strings) 
      std::endl << " " << strings[i] << std::endl; 
     if (const char *line = addr2line(buffer[i], strings ? strings[i] : 0))   
      std::cerr << " " << line << std::endl; } 
    if (size < 1) 
     std::cerr << "backtrace failed" << std::endl; 
} 

注意,它需要知道的路徑可執行文件(上面的program_name),它需要用-g構建完整的信息。