GDB 사용법
Debugging은 bug, 즉, 컴퓨터 프로그램 상의 논리적 오류를 찾아 해결하는 과정이다.
프로그램 소스를 눈으로 따라가며, 머리로 실행시켜 논리적 오류를 찾아낸다. 이것은 프로그래머로 하여금 정말 많은 에너지를 소비하게 하며, 자신이 작성한 프로그램인 경우 선입견으로 인해 오류를 찾아내기 힘든 경우가 많다.
프로그램의 중간 중간에 ‘printf’를 사용하여 실행 상태를 출력하도록 한다. 이렇게 함으로써 변수에 잘못된 값이 들어가는지 여부를 사람이 직접 계산하는 것보다 좀 더 쉽게 알 수 있다.
Debugging tool (예, gdb, dbx, xdbx 등)을 이용한다. Debugging tool들은 프로그램이 실행 중일 때, 변수들의 값이나 수행되는 statement을 보여주며, 필요에 따라 변수 값을 변경하여 실험을 해 볼 수 있도록 해준다.
gdb는 C, C++, Modula-2로 구현된 프로그램을 디버그할 수 있는 도구이다. 버그를 잡는 걸 돕기 위해 gdb는
다음과 같은 작업들을 가능하게 한다.
프로그램의 행동에 영향을 줄 수 있는 각종 조건을 설정한 후, 프로그램을 시작한다.
특정 조건을 만나면 프로그램을 정지시킨다.
프로그램이 정지됐을 때 무슨 일이 일어났는지 검사한다.
프로그램 내부 설정을 바꾸어서 버그를 수정함으로써 다른 버그를 계속 찾아나간다.
$ gdb [prog [core|procID]]
prog: 디버깅할 프로그램
core: 프로그램 실행 중에 “segmentation fault” 등의 오류에 의해 비정상적으로 종료할 때 생성되는 파일로, 그때의 시스템의 내부 상태를 그대로 저장해 놓은 것이다. 이 파일을 인자로 주면 실행파일이 비정상적으로 종료된 곳이 소스코드의 어느 부분인지를 표시해 준다.
procID: 이미 실행중인 프로그램을 debugging하려면 해당 process의 id (PID)를 주면 되는데, 이 때 주의 할 것은 PID와 같은 이름의 파일이 있을 경우 gdb가 core파일로 여기게 되는 점이다.
주의: Debugging하고자 하는 실행파일은 gcc에서 –g 옵션을 주어 compile함으로써 gdb가 필요로 하는 부가 정보들이 추가된 것을 사용해야 제대로 debugging을 수행할 수 있다.
gdb를 실행하여 gdb prompt ‘(gdb) ’가 표시된 상태에서 gdb 명령어를 사용하여 디버깅을 진행한다.
참고: class와 command의 축약형도 지원된다. (예, ‘run’명령어를 축약형 ‘r’로 대신할 수 있다.)
도움말 (help)
help [class|command]
도움말, 명령어 분류 목록 출력, 해당 class에 속한 명령어 목록 표시, 해당 command에 대한 도움말 표시
프로그램 수행 (running)
kill
디버깅 중인 프로그램의 실행을 강제로 종료시킨다.
run [args]
디버깅할 프로그램의 수행을 시작한다. 프로그램 실행에 필요한 argument (args)를 지정할 수 있다. args를 지정하지 않으면 바로 이전의 run실행이나 “set args”명령에 의해 미리 주어진 argument를 사용한다. 입출력 방향 재지정 (“>”, “<”, “>>”)을 사용할 수 있다.
set args [args]
프로그램이 시작될 때, 디버깅할 프로그램에 전달할 argument를 설정한다.
next [n]
멈춰진 프로그램에서 프로그램의 다음 n(default=1)개의 문장을 수행한 후 멈춘다. 함수일 경우, 함수 전체를 수행한다.
step [n]
멈춰진 프로그램에서 프로그램의 다음 n(default=1)개의 문장을 수행한 후 멈춘다. 함수일 경우, 함수 내부로 들어가 한 문장씩 수행한다.
continue [n]
시그널(Ctrl-C)이나 breakpoint 등에 의해 멈춰진 프로그램의 수행을 계속한다. n이 지정될 경우, 이후 n-1번의 breakpoint는 무시하고, n번째 breakpoint에서 수행을 멈춘다.
until [[file:]n|function]
프로그램이 현재 라인보다 큰 라인이나 또는 지정된 라인이나 어드레스 또는 함수에 도달할 때까지 수행한다(break 명령과 동일한 argument). 또한, 현재 stack frame을 빠져나올 때도 멈춘다. loop를 지날 때, 첫번째 loop수행에서는 next명령과 동일하지만 두번째 loop수행부터는 그 loop를 벗어날 때까지 멈추지 않는다.
스택 검사 (stack)
스택은 스택 프레임으로 구성된다. gdb는 스택 프레임에 번호를 지정하는데, 가장 안쪽에 있는(현재 실행중인) 프레임에 대해 0번부터 번호를 부여한다. gdb는 항상 한 프레임을 선택된 프레임으로 간주하며, 선택된 프레임에 대하여 변수 값 보기가 이루어진다. 아래 명령어들에서 숫자나 어드레스를 사용하여 다른 프레임을 지정할 수도 있다.
bt (또는 backtrace 또는 where) [[-]N]
모든 스택 프레임이나 가장 안쪽에 있는 N개의 프레임에 대한 backtrace를 출력한다. argument가 음수(-N)일 때, 가장 바깥쪽에 있는 N개의 프레임을 출력한다.
frame [N]
스택 프레임을 선택하고 출력한다. N은 선택할 프레임 번호(혹은 프레임의 주소)를 가리킨다. Argument가 없으면 현재 선택된 프레임을 출력한다.
up [N]
현재 선택된 프레임을 호출한 스택 프레임 (caller)을 선택하고 출력한다. N은 몇 개의 프레임 위로 올라가야 할지를 말해준다.
down [N]
현재 선택된 프레임에 의해 호출된 스택 프레임 (callee)을 선택하고 출력한다. N은 몇 개의 프레임 아래로 내려가야 할지를 말해준다.
return [rvalue]
선택된 스택 프레임으로 하여금 호출자 (caller)에게로 리턴하게 한다. 실행은 현재 선택된 것보다 위에 있는 프레임 (caller)에서 계속될 것이다. rvalue는 리턴 값을 지정한다.
set variable [variable] = [exp]
[variable]의 값을 [exp] 계산 결과로 대치한다. set variable 대신 set만 써도 된다
데이터 검사 (data)
whatis EXP - expression! EXP의 data 타입을 출력한다.
ptype TYPE - 타입 TYPE의 정의를 출력한다.
print [EXP]
expression! EXP의 값을 출력한다. EXP에 사용될 수 있는 변수는 선택된 프레임에 있는 변수이거나 전역 변수이다.
printf [“format string”, arg1, arg2, arg3, ..., argn] - printf 형식으로 출력한다.
display [EXP] - expression! EXP의 값을 프로그램이 멈출 때마다 출력한다.
delete display (또는 undisplay) [N …]
프로그램이 정지할 때마다 출력되는 몇몇 expression!을 취소한다. N은 취소할 expression!의 번호를 지정한다. Argument가 없으면 모든 자동 출력 expression!을 취소한다.
disable display [N …]
프로그램이 정지할 때마다 출력되는 몇몇 expression!을 disable한다. N은 disable할 expression!의 번호를 지정한다. Argument가 없으면 모든 자동 출력 expression!을 disable한다.
enable display [N …]
프로그램이 정지할 때마다 출력되는 몇몇 expression!을 enable한다. N은 enable할 expression!의 번호를 지정한다. Argument가 없으면 모든 자동 출력 expression!을 enable한다.
특정 지점에서 프로그램 정지 (breakpoints)
watch [EXP]
expression! EXP에 대한 watchpoint를 설정한다. EXP의 값이 변할 때마다 프로그램의 수행을 멈춘다.
break [[file:]n|function]
특정 라인(n)이나 함수(function)에 breakpoint를 설정한다. Argument가 없으면 현재 수행 위치에 breakpoint를 설정한다. 프로그램이 수행 중에 지정된 breakpoint에 도착하면 수행을 멈춘다.
clear [[file:]n|function]
특정 라인(n)이나 함수(function)에 설정된 breakpoint를 제거한다. Argument가 없으면 현재 수행 위치에 설정된 모든 breakpoint를 제거한다.
delete [N …]
몇몇 breakpoint나 자동 출력 expression!을 제거한다. N은 제거할 breakpoint 번호를 가리킨다. Argument가 없으면 모든 breakpoint를 제거한다.
disable [N …]
몇몇 breakpoint를 disable시킨다. N은 disable할 breakpoint를 가리킨다. Argument가 없으면 모든 breakpoint를 disable시킨다. disable된 breakpoint는 enable에 의해 다시 동작하도록 할 수 있다.
enable [N …] - 몇몇 breakpoint를 enable시킨다. N은 enable할 breakpoint를 가리킨다.
condition [
검사할 파일 (files)
cd [DIR] - 작업 디렉토리를 DIR로 설정한다
pwd - 작업 디렉토리를 출력한다.
core-file [FILE] - FILE을 core dump 파일로 사용한다.
file [FILE] - FILE을 디버깅할 프로그램으로 사용한다.
list [[file:]n|function][, [file:]n|function]
지정된 함수나 라인 앞뒤의 11라인을 출력한다. 콤마로 분리된 두 개의 Argument는 출력할 시작 라인과 끝 라인을 가리킨다. Argument가 없으면 앞서 출력된 라인 이후의 10개 라인을 출력한다. “list –”는 앞서 출력된 라인 이전의 10개 라인을 출력한다.
상태 조회 (status)
info - 디버깅 중인 프로그램에 대한 여러가지를 보여 주기 위한 포괄적인 명령어
info breakpoints (또는 info watchpoints) [N]
설정된 breakpoint의 상태를 보여준다. N은 특정 breakpoint 번호를 가리킨다. Argument가 없으면 모든 breakpoint의 상태를 보여 준다.
info args - 현재 스택 프레임의 인자 변수를 보여준다.
info display - 프로그램이 멈출 때 출력할 expression!들을 보여준다.
지원도구 (support)
help [class|command]
도움말, 명령어 분류 목록 출력, 해당 class에 속한 명령어 목록 표시, 해당 command에 대한 도움말 표시
quit - gdb를 종료한다.
make [args] - ‘make’를 실행한다.
gdb 사용법을 익히기 위해 bug가 있는 간단한 프로그램을 gdb를 사용하여 디버깅해 보자. 먼저, /afs/p/class/cse/yjsuh/csed103F2004/lab/lecture_note/bug.c를 각자의 디렉토리로 복사한다.
$ mkdir debug; cd debug
$ cp /afs/p/class/cse/yjsuh/csed103F2004/lab/lecture_note/bug.c ./
#include <stdio.h> int score[5]; { int i; } { int cnt=0; while(1) printf("score%d? ", cnt+1); break; cnt++; } } |
본 소스 코드는 임의의 개수의 점수를 입력 받아 총점과 평균을 출력해 주는 프로그램이다. 이를 컴파일하여 실행 해보면 segmentation fault 오류가 나며 core파일이 생성되며 종료된다. 생성된 core 파일을 바탕으로 디버깅을 한다. 이때 컴파일시 –g 옵션을 써주어야 디버깅 정보를 볼 수 있다. 굵은 글씨가 사용자가 입력한 부분이다.
vision/endovert ~/gdb {298} gcc -g bug.c vision/endovert ~/gdb {299} a.out input scores. input -1 to finish. score1? 100 Segmentation fault (core dumped) vision/endovert ~/gdb {300} gdb GNU gdb 5.0 Copyright 2000 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "alpha-dec-osf4.0d". (gdb) file a.out Reading symbols from a.out...done. (gdb) core core Core was generated by `a.out'. Program terminated with signal 11, Segmentation fault. #0 0x3ff800e1e4c in _doscan () from /usr/shlib/libc.so (gdb) bt #0 0x3ff800e1e4c in _doscan () from /usr/shlib/libc.so #1 0x3ff8018ea80 in scanf () from /usr/shlib/libc.so #2 0x120001384 in main () at bug.c:26 (gdb) list 26 21 22 printf("input scores. input -1 to finish.\n"); 23 while(1) 24 { 25 printf("score%d? ", cnt+1); 26 scanf("%d", score[cnt]); 27 if(score[cnt] == -1) 28 break; 29 cnt++; 30 } (gdb) quit vision/endovert ~/gdb {301} |
bt결과를 보면 26번째 행에서 core dump가 일어난 것을 볼 수 있다. 26번 행을 보면 scanf의 인자로 넣은 변수 score[cnt] 앞에 &가 빠졌음을 알 수 있다. 고쳐서 다시 컴파일 해본다. 이번엔 결과값이 이상하게 나온다. 다시 gdb를 사용하여 다시 디버깅해본다.
vision/endovert ~/gdb {303} gcc -g bug.c vision/endovert ~/gdb {304} a.out input scores. input -1 to finish. score1? 100 score2? 100 score3? 100 score4? -1 3 scores read. --- result --- sum: 301 avg: 200 vision/endovert ~/gdb {305} gdb a.out GNU gdb 5.0 Copyright 2000 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "alpha-dec-osf4.0d"... (gdb) break sum Breakpoint 1 at 0x120001268: file bug.c, line 7. (gdb) run Starting program: /afs/postech.ac.kr/home/std/endovert/gdb/a.out input scores. input -1 to finish. score1? 50 score2? 50 score3? 50 score4? -1 3 scores read. --- result --- Breakpoint 1, sum (cnt=0) at bug.c:7 7 { (gdb) l 2 3 int score[5]; 4 5 6 int sum(int cnt) 7 { 8 int i; 9 int sum; 10 11 for(i = 0; i < cnt; i++) (gdb) print sum $1 = 1 (gdb) next 11 for(i = 0; i < cnt; i++) (gdb) step 12 sum += score[i]; (gdb) display sum 1: sum = 1 (gdb) s 11 for(i = 0; i < cnt; i++) 1: sum = 51 (gdb) s 12 sum += score[i]; 1: sum = 51 (gdb) s 11 for(i = 0; i < cnt; i++) 1: sum = 101 (gdb) set sum = 100 (gdb) print sum $2 = 100 (gdb) s 12 sum += score[i]; 1: sum = 100 (gdb) s 11 for(i = 0; i < cnt; i++) 1: sum = 150 (gdb) s 14 return sum; 1: sum = 150 (gdb) s 15 } 1: sum = 150 (gdb) info display Auto-display expression!s now in effect: Num Enb Expression! 1: y sum (gdb) delete display 1 (gdb) continue Continuing. Breakpoint 1, sum (cnt=3) at bug.c:7 7 { (gdb) bt #0 sum (cnt=3) at bug.c:7 #1 0x120001414 in main () at bug.c:35 (gdb) l 35 30 } 31 32 printf("%d scores read.\n", cnt); 33 34 printf("--- result ---\n"); 35 printf("sum: %d avg: %d\n", sum(cnt), sum(cnt)/cnt); 36 37 return 0; 38 } 39 (gdb) s 11 for(i = 0; i < cnt; i++) (gdb) print sum $3 = 150 (gdb) p i $4 = 3 (gdb) s 12 sum += score[i]; (gdb) print sum $5 = 150 (gdb) print i $6 = 0 (gdb) return 150 Make sum return now? (y or n) y #0 0x120001414 in main () at bug.c:35 35 printf("sum: %d avg: %d\n", sum(cnt), sum(cnt)/cnt); (gdb) c Continuing. sum: 150 avg: 50 Program exited normally. (gdb) info break Num Type Disp Enb Address What 1 breakpoint keep y 0x120001268 in sum at bug.c:7 breakpoint already hit 2 times (gdb) delete 1 (gdb) info break No breakpoints or watchpoints. (gdb) q vision/endovert ~/gdb {306} |
합을 계산하는 sum함수에 breakpoint를 걸고 실행 시켜보면 초기의 sum의 값이 0이 아닌 다른 값 (이 경우 1)이 나옴을 볼 수 있다. sum값이 0으로 초기화 되도록 소스를 고친다.
'[☩ OS Tip ☩]' 카테고리의 다른 글
리눅스 관리자가 알아야할 50가지 !! (0) | 2008.02.04 |
---|---|
Linux에서 Windows 공유 폴더 접근하기 (0) | 2008.02.04 |
Ubuntu 패키지 관리 및 APM 설치 (1) | 2008.02.04 |
리눅스 root 비번을 모를때 (0) | 2008.02.04 |
Linux 파티션 설정 용량 (0) | 2008.02.04 |