gdb 를 활용한 segmentation fault 분석
Published:
gdb backtrace 의 필요성
실행 이미지에서 segmentation fault 가 날 경우, 어느 라인에서 에러가 생겼는지 추적하기가 쉽지 않다. 의심가는 라인 전, 후로 print를 하는 방법이 있겠지만 프로그램 전반적으로 호출되는 함수에서는 print를 너무 많이해야해서 비효율적이다. 이 때, gdb bt
를 사용할 경우, 추적이 수월하다!
gdb란?
GNU 에서 나온 디버거 프로그램
예제
예제로 두 인자를 받는 함수를 이용한다
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
void func4(int a, int b)
{
if (b>1000)
{
std::vector<double> a;
printf("%lf", a[101]);
}
printf("sum : %d\n", a + b);
}
void func3(int a, int b) { return func4(a, b); }
void func2(int a, int b) { return func3(a, b); }
void func1(int a, int b) { return func2(a, b); }
int main(int argc, char *argv[])
{
int a = atoi(argv[1]);
int b = atoi(argv[2]);
func1(a, b);
return 0;
}
gdb_exercise 라는 실행 파일 이름을 가지도록 CMakeList 를 구성한뒤에 정상 실행하면 아래와 같다.
project/build$ ./gdb_exercise 3 5
sum : 8
하지만 만약 두번째 인자가 1000 보다 클 때는 segmentation fault 가 날것이다. ( vector a 에는 101 번째 인자가 없기 때문에)
project/build$ ./gdb_exercise 3 3000
Segmentation fault (core dumped)
위와 같은 상황에서 gdb를 이용하여 Debugging 을 해본다.
먼저 argument가 있는 상황에서 gdb 실행은 아래 명령어와 같다.
gdb --args executablename arg1 arg2 arg3
위의 예제에 이를 적용하면 아래와 같이 적용할 수 있다
gdb --args ./gdb_exercise 3 3000
여기까지 했으면 gdb 실행 환경에 집입하게 된다 여기서 실행을 위해 run
명령어를 치면 마찬가지로 Segmentation fault 가 날 것이다.
(gdb) run
Program received signal SIGSEGV, Segmentation fault.
0x000000000040093a in func4(int, int) ()
보면 func4 에서 에러가 났음을 알수 있다.
함수 호출 순서를 보고 싶으면 bt
명령어를 치면 된다. bt
는 back trace 의 줄임말이다
(gdb) bt
#0 0x000000000040093a in func4(int, int) ()
#1 0x00000000004009cf in func3(int, int) ()
#2 0x00000000004009ee in func2(int, int) ()
#3 0x0000000000400a0d in func1(int, int) ()
#4 0x0000000000400a59 in main ()
이를 보면 스택에 쌓인 순서대로 함수의 호출 과정을 볼 수 있다. 따라서 이를 보면, main 에서 func1 -> func2 -> func3 -> func4 순서대로 불린 func4 에서 Segmentation fault 가 일어났음을 알 수 있다. (bt full
을 이용할 경우, Local 변수도 볼 수 있다)
정리
gdb --args executablename arg1 arg2 arg3
bt full