2011-08-04 13 views
10

Próbuję uzyskać ślad wsteczny w pewnym momencie wykonywania mojego programu (C++).Stacktrace i funkcje w przestrzeniach nazw

dla tego używam backtrace i backtrace_symbols. Coś w tym stylu:

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

Działa, ale brakuje niektórych nazw funkcji. Przykład:

[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] 
... 

funkcje 0 do 8 mają jeden punkt wspólny: wszyscy siadają w obszarze nazw ...
Próbowałem funkcji 9 umieszczenie w przestrzeni nazw anonimowych (bez innych modyfikacji) i disapears od backtrace ... który teraz wygląda następująco:

[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] 
... 

Czy istnieje sposób, aby to naprawić?

PS: wersja g ++: g ++ (GCC) 4.6.0 20.110.530 (Red Hat 4.6.0-9)

edit ustalona maksymalna głębokość backtrace po Code Monkey uwagą
Edit2 dodał pełny kod funkcji
Edit3 kod jest skompilowany z -O0 -g3 i połączonego z -rdynamic

Odpowiedz

6

Twój problem może być funkcje używasz. Twój max_depth w backtrace(..) jest ustawiony na 16. To może być zbyt niskie. W każdym razie ...

Ten wpis na blogu na stronie C++ stack traces with GCC wyjaśnia, w jaki sposób należy wykonywać śledzenie stosu. W sumie,

#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 zapewnia również dostęp do C++ nazwy (de) mangler. Istnieją pewne dość owłosione dane dowiedzieć się o własności pamięci i relacje z wyjściem ślad stosu wymaga trochę ciąg parsowania, ale sprowadza się do zastąpienia powyższą pętlę wewnętrzną z tym:

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

Jest więcej informacji na tej stronie (nie chciałem kopiować dosłownych), ale patrząc na ten kod i powyższą stronę, powinienem dostać właściwy tor.

+0

Witam, dziękuję za odpowiedź.masz rację co do maksymalnej głębokości, brakuje końca śledzenia wstecznego, ale to nie jest problem, ponieważ te brakujące połączenia pochodzą z używanego przez mnie schematu testowego. Mimo to problem pozostaje i robię to samo, co w blogu. Jeden interesujący fakt jednak, struktura testowa ma funkcje w przestrzeniach nazw i są one widoczne w stosie, moje funkcje nie są ... Zrobiłem test ponownie (umieszczając funkcję w przestrzeni nazw), i to samo stało się ponownie (funkcja nie jest już widoczny na backtrace ... – foke

1

backtrace listy ramek połączeń, które odpowiadają kodu maszynowego call instrukcjami, a nie źródło wywołania funkcji poziomu.

Różnica polega na tym, że podczas wstawiania kompilator optymalizujący może często unikać stosowania instrukcji call dla każdego logicznego wywołania funkcji w kodzie źródłowym.

+0

W takim przypadku nie pojawią się one wcale w bt. W każdym razie nie ma tutaj optymalizacji, jest skompilowany z '-O0 -G3' .Ponieważ jeśli włamie się funkcję, która tworzy ślad i przejdzie do adresu pod jednym bez symbolu, w widoku demontażu (używam zaćmienia), kończę zaraz po poleceniu 'call', które jest poprawnie wyświetlany (aka pokazuje nazwę funkcji/metody, do której ma zamiar wskoczyć). – foke

Powiązane problemy