2011-08-04 4 views
10

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

작동하지만 일부 기능 이름이 없습니다. 예를 들면 : 나는 (다른 수정없이) 익명의 네임 스페이스 기능 9 퍼팅 시도
... 그들은 모두 네임 스페이스에 앉아서는에서 disapears :

[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 하나 개의 공통 지점이 backtrace ... 이제 다음과 같이 보입니다 :

[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 (레드햇 4.6.0-9) 코드 원숭이의 발언 후 역 추적의 최대 깊이를 고정

편집
EDIT2
EDIT3 코드가 -O0 -g3 컴파일하고 사용하는 기능을 할 수있다 -rdynamic

답변

6

귀하의 문제와 연결되어 함수의 전체 코드를 추가했습니다. max_depth : backtrace(..)은 16으로 설정됩니다. 너무 낮을 수 있습니다. 어쨌든 ...

C++ stack traces with 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++ 이름 (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); 
} 

해당 사이트에 대한 더 많은 정보가 있습니다. (나는 그대로 사용하고 싶지 않습니다.) 그러나이 코드를 보면서 위의 사이트는 올바른 길을 찾아야합니다.

+0

안녕하세요, 귀하의 답변에 감사드립니다.당신은 최대 깊이에 대해 옳았습니다. 백 트레이스의 끝은 누락되었지만, 누락 된 호출은 제가 사용하고있는 테스트 프레임 워크에서 나온 것이므로 문제가 아닙니다. 그래도 문제는 여전히 남아 있으며 블로그 게시물에 나와있는 것과 똑같이하고 있습니다. 하나의 흥미로운 사실이지만 테스트 프레임 워크는 네임 스페이스에 함수가 있고 스택 트레이스에서 볼 수 있습니다. 함수는 ... 다시 테스트를 수행하고 (네임 스페이스에 함수를 넣음) 동일한 hapenned 함수를 다시 사용합니다 backtrace에서 더 이상 볼 수 없다 ... – foke

1

backtrace 목록 기계 코드에 call 지침이 아닌 소스 레벨의 함수 호출을 해당 전화 프레임.

인라인을 사용하면 최적화 컴파일러에서 소스 코드의 모든 논리 함수 호출에 call 명령어를 사용하지 않을 수도 있습니다.

+0

그 경우에는 bt에 전혀 나타나지 않을 것이다. 어쨌든 최적화가 없다면, -O0 -g3'. 또한 백 트레이스를 구성하는 함수를 깨고 기호가없는 주소 아래로 이동하면 해시 뷰 (이클립스를 사용하고 있음)에서 'call'명령을받은 직후에 끝납니다 올바르게 표시됩니다 (점프 할 함수/메소드의 이름이 표시됨). – foke