본문 바로가기

[☩ OS Tip ☩]

GDB 사용법

GDB 사용법

 Debugging이란

Debugging bug, , 컴퓨터 프로그램 상의 논리적 오류를 찾아 해결하는 과정이다.

 Debugging 방법

프로그램 소스를 눈으로 따라가며, 머리로 실행시켜 논리적 오류를 찾아낸다. 이것은 프로그래머로 하여금 정말 많은 에너지를 소비하게 하며, 자신이 작성한 프로그램인 경우 선입견으로 인해 오류를 찾아내기 힘든 경우가 많다.

프로그램의 중간 중간에 printf 사용하여 실행 상태를 출력하도록 한다. 이렇게 함으로써 변수에 잘못된 값이 들어가는지 여부를 사람이 직접 계산하는 것보다 쉽게 있다.

  
Debugging tool (, gdb, dbx, xdbx ) 이용한다. Debugging tool들은 프로그램이 실행 중일 , 변수들의 값이나 수행되는 statement 보여주며, 필요에 따라 변수 값을 변경하여 실험을 있도록 해준다.

 gdb (GNU Debugger)

gdb C, C++, Modula-2 구현된 프로그램을 디버그할  있는 도구이다. 버그를 잡는  돕기 위해 gdb 
다음과 같은 작업들을 가능하게 한다
.


 
프로그램의 행동에 영향을 있는 각종 조건을 설정한 , 프로그램을 시작한다
.





특정 조건을 만나면 프로그램을 정지시킨다.



프로그램이 정지됐을 무슨 일이 일어났는지 검사한다.




프로그램
내부 설정을 바꾸어서 버그를 수정함으로써 다른 버그를 계속 찾아나간다.

 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 실행하여 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 [N  COND] - breakpoint N에서 COND true 때만 멈추도록 명시한다.

검사할
파일 (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 사용 예제

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 ./

 bug.c 소스 코드는 다음과 같다.

#include <stdio.h>

int score[5];
int sum(int cnt)

{

   int i;
   int sum;
   for(i = 0; i < cnt; i++)
   sum += score[i];
   return sum;

}
  int main()

{

   int cnt=0;
   printf("input scores. input -1 to finish.\n");

   while(1)
   {

      printf("score%d? ", cnt+1);
      scanf("%d", score[cnt]);
      if(score[cnt] == -1)

         break;

      cnt++;

   }
    printf("%d scores read.\n", cnt);
    printf("--- result ---\n");
    printf("sum: %d   avg: %d\n", sum(cnt), sum(cnt)/cnt);
    return 0;

}

소스 코드는 임의의 개수의 점수를 입력 받아 총점과 평균을 출력해 주는 프로그램이다. 이를 컴파일하여 실행 해보면 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.

Reading symbols from /usr/shlib/libc.so...done.

#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으로 초기화 되도록 소스를 고친다.