трассировка стека и функции в пространствах имен - PullRequest
10 голосов
/ 05 августа 2011

Я пытаюсь получить обратную трассировку в какой-то момент выполнения моей (c ++) программы.

, для этого я использую backtrace и backtrace_symbols.Что-то вроде этого:

std::string stacktrace( unsigned int frames_to_skip )
{
    std::string str;

    void* stack_addrs[50];
    int trace_size = backtrace( stack_addrs, 50 );
    char** stack_strings = backtrace_symbols( stack_addrs, trace_size );

    str += "[bt] backtrace:\n";
    // skip frames_to_skip stack frames
    for( int i = frames_to_skip; i < trace_size; ++i )
    {
        char tmp[4096];
        sprintf( tmp, "[bt] #%d %s\n", i-frames_to_skip, stack_strings[i] );
        str += tmp;
    }

    free( stack_strings );

    return str;
}

Это работает, но некоторые имена функций отсутствуют.пример:

[bt] #0 /path/to/executable() [0x43e1b5]
[bt] #1 /path/to/executable() [0x43e0cd]
[bt] #2 /path/to/executable() [0x43df51]
[bt] #3 /path/to/executable() [0x43dd44]
[bt] #4 /path/to/executable() [0x43db50]
[bt] #5 /path/to/executable() [0x43d847]
[bt] #6 /path/to/executable() [0x43d216]
[bt] #7 /path/to/executable() [0x43c1e1]
[bt] #8 /path/to/executable() [0x43b293]
[bt] #9 /path/to/executable(_Z29SomeRN5other8symbolE+0x2c) [0x43a6ca]
[bt] #10 /path/to/executable(_Z11SomeIN5_8symbolEPFvRS1_EEvRKT_RKT0_+0x77) [0x441716]
...

функции от 0 до 8 имеют одну общую точку: они все находятся в пространстве имен ...
Я попытался поместить функцию 9 в пространство анонимных имен (без каких-либо других изменений), и этоисчезает из следа ... который теперь выглядит следующим образом:

[bt] #0 /path/to/executable() [0x43e1b5]
[bt] #1 /path/to/executable() [0x43e0cd]
[bt] #2 /path/to/executable() [0x43df51]
[bt] #3 /path/to/executable() [0x43dd44]
[bt] #4 /path/to/executable() [0x43db50]
[bt] #5 /path/to/executable() [0x43d847]
[bt] #6 /path/to/executable() [0x43d216]
[bt] #7 /path/to/executable() [0x43c1e1]
[bt] #8 /path/to/executable() [0x43b293]
[bt] #9 /path/to/executable() [0x43a6ca]
[bt] #10 /path/to/executable(_Z11SomeIN5_8symbolEPFvRS1_EEvRKT_RKT0_+0x77) [0x441716]
...

Есть ли способ исправить это?

ps: версия g ++: g ++ (GCC) 4.6.0 20110530(Red Hat 4.6.0-9)

edit фиксированная максимальная глубина трассировки после замечания Code Monkey
edit2 добавлен полный код функции
edit3 код скомпилирован с -O0 -g3 и связан с -rdynamic

Ответы [ 3 ]

6 голосов
/ 05 августа 2011

Возможно, вашей проблемой являются используемые вами функции. Ваш max_depth in backtrace(..) установлен на 16. Это может быть слишком низким. Во всяком случае ...

В этом блоге о трассировках стека C ++ с помощью GCC объясняется, как вы должны выполнять трассировку стека. В сумме

#include <execinfo.h>
void print_trace(FILE *out, const char *file, int line)
{
    const size_t max_depth = 100;
    size_t stack_depth;
    void *stack_addrs[max_depth];
    char **stack_strings;

    stack_depth = backtrace(stack_addrs, max_depth);
    stack_strings = backtrace_symbols(stack_addrs, stack_depth);

    fprintf(out, "Call stack from %s:%d:\n", file, line);

    for (size_t i = 1; i < stack_depth; i++) {
        fprintf(out, "    %s\n", stack_strings[i]);
    }
    free(stack_strings); // malloc()ed by backtrace_symbols
    fflush(out);
}

GCC также предоставляет доступ к C ++ name (de) mangler. Есть некоторые довольно волосатые детали, чтобы узнать о владении памятью и взаимодействии с выводом трассировки стека требуется немного анализа строки, но это сводится к замене вышеуказанного внутреннего цикла следующим:

#include <cxxabi.h>
...
for (size_t i = 1; i < stack.depth; i++) {
    size_t sz = 200; // just a guess, template names will go much wider
    char *function = static_cast(malloc(sz));
    char *begin = 0, *end = 0;
    // find the parentheses and address offset surrounding the mangled name
    for (char *j = stack.strings[i]; *j; ++j) {
        if (*j == '(') {
            begin = j;
        }
        else if (*j == '+') {
            end = j;
        }
    }
    if (begin && end) {
        *begin++ = '';
        *end = '';
        // found our mangled name, now in [begin, end)

        int status;
        char *ret = abi::__cxa_demangle(begin, function, &sz, &status);
        if (ret) {
            // return value may be a realloc() of the input
            function = ret;
        }
        else {
            // demangling failed, just pretend it's a C function with no args
            std::strncpy(function, begin, sz);
            std::strncat(function, "()", sz);
            function[sz-1] = '';
        }
        fprintf(out, "    %s:%s\n", stack.strings[i], function);
    }
    else
    {
        // didn't find the mangled name, just print the whole line
        fprintf(out, "    %s\n", stack.strings[i]);
    }
    free(function);
}

На этом сайте есть больше информации (я не хотел дословно копировать), но просмотр этого кода и приведенного выше сайта должен привести вас на правильный путь.

1 голос
/ 05 августа 2011

backtrace перечисляет кадры вызовов, которые соответствуют машинному коду call, а не вызовам функций на уровне источника.

Разница заключается в том, что с помощью встраивания оптимизирующий компилятор часто может избежать использования call инструкция для каждого вызова логической функции в исходном коде.

1 голос
/ 05 августа 2011

Можете ли вы попробовать добавить -rdynamic к вашей ссылке?

http://www.linuxforums.org/forum/programming-scripting/35192-backtrace_symbols-no-symbols.html

...