# 모든 함수의 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);
...
}