# 모든 함수의 Stack frame (call 규칙)에서 frame-pointer 를 최적화에 따른 비정규 frame 방식을 사용하지 않겠다는 의미 CFLAGS += -fno-omit-frame-pointer # 필수 # 코드를 재배치 가능한 형식으로 만들겠다는 의미 (만약 이 옵션으로 컴파일에 문제가 있다면 빼도 됩니다.) CFLAGS += -fPIC # 선택사항 # Thread 를 프로그램 내에서 사용한다면 다음과 같은 재진입성 향상 옵션을 추가하세요. CPPFLAGS += -D_REENTRANT # 선택사항 # 만약 64bit file size를 접근한다면 다음과 같은 호환 확장 옵션을 추가해볼 수 있습니다. CPPFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 # 선택사항 # 빌드 환경과 런타임 환경의 glibc 가 다를 수 있다면 glibc 호환성 향상 옵션을 사용하세요. CPPFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 # 선택사항 # 자신의 주소에 대한 심볼명을 동적으로 확인하기 위하여 필요 LDFLAGS += -rdynamic # 권장사항 (심볼명 dump를 원하면 필수사항) 위 option들은 Symbol명을 확인하기 위해서 필요합니다. 하지만 필수는 아닙니다. 위 옵션이 주어지지 않는다면 주소만 표시될 것이며 이를 addr2line 명령어로 심볼을 확인할 수도 있기 때문입니다.
#include <execinfo.h> void dump_backtrace(void) { /* IMPORTANT gcc need compile option "-fno-omit-frame-pointer" gcc optional linker option "-rdynamic" */ void *s_backtrace_buffer[16]; char **s_backtrace_symbols; int s_backtrace_size; int s_backtrace_index; s_backtrace_size = backtrace( (void **)(&s_backtrace_buffer[0]), (int)(sizeof(s_backtrace_buffer) / sizeof(void *)) ); if(s_backtrace_size <= 0) { s_backtrace_symbols = (char **)0; } else { s_backtrace_symbols = backtrace_symbols( (void * const *)(&s_backtrace_buffer[0]), s_backtrace_size ); } (void)fprintf(stderr, "backtrace() returned %d addresses\n", s_backtrace_size); for(s_backtrace_index = 0;s_backtrace_index < s_backtrace_size;s_backtrace_index++) { (void)fprintf( stderr, "%02d - %p - %s\n", s_backtrace_index + 1, s_backtrace_buffer[s_backtrace_index], (s_backtrace_symbols == ((char **)0)) ? "<unknown symbol>" : s_backtrace_symbols[s_backtrace_index] ); } free((void *)s_backtrace_symbols); }
#include <signal.h> void my_signal_handler(int s_signal) { switch(s_signal) { case SIGILL: case SIGABRT: case SIGBUS: case SIGSTKFLT: case SIGFPE: case SIGSEGV: dump_backtrace(); break; } signal(s_signal, my_signal_handler); /* 자기자신의 Signal 을 재귀적으로 처리하기 위해서 */ } int main(int s_argc, char **s_argv) { ... /* 주요 비정상 종료와 관련한 Signal에 handler를 등록합니다. */ signal(SIGILL, my_signal_handler); signal(SIGABRT, my_signal_handler); signal(SIGBUS, my_signal_handler); signal(SIGSTKFLT, my_signal_handler); signal(SIGFPE, my_signal_handler); signal(SIGSEGV, my_signal_handler); ... }