노무현 대통령 배너


2006. 7. 20. 16:59

DDD를 이용한 디버깅

출처: http://www.linuxfocus.org/Korean/January1998/article20.html

DDD를 이용한 디버깅

요약: ddd는 환상적인 그래픽환경의 디버거입니다. 이 글에서 글쓴이는 ddd의 기본기능들에 대해 설명하고 있습니다.




들어가는 글

이 글에서는 디버거를 사용해 보지 못한 사람을 위해서 디버거란 무엇인지, 디버거의 개념에 대해서 설명하고, 또 사용하기 쉬운 GUI 환경의 디버거- DDD를 소개한다. gdb와 같은 훌륭한 디버거도 있으나, 이 글을 교육적인 목적으로 쓰였으므로, 간단한 디버거를 골랐다.

디버거란 무엇인가?

"옛날에 한 프로그래머가 살았는데 버그를 잡을 때면 언제나 다음과 같은 code를 삽입하였다.

/*Code*/
(...)
loop
change_a_variable;
show_value_of_variable;
end_loop
(...)

그는 프로그램의 실행 중에 변수가 어떤 값을 갖는지 알아내기 위하여 언제나 위와 같은 코드를 여러군데 삽입해야 했다. 이는 매우 어려운 작업이었고, 소스 코드를 작성하는 시간보다, 버그를 잡는 시간이 두배나 더 걸렸다. "

누구나 위와 같은 경우를 한번쯤은 겪어봤을 것이다. 보통 프로그램에는 버그가 있기 마련인데, 이런 경우 보통 소스 코드의 이곳저곳을 바꿔보다가 그래도 안되면 , " 컴파일러에 문제가 있나 보지?" 하고는 넘어가고 만다. 이 때 버그를 쉽게 찾게 해주는 디버거를 이용해보자.

디버거는 프로그램의 실행을 제어할 수 있게 하고, 이런 식으로 우리는 프로그램의 실행 중에, 변수의 값이 얼마인지, 변수의 선언은 어떻게 되었는지, 특정한 조건에서 어떤 일이 발생하는지 등등 모든 것을 조사할 수 있다. 위의 설명이 조금 부족하다면 계속 글을 읽어 가면서 이해를 하도록 하자.

위의 이야기의 주인공이 "spy"라는 디버거를 이용하면 어떤지 보자.

jose# spy my_program

위처럼 "spy"를 실행시키고, 프로그래머는 다음과 같은 일을 할 수가 있다.

spy > "프로그램을 50 번째 줄까지 실행시켜라"
spy > "변수 X의 값이 얼마인지 출력하라"
spy > "변수 X의 type은 무엇인가?"

이해력이 빠른 프로그래머라면, 위와 같은 식으로 어떤한 원인에서 버그가 생겼는지 쉽게 찾을 수 있을 것이다.

"spy"는 프로그램의 실행 중에 변수의 값과 형식등을 알려주기 때문에 매우 유용하다. 그리고, 이런한 일은 디버거의 가장 필수적인 일이다.

주의 !!. 프로그램을 디버깅하기 위해서는 컴파일을 할 때 -g라는 옵션을 꼭!! 붙여 줘야 한다.

리눅스에는 GDB(GNU 소스수준의 디버거/"The GNU Source-Level Debugger")라는 디버거가 있다. (물론 다른 플랫폼에도 있다.) GNU General Public License를 따르고 있고, 무료로 사용할 수 있다. C, C++, Modula-2와 Assemler로 작성된 프로그램을 디버깅할 수 있다.

대부분의 리눅스 배포판에는 기본적으로 gdb를 포함하고 있다. 만약 없다면 다른 리눅스 배포판을 찾아 보던지, 아니면 인터넷에서 구하기 바란다.

소스 코드를 /usr/src에 깔았다면, /usr/src/gdb-4.xxxx/gdb로 가서 ./configure를 입력하고, doc이란 디렉터리로 가서, gdb에 대한 문서를 만들면 된다. "make gdb.dvi; make refcard.dvi"라고 입력하면 된다. 이 파일들은 리눅스 상에서 쉽게 읽을 수 있고, 프린트 할 수 있다.

DDD란 무엇인가.?

gdb에 대한 설명을 계속하기 보다는 이젠 초보자가 쉽게 쓸 수 있고, 그래픽컬한 환경을 제공하는 DDD( Display Data Debugger)에 대하여 알아 보자.

DDD는 일반적으로 다른 디버거보다 사용하는데 편리한 인터페이스를 제공하고, 또 디버깅을 하는데 필요한 환경을 손쉽게 설정할 수 있다. 하지만, 디버거는 기본적으로 gdb를 사용하고, 인터페이스만을 제공한다는 점을 명심해야한다. 따라서 DDD는 gdb가 꼭 있어야만 한다. gdb말고도, dbx나 xdb, jdb를 이용할 수도 있다.

DDD의 소스는 http://www.cs.tu-bs.de/softech/ddd/에서 구할 수 있다. 물론 RedHat 사용자는 rpm 패키지로도 구할 수 있다. DDD에는 두 가지 버전이 있다. 하나는 Motif의 동적 라이브러리를 이용하는 버전이고, 다른 하나는 정적 라이브러리를 이용하는 것이다. 정적 라이브러리를 이용한 버전은 자신의 리눅스에 Motif가 설치되어 있지 않는 사용자를 위한 버전이다.

Motif의 클론(clone)으로 무료로 사용할 수 있는 Lesstif를 이용해서도 컴파일이 가능한데, 이에 대한 설명은 하지 않기로 한다. 관심있는 사람은 http://www.lesstif.org를 찾아보기 바란다. 예전에 DDD는 lesstif 0.75에서 컴파일이 성공했었다. lesstif에 대한 것은 위의 싸이트를 찾아가기 바란다.

ddd를 실행 시키면 다음과 같은 화면이 보인다.(큰 그림을 보려면 마우스로 클릭하세요.)


그림 1. ddd의 기본 화면

DDD를 실행시키는 방법에는 세 가지가 있다. 첫번째 방법은 위에서 SPY이 이름붙인 디버거처럼 사용하는 것이다. 다른 두 방법은 다음과 같다.

ddd core
ddd

"core"라는 파일은 프로그램의 실행 중에 문제가 있을 때마다 생성되는 파일인데 프로그램에 대한 많은 정보를 담고 있다. 만약 여러분의 시스템이 코어덤프(core dump)를 만들지 않는다면 코어(core)에 관련된 환경 변수를 확인하여 보아라. ('ulimit -a'는 모든 것들을 보여주고, 'ulimit -c '는 최대 크기나, 다른 값들을 보여 준다.)

process_id는 프로그램이 실행 되고 있는 중간에도 디버깅을 할 수 있게 해준다.

DDD의 그래픽 환경은 프로그램을 실행 시키는데 다양한 방법을 제공한다. 다양한 방법을 여기서 설명할 수는 없고, 가장 간단한 방법만을 설명할 것이다. 또 DDD 실행 화면 중 가장 밑의 창(디버거의 콘솔/"Debugger console")에는 ddd에 의해서 실행되는 일들이 보여진다. 또 이 창은 gdb의 명령어를 배우는데도 유용하게 쓰일 수 있다.

DDD의 그래픽 환경

그림 1을 보면 기본 창이 세 부분으로 나워져 있는 것을 알 수 있다. 가장 밑의 창은 디버거 콘솔(Debugger Console)이다(위의 예는 gdb이다). 이 창에 gdb의 명령을 직접 입력할 수 있다. 가운데 창은 프로그램의 소스 코드를 보여 준다. 맨 위의 창은 프로그램의 변수나 객체를 그래픽적으로 보여준다. 또, 둥둥떠다니는 창인 툴바는 ddd의 명령을 실행시키거나 제어하는 창이다.

부가적으로 실행할 프로그램에 대한 실행 창과, 소스 코드를 에디트할 수 있는 창이 있는데 이들은 선택적으로 띄울 수 있다.

ddd는 사용자에게 많은 도움말을 제공한다. 예를 들어 마우스의 커서가 변수 위에 놓여지거나 버튼 위에 놓여지게 되면, 적절한 풍선 도움말이 뜬다. 또, 창의 가장 밑 테두리에는 현재 실행 중인 명령어와 그의 상태를 보여 준다. 팝업 메뉴의 오른 쪽에는 "help" 메뉴가 있다. F1 키를 눌러도 자세한 도움말을 볼 수 있다. 또한 맨 밑의 창에서 "help"라고 치거나, "help 명령어(command_name)"라고 치면, 자세한 정보를 볼 수 있다.

기본적으로 하나의 Frame에 세개의 창이 존재하는 모습인데, "Preference" 메뉴을 이용하여 원하는 모양으로 분리시킬 수도 있다.


Figure 2. File 메뉴에 대한 도움말

가장 밑에 있는 창 부터 시작하자

맨 밑에 있는 창인 "Debugger Console"이 우리가 디버깅을 할 때 처음으로 할 부분이다. gdb를 이미 사용해 본 적이 있는 사용자라면, 이 창에서 쉽게 ddd를 이용할 수 있을 것이다. ddd에 명령을 내리면서 어떤 일이 일어 났는지에 대해서도 이 창을 통해 쉽게 알 수 있다. 지금까지 사용한 명령어를 보려면 "Commands -> Command History" 메뉴를 이용하면 된다. DDD에 대해서 자세히 알고자 할 경우는 DDD를 설치할 때 같이 딸려오는 문서를 살펴보기 바란다. 이 글에서는 몇가지 간단한 일을 해 볼 것이다.

일반적인 디버깅

"File" 메뉴에서 디버깅을 할 프로그램의 소스 코드를 읽어온다. 그러면 창에 소스 코드가 보일 것이다.소스 코드를 보면서 변수의 값이나 형식 등을 알 수 있다.

프로그램이 돌아가는 모습은 실행 창("Option -> Run in Execution Window")나 debugger console에서 확인할 수 있다. debugger console에서는 GUI 라이브러리를 이용해서 만든 프로그램은 실행시킬 수가 없다. 소스 코드에서 마우스를 변수 위에 가져다 놓으면, 현재 변수의 값을 알 수가 있다. 아니면, 변수의 위에 마우스를 놓은 후, 마우스의 오른쪽 버튼을 누르면 다음과 같은 메뉴가 나타난다.

"Print fname"는 변수 fname의 값을 debugger console에 보여주고, "Display fname"는 변수 fname의 값을 가장 위에 있는 창("drawing area")에 보여준다.(포인터 변수에 대해서도 사용할 수 있다.) "What is"는 변수의 형식이나 구조를 보여주고, "Lookup"은 같은 변수가 다른 곳에 있는지 찾는데 쓰인다. 마지막으로 "Break at", "Clear at"은 밑에서 배울 멈춤점(Breakpoints)에 대한 설정을 하는데 이용된다.

이러한 일과 몇몇 일들은 소스 코드 창이 밑 부분에 있는 버튼들을 이용해서 할 수도 있다. 박스 부분에 인자를 입력하고, 원하는 버튼을 누르면 된다.

멈춤점(Break-points)는 프로그램을 원하는 부분까지 실행 시키는데 사용된다. 프로그램이 원하는 곳까지 실행되고, 일시 중단되었으면 이때부터 변수의 값 등을 조사할 수 있고, 프로그램을 계속 실행 시킬 수 있다. 멈춤점(break-ponint)가 없으면 프로그램은 정상적으로 종료하거나, 버그(bug)에 의해서 종료될 때까지 실행이 된다. 이 때는 이미 프로그램이 왜 종료되었는지 조사하기에 너무 늦었다. 따라서 프로그램의 실행 중에 디버깅을 하는 것은 필요하다.

다음과 같이 하여 멈춤점(breakpoint)을 지정할 수 있다.

  • 멈춤점(breakpoint)을 설정하고자 하는 줄의 맨 왼쪽에 마우스를 위치시킨 다음 마우스의 오른쪽 버튼을 누른다. 그리고 "Set Breakpoint""Set Temporary Breakpoint"를 선택한다. 이 둘의 차이점은 Temporary는 그 줄까지 실행이 한번 된 후 Breakpoint가 삭제된다는 점이다. "Set Breakpoint"는 명령어에 의해서만 Breakpoint가 삭제 된다.
  • 소스 코드 창에서 "Break at()"라는 버튼을 누른다.
  • debugger console에서 "break <줄번호>"를 입력한다.
  • "Source->Edit Breakpoints" 메뉴에서 breakpoint를 지정할 수도 있다.

    위의 그림에서 70번째 줄과 71번째 줄에 Breakpoint가 지정된 것을 볼 수 있다. Breakpoint를 나타내는 그림은 한눈에 알 수 있다.

    위의 메뉴를 이용해서 Breakpoint에 대한 관리를 할 수 있다.
    "Condition" 을 이용하면, 조건에 만족할 때만 Breakpoint가 작동을 하도록 할 수도 있다. 프로그램이 Breakpoint를 만났을 때, 조건이 맞는지를 확인하고, 조건에 맞을 때만 멈추게 할 수 있다."Ignore Count"를 이용하여 Breakpoint가 지정된 줄을 번 지나고 난 후에 프로그램이 멈추도록 할 수 있다. 예들 들어 반복문에서 반복문이 15번 반복된 후에 멈추도록 할 수 있다. 일단 프로그램이 Breakpoint를 만나서 멈추었다면, 이때부터 현재 상태에서 변수의 값이 얼마인지 조사할 수 있게 된다.
    프로그램의 실행은 밑에 있는 메뉴를 이용해서 제어할 수 있다.


    메인 메뉴에 있는 것과, Floating window에 있는 것을 나타내었다.

    이들을 이용하여 프로그램을 실행시키거나 중단시킬 수 있다. 메인 메뉴를 이용해서 실행시키면 프로그램에 파라메터(Parameter)를 주어 실행시킬 수 있다. "Step"을 이용하여 프로그램을 한 줄씩 실행할 수 있다. 예를 들어, 실행을 하면서 함수(function)를 만났다면, "Step"은 함수(function)의 첫 줄에서 다시 "Step"을 누를 때까지 기다릴 것이다. 반면 "Next"는 함수를 한꺼번에 실행시킨다. "Continue"는 Breakpoint에 의해 프로그램이 일시 중단되었을 때 계속해서 프로그램을 수행하도록 한다. "kill", "interrupt","Abort"는 프로그램을 중단시킬 때 쓰인다.

    DDD의 가장 큰 특징은 맨 위의 창에 있다. 우리는 이 창을 이용해서 Dada의 구조를 그래픽하게 볼 수 있다. 다음 예에서는 Arguement로 들어온 배열의 구조와, 원소들의 값을 보여 준다.

    "Data -> More Status Displays"를 이용해서 사용자가 보기 원하는 것을 선택할 수 있다. 이 창은 매우 많은 정보를 보여 준다. 다음의 예에서는 프로세서의 레지스터에 어떤 값이 있는지와 프로그램을 실행하는데 필요한 동적 라이브러리 등을 보여준다.


    마치는 글

    DDD의 환경은 "Options -> Preferences"를 이용해서 사용자의 취향에 맞게 설정될 수 있다. 아니면, Motif로 만들어진 프로그램의 설정 방법인 $HOME/.dddinit으로도 설정되어질 수 있다. 자세한 설명은 이 글의 범위를 넘어가므로 생략한다.

    ddd를 설치할 때 같이 들어 있는 ddd.ps라는 문서를 꼭 한 번 읽어 보기 바란다. 또한 gdb의 설명서도 읽어 보기 바란다.("Debugging with DDB") 약간의 시간만 투자하면 쉽게 디버깅에 대해서 배울 수 있다.

    마지막으로 이 글에 잘못된 글이 있다면 용서하기 바란다 ^^;.


    번역 : 허정수

  • 'Utilities' 카테고리의 다른 글

    CVS 사용  (0) 2006.07.26
    [본문스크랩] vi 편집기 사용법  (0) 2006.07.21
    VIM을 사용하자  (0) 2006.07.20
    GCC의 간단한 사용법  (0) 2006.07.20
    The Linux GCC HOWTO  (0) 2006.07.20