2011-08-03 4 views
67

Linux 특정 backtrace()backtrace_symbols()을 사용하면 프로그램의 호출 추적을 생성 할 수 있습니다. 그러나 프로그램의 이름이 아닌 기능 주소 만 인쇄합니다. 함수 이름도 인쇄 할 수 있습니까? 난 -g뿐만 아니라 -ggdb와 함께 프로그램을 컴파일하려고했습니다. 바로 아래의 테스트 케이스는이 인쇄 :backtrace()/backtrace_symbols()는 함수 이름을 출력하는 방법은 무엇입니까?

 

    BACKTRACE ------------ 
    ./a.out() [0x8048616] 
    ./a.out() [0x8048623] 
    /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413] 
    ./a.out() [0x8048421] 
    ---------------------- 

나는 또한 함수 이름, foomain

코드 보여주기 위해 처음 2 개 항목을 원하는 것 :

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

static void full_write(int fd, const char *buf, size_t len) 
{ 
     while (len > 0) { 
       ssize_t ret = write(fd, buf, len); 

       if ((ret == -1) && (errno != EINTR)) 
         break; 

       buf += (size_t) ret; 
       len -= (size_t) ret; 
     } 
} 

void print_backtrace(void) 
{ 
     static const char start[] = "BACKTRACE ------------\n"; 
     static const char end[] = "----------------------\n"; 

     void *bt[1024]; 
     int bt_size; 
     char **bt_syms; 
     int i; 

     bt_size = backtrace(bt, 1024); 
     bt_syms = backtrace_symbols(bt, bt_size); 
     full_write(STDERR_FILENO, start, strlen(start)); 
     for (i = 1; i < bt_size; i++) { 
       size_t len = strlen(bt_syms[i]); 
       full_write(STDERR_FILENO, bt_syms[i], len); 
       full_write(STDERR_FILENO, "\n", 1); 
     } 
     full_write(STDERR_FILENO, end, strlen(end)); 
    free(bt_syms); 
} 
void foo() 
{ 
    print_backtrace(); 
} 

int main() 
{ 
    foo(); 
    return 0; 
} 
+0

의 중복 가능성 [자세한 역 추적을 얻을 방법] (http://stackoverflow.com/questions/5945775 (당신이 힘든 마음에 들지 않으면, 그냥이에 대한 계정을 만들려고하지 않음)/how-to-get-more-detailed-backtrace) – Nemo

+0

http://stackoverflow.com/questions/105659/how-can-one-grab-a-stack-trace-in-c –

답변

46

기호가 촬영을 동적 심볼 테이블로부터; -rdynamic 옵션을 gcc으로 설정해야 링커에 플래그를 전달하여 모두 기호가 테이블에 배치되도록합니다.

합니다 (GCC manualLink Options 페이지를 참조하십시오, 및/또는 glibc manualBacktraces 페이지입니다.)

+8

정적 인 기호에는 작동하지 않습니다. 'libunwind'는 @Nemo가 언급하고, 정적 함수에 대해 작동합니다. –

25

사용 addr2line command을 소스 코드 파일 이름 + 행 번호에 실행 주소를 매핑 할 수 있습니다. -f 옵션에 함수 이름도 지정하십시오.

또는 libunwind을 시도하십시오.

+3

addr2 행은 파일 이름과 행 번호를 출력에 포함하기 때문에 좋지만, 로더가 재배치하는 즉시 실패합니다. –

+0

... ASLR 재배치는 그 어느 때보 다 일반적입니다. –

+0

@ErwanLegrand : ASLR 이전에 필자는 재배치가 예측 가능하고 공유 객체의 주소에 대해서도 'addr2line'이 안정적으로 작동한다고 생각 했었습니다. 그렇습니다. 현대 플랫폼에서는 재배치 가능 객체의 실제로드 주소를 알아야합니다. 원칙적으로이 작업. – Nemo

9

Ian Lance Taylor의 우수한 Libbacktrace가이 문제를 해결합니다. 스택 해제를 처리하고 일반 ELF 심볼과 DWARF 디버깅 심볼을 모두 지원합니다.

Libbacktrace는 모든 기호를 내보낼 필요가 없으며 추한 것이고 ASLR은이를 깨뜨리지 않습니다.

원래 Libbacktrace는 GCC 배포판의 일부였습니다. 이제 독립 실행 형 버전이 Github에서 찾을 수 있습니다 :

상단의 대답은 버그 경우 RET == -1을 가지고 있으며, errno를 사용하면 다시 시도하지만 복사로 RET를 계산하지 말아야 EINTER입니다

https://github.com/ianlancetaylor/libbacktrace

1

static void full_write(int fd, const char *buf, size_t len) 
{ 
     while (len > 0) { 
       ssize_t ret = write(fd, buf, len); 

       if ((ret == -1) { 
         if (errno != EINTR)) 
           break; 
         //else 
         continue; 
       } 
       buf += (size_t) ret; 
       len -= (size_t) ret; 
     } 
}