오늘은 ‘리눅스 디버거’인 GDB의 사용법에 대해 알아보자.
GDB는 코어 파일 분석 또는 프로세스 디버깅에 사용된다.
- Core 파일 분석 core file을 분석하기 위해서는 먼저 segmentation fault 발생 시 core file이 생성되도록 설정하여야 한다. core file은 현재 사용자에게 설정되어 있는 최대 core file 사이즈가 0보다 클 경우 core file 이 생성되는데, 이 값은 ulimit 명령을 통해 확인할 수 있다.
- ulimit : ulimit is admin access required Linux shell command which is used to see , set , or limit the resource usage of the current user . It is used to return the number of open file descriptors for each process . It is also used to set restrictions on the resources used by a process
- ulimit 은 위의 설명과 같이 사용자의 자원 또는 프로세스에 의해 사용되는 자원을 제한하거나 확인하기 위해 사용된다.
- ulimit [옵션] 값 (Centos, RHEL 기준)-a : 모든 제한사항 표시.-c:최대 코어 파일 크기-d:프로세스 데이터 세그먼트의 최대 크기-f:shell에 의해 만들어지는 최대 파일 사이즈-s:최대 스택 사이즈-p:파이프 사이즈-n:오픈 파일의 최대 수-u:오픈 파일의 최대 수-v:프로세스 데이터 세그먼트의 최대 수-v:최대 수
- 위와 같이 많은 옵션을 통해 여러 값을 설정할 수 있는데, 지금 필요한 것은 core file의 최대 사이즈를 확인하는 것이므로 아래와 같이 ulimit-a를 통해 core file의 최대 사이즈를 확인한다.현재 core file size가 0이므로 segmentation fault가 발생하더라도 core 파일이 생성되지 않는다. core file을 생성하기 위해서 다시 한번 ulimit 명령어로 core file size를 변경한다.변경 후 ulmit에서 다시 조회할 때 아래와 같이 core file size가 unlimited로 변경되었음을 확인할 수 있다.간신히 core file이 생성되도록 설정했기 때문에 실제로 core dump를 만들어 보도록 한다. 쉽게 Initialize가 아닌 string pointer를 참조하는 코드를 삽입했다.실행하면 segmentation fault 에러가 발생함을 확인할 수 있다.Red hat에서 테스트를 한 경우는 해달 폴더 아래에 core.xxx로 파일이 떨어졌는데, 현재 사용하고 있는 centOS는 core 파일명/파일형태/위치가 설정되어 있지 않거나/var/lib/systemd/coredump 경로에 lz4로 압축된 형태로 core dump가 생성되었다.이제 core dump를 gdb를 사용해서 분석해 보자.
- gdb [program or core dump file]을 사용하여 core file을 열면 아래와 같이 core dump가 gdb에 의해 열린다.이하의 gdb 명령에 의해 코어 디스크를 분석하는 것이,
- ● bt (많이 사용해!!!!!!!!) – call stack, backtrace- stack 정보를 나열, 반대로 추적 가능- full 옵션을 사용하면 더 자세히 제공
- ●file [파일의 절대경로] – 해당 파일의 정보를 불러온다. 리스트 명령으로 코드를 보기 위해서는 file 명령으로 파일 정보를 등록해야 한다.
- ● frame [framenumber] (자주사용!!!) bt에서 나온 코드블록 중 특정 frame 정보를 확인하기 위한 명령어
- ● list(많이 사용!!!) – stack의 소스 코드 표시하기 – frame에서 블럭 선택 후 list를 통해 해당 frame의 코드 확인 가능
- ● print [변수](다용!!!)-특정 변수의 값을 확인할 때 사용-frame, list와 함께 사용하면 특정 frame의 코드와 해당 코드에서의 실제 변수 중의 값을 확인할 수 있다.
- 위의 방식 등을 활용해 콜스택을 추적하고 에러의 원인을 찾아내면 된다.
- 실제 오류가 발생했을 경우 부장들의
- 2. Debugging 2-1. Debugging running process Debugging을 위해서는 우선적으로 compile의 경우 -g 옵션을 부여해야 한다. g옵션을 사용하면 gdb에 제공할 바이너리 정보를 생성한다.
- Debugging을 하는 방법 중에는 두 가지 방법이 있다. 현재 실행 중인 프로세스에 대해 디버깅을 하거나 프로그램을 gdb 내에서 실행하여 디버깅하는 방법이 있다.
- 1) 실행 중인 프로그램 Debugging 쉬운 테스트를 위해 아래와 같이 5초에 한번 cycle 정보를 찍는 코드를 만들었다.이를 실행한 후 ps 명령어를 통해 pid를 확인한다.pid를 확인했으면 아래의 명령어를 통해 gdb를 실행한다.
- gdb-p [pid] 또는 gdb를 실행한 후(gdb) attach [pid] 명령을 실행하면, 위 화면과 같이 gdb가 해당 process의 control을 가져오는 것을 볼 수 있다(control을 가져온 상태이므로, 해당 process는 일시 정지된 상태이다).
- Debugging 이 필요한 코드에 break 명령을 통해 break point를 파악한다.
- (gdb) b [line or file : line] 10 라인에 break point가 들어가는 것을 확인할 수 있다.
- 그 후 일시 정지된 프로세스를 다시 실행한다. 이미 구동중이었던 프로그램이기 때문에 run을 할 필요가 없고, continue 명령에 의해서 일시정지된 부분부터 재시작한다.
- (gdb) continue continue 와 동시에 process 가 다시 실행되며, 앞서 설정한 break point 에 break 이 있음을 확인할 수 있다.
- 이후의 단계 또는 n에 다음 코드로 갈 수 있지만, 단계가 n에는 이하와 같은 차이가 있다.(gdb) step -> 다음 라인 확인 만약 함수라면 함수 내부로 들어간다.(gdb) n -> 함수에 들어가지 않고 다음 라인을 확인한다.
- n에서 다음 라인으로 이행하고 print에서 변수가 가지는 실제 값을 확인할 수 있다. 만약 기본 데이터 타입이 아닌 자료형을 사용할 경우, 해당 자료형에서 .data()와 같이 c++ 자료형을 리턴하는 함수가 있다면 gdb 상에서 해당 함수를 다음과 같이 실행하여 값을 확인할 수 있다.
- ( gdb ) print var . data ( )
- 2-2.Debugging program, 이번에는 실행 중인 프로그램이 아니라 프로그램을 실행하고 디버깅을 해보려고 한다. 2-1로 생성한 프로그램을 이번에는 gdb로 실행시키고 디버깅을 해보려고, 아래의 명령어를 사용해서 gdb를 해당 프로그램과 연결한다.
- gdb [ program ]
- 이전에는 이미 실행 중인 프로세스에 대한 디버깅이었지만, 이번에는 아직 실행하지 않은 프로그램에 대한 디버깅이므로, run 명령을 통해 연결된 프로그램을 실행시킨다.
- ( gdb ) run
- run 명령어 실행 시 아래와 같이 프로그램이 실행되는 것을 확인할 수 있다. 단, 주의해야 할 점은 run 명령어를 실행하기 전에 원하는 break point를 걸고 시작해야 debugging이 가능하다.지금까지의 내용은 정말 간단한 것이므로, 보다 복잡한 디버깅은 이하의 gdb 명령어를 참조하여 하면 된다.
- 참조: https://blog.naver.com/euclid1001/40179341273