C ++漂亮的堆栈跟踪

时间:2014-12-07 03:05:19

标签: c++

我在Mac上,我正在使用clang ++(别名为g ++)。

我正在尝试用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();

1 个答案:

答案 0 :(得分: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 = "0123456789abcdef"[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构建完整信息。