backtrace
는 프로그램의 실행 중 호출된 함수들의 스택을 추적하여 오류나 크래시 발생 시 해당 문제가 발생한 위치와 그 경로를 파악하는 데 유용한 도구이다 .주로 디버깅 시 사용되며, 특히 프로그램이 비정상 종료되었을 때 그 원인을 추적하는 데 도움을 준다. 이 글에서는 C/C++ 프로그램에서 backtrace
사용 방법에 대해 알아본다.
GNU backtrace()
함수 사용
GNU C 라이브러리는 backtrace()
와 backtrace_symbols()
함수를 제공하여 백트레이스를 쉽게 생성할 수 있다. 이 함수들은 표준 라이브러리에 포함되어 있어 별도의 설치가 필요하지 않고 사용할 수 있다.
예제 코드
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
void print_backtrace() {
void *array[10];
size_t size;
char **strings;
size_t i;
// 백트레이스 생성
size = backtrace(array, 10);
// 백트레이스의 심볼을 변환
strings = backtrace_symbols(array, size);
printf("Obtained %zu stack frames.\n", size);
for (i = 0; i < size; i++) {
printf("%s\n", strings[i]);
}
free(strings);
}
void function2() {
print_backtrace();
}
void function1() {
function2();
}
int main(int argc, char *argv[]) {
function1();
return 0;
}
컴파일 및 실행
gcc -o backtrace_example backtrace_example.c -rdynamic
./backtrace_example
Obtained 6 stack frames.
./backtrace_example(print_backtrace+0x2c) [0x55fc0681b215]
./backtrace_example(function2+0x12) [0x55fc0681b2b7]
./backtrace_example(function1+0x12) [0x55fc0681b2cc]
./backtrace_example(main+0x1d) [0x55fc0681b2ec]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x7f9077e77083]
./backtrace_example(_start+0x2e) [0x55fc0681b12e]
gdb
를 사용한 백트레이스
gdb
(GNU Debugger)는 C/C++ 프로그램의 디버깅을 위한 강력한 도구로, 실행 중 또는 프로그램이 크래시한 이후에 백트레이스를 생성할 수 있다.
다음은 gdb
를 사용하여 백트레이스를 확인하는 방법이다.
1. 프로그램에 디버그 심볼을 포함하여 컴파일
gcc -g -o my_program my_program.c
2. gdb
로 프로그램 실행
gdb ./my_program
3. gdb
내에서 프로그램을 실행
(gdb) run
4. 프로그램이 원하는 위치에서 중단된 상태에서 backtrace
실행
(gdb) backtrace
출력 예시
#0 0x00007ffff7a4d527 in __GI_raise (sig=sig@entry=0x6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff7a4e9aa in __GI_abort () at abort.c:89
#2 0x0000555555554719 in function2 () at my_program.c:15
#3 0x0000555555554739 in function1 () at my_program.c:19
#4 0x0000555555554749 in main (argc=1, argv=0x7fffffffe2b8) at my_program.c:23
SIGSEGV와 같은 시그널 처리 시 백트레이스 생성
프로그램이 SIGSEGV와 같은 시그널에 의해 크래쉬가 발생 했을 때 자동으로 백트레이스를 생성하면 디버깅 하는데 도움이 된다.
예제
#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void handle_sigsegv(int sig) {
void *array[10];
size_t size;
// 백트레이스 생성
size = backtrace(array, 10);
// 백트레이스 출력
fprintf(stderr, "Error: signal %d:\n", sig);
backtrace_symbols_fd(array, size, STDERR_FILENO);
exit(1);
}
int main() {
signal(SIGSEGV, handle_sigsegv);
// 잘못된 메모리 참조 (Segmentation Fault 유도)
int *p = NULL;
*p = 0;
return 0;
}
컴파일 및 실행
gcc -o sigsegv_example sigsegv_example.c -rdynamic
./sigsegv_example
Error: signal 11:
./sigsegv_example(handle_sigsegv+0x2f)[0x55e1625e71f8]
/lib/x86_64-linux-gnu/libc.so.6(+0x43090)[0x7fadb6017090]
./sigsegv_example(main+0x29)[0x55e1625e7268]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x7fadb5ff8083]
./sigsegv_example(_start+0x2e)[0x55e1625e710e]