여치의 프로그래밍 강좌 #5

조회 수 42032 추천 수 249 2005.07.27 23:47:14
/*
과거 모 잡지에 연재했던 프로그래밍 강좌입니다.
퍼가실땐 사전에 동의를 얻으시기 바랍니다.
-유영천
*/

버그(bug)란?
호랑이 담배 피우던 시절 진공관식 컴퓨터가 있었는데 그 진공관에 나방이 한마리 껴서 타죽었고 그래서 진공관이 오동작 했다. 이것이 최초의 컴퓨터 버그이고 이후로 컴퓨터에서 발생하는 소프트웨어적, 하드웨어적인 문제를 버그라 부르게 되었다...
라는 얘기가 전해내려온다. 진공관 컴퓨터 쓰던 시절에 필자가 살았던게 아니니까 진위여부는 잘 모르겠지만 하여간 그렇다고 한다.

오늘날 말하는 버그는 컴퓨터가 의도하지 않은, 작동을 하는 것을 통칭한다.
컴퓨터를 사용하는 사람이라면 C/C++은 못들어봤어도 버그란 말은 들어봤을 것이다. 외국인이 한국어를 배우면 가장 먼저 배우는 말이 '빨리빨리'라던데...
그만큼 한국어에서 많이 쓰이고 필수불가결(?)한 말이란 뜻이겠지.
컴퓨터를 사용하기 시작하면 금방 배우는 말이 '버그'라고 하면 마찬가지로 컴퓨터를 사용함에 있어 필수불가결(?) 하다는 의미...(?).

하드웨어 개발자나 소프트웨어 개발자나 버그를 일부러 만들려고 하지는 않지만, 피할래야 피해갈수없다. 버그가 전혀 없는 소프트웨어는 존재한적도 없거니와 앞으로도 존재하지 않을것이다.

디버깅(debugging)
버그 없는 소프트 없다고 그 상태 그대로 출시하면 욕은 욕대로 먹고 회사문 닫는 날을 앞당기게 된다. 당연히 버그를 잡아야한다. 잡는것도 중요하지만 발견해내야 잡을 수 있다. 예외도 있지만 대체로 버그가 있다는 사실을 알면서 그대로 출시하진 않는다(알면서 내보내는 경우도 없다고 하진 않겠다). 때문에 유져들이 엄청나게 불만을 쏟아내고 나서야 어떤 버그가 있는지 개발자가 알게 되는경우가 많다. 따라서 버그를 발견해내는것이 엄청 중요하다. 뭔 버그가 있는지 알아야 잡을 방법도 생각해볼테니까.

여튼 버그를 찾아내고 제거하는 행위.
이것이 디버깅(debugging)이다.

여담이지만 필자가 일본의 모 기업에 출장가서  프로그래머들을 만났을 때 그쪽에서 만들어놓은 3D라이브러리에 대해서 질문을 한 적이 있다.

'디버깅은 어떻게 합니까?

통역하는 분이 '디버깅'이라고 그대로 발음했다. 우리들은 아무도 이상하게 생각하지 않았다.
근데 일본 프로그래머들이 한참동안 고개를 갸우뚱하더니...

'아 데바그!!!'

아 그렇구나. 일본식으로는 데바그라고 하는구나.--; 디바그 라거나 디바깅 이라고 할 줄 알았는데.--;
여튼 첫 대면부터 디버깅은 어떻게 해요? 라고 물을 정도로 디버깅은 중요하다는 얘기지...


디버거(debugger)
디버깅은 뭘로 하나? 문제 있는 코드를 고치는게 디버깅 아닌가? 맞다. 고치는것은 소스 에디터로 하면 된다. 지금껏 예제 코드를 작성했던 VC++ 에디터 정도면 충분하다. 하지만 에디터가 디버거인것은 아니다. 디버거가 왜 필요하지? 디버거로 소스를 고치는 것은 아니다. 위에서 설명했듯이 잡는것보다 찾는게 더 중요하다. 디버거는 버그를 찾아내기 위한 툴이라고 보면된다. (물론 많은 디버거들이 바이너리 레벨에서 고치는 기능도 포함하고 있지만).

요새는 컴파일러와 에디터, 디버거가 통합되어 나온다. 우리가 사용하고 있는 VC++ 도 통합툴이다. 당연히 디버거를 가지고 있다. F5를 눌러 실행하면 디버거가 동작하는 것이다.

디버거의 사용
다음의 소스를 입력해보자. 아주 간단한 소스다.
그리고 int c = a + b; 줄에다가 커서를 올려놓고 F9를 누르자. 스샷에서 보는 바와 같이 좌측에 빨간 딱지가 붙었을것이다. 다시 F9를 누르면 해제된다.

source_editor.jpg



그리고 F5를 눌러보자. 아래와 같은 화면을 볼 수 있다.
다음은 VC++6.0의 디버그 상태에서의 화면이다. 화면구성은 각자 취향에 맞게 할 수 있다.

debugger_view.jpg



몇개의 창이 안보이는 독자들도 있을텐데 놀라지 말고 메뉴에서 디버그 아웃풋창들을 활설화시킨다.

debugger_output.jpg



1. 디스어셈블 창
작성한 C/C++소스를 컴파일한 어셈블리 코드를 보여준다. 이것이 실제로 CPU에서 돌아가는 프로그램의 코드이다. C/C++소스와 비교해서 보여주므로 어셈블리 공부에도 매우 도움이 된다.

2. 레지스터 상태 창
CPU의 레지스터 상태를 보여준다. 물론 디버깅되고 있는 프로세스의 레지스터 상태이다.

3, 변수 창
브레이크 포인트를 기준으로 이전 몇 개의 변수들의 값을 보여준다.

4.워치 창
변수명을 직접 타이핑 하거나 드래그 앤 드롭하면 이 화면에 해당 변수의 값이 나온다. 3과 비슷하지만 큰 차이점은 직접 값을 바꿀 수 있다는 것이다.
물론 레지스터나 함수의 어드레스도 볼 수 있다.

5. 메모리 창
특정 어드레스의 메모리값을 직접 들여다 볼 수 있다. 16진수 형태로 주소를 타이핑 해 넣으면 된다.??로 나올때는 물리 메모리에 맵핑되지 않은 영역이다. 쉽게 말해 할당받지 못한 영역이나 원래 사용할 수 없는 영역이다.

아랫쪽 워치 창에다 c,a,b를 각각 타이핑해보자.
다음과 같이 나온다.

debugger_watch_0.jpg



a와 b에는 코드에서 값을 넣은대로 10과 5가 들어가있다.
c에는 아무 값도 넣지 않았으므로 일단 컴파일러가 디버그 모드에 초기화할때 사용하는 0xcccccccc(16진수표기법으로)가 들어있다.

이제 F10을 눌러보면..

debugger_watch_1.jpg



이와같이 c값이 바뀌어있다. c = a +b 라는 코드를 한줄만 실행한 것이다. 바뀐 값은 빨간색으로 표시된다. printf따위를 사용하지 않고서도 중간 중간 결과를 확인할 수 있는 것이 디버거의 위력이다.
이런 간단한 프로그램이야 굳이 중간값을 확인할 필요는 없지만 복잡한 코드에선 어디서 문제가 생겼는지 알 수 없기 때문에 이런식으로 중간중간 값을 확인해야할 필요가 있다. 그래서 버그를 ‘찾아’낼 수 있고 ‘제거’까지 가능한 것이다.


디버그 인터럽트(Debug Interrupt)
최초의 강좌에서 인터럽트에 대한 설명을 했다. 다시 간략하게 설명하자면 CPU의 작동 흐름을 간섭하는 일종의 긴급 신호라 할 수 있다.
타이머칩에서 발생시키는 타이머 인터럽트나 주변장치의 I/O 가 발생시키는 인터럽트는 하드웨어 인터럽트다. 그리고 CPU가 연산도중 발생시키는 인터럽트는 소프트웨어 인터럽트가 되겠다. 0으로 나누거나 억세스 금지된 메모리 영역을 억세스 하려고 할때 이런 인터럽트가 발생한다. 여러분이 게임을 하다가 잘못된 연산오류 어쩌고를 본다면 이와같은 소프트웨어 인터럽트로 인해 어플리케이션이 크래쉬했다고 생각하면 된다.
이러한 소프트웨어 인터럽트는 익셉션(exception)이라고 한다. 익셉션은 소프트웨어적으로 프로그래머가 발생시킬 수 있다.
아까의 예제 소스에 다음과 같이 __asm int 3을 추가하고 F5를 눌러보자.

int3.jpg



위에서 사용한 인터럽트 3번은 디버그용으로 예약된 인터럽트이다. 대부분의 현대 OS는 유져모드에서 인터럽트 사용이 불가능하다. 엄밀히 말해서 아주 불가능한 것은 아니고 디버그용으로 예약된 3번이나 시스템 콜을 사용하기 위한 인터럽트는 사용 가능하다.

방금 우리가 의도적으로 인터럽트를 발생시킨 것처럼 디버거도 디버깅을 위해 의도적으로 인터럽트 3번을 발생시킨다.

3번 인터럽트가 발생하면 OS는 인터럽트가 발생한 프로세스의 스레드에 익셉션 핸들러가 있는지를 확인한다. 익셉션 핸들러란 익셉션이 발생했을때 어떻게 처리할지를기술한 프로그램 코드이다. 이는 어플리케이션을 짜는 프로그래머가 만들어넣게 된다. SEH라고 부르는 루틴이 이것이 되는데 안짜넣는 경우가 많다. 익셉션 핸들러가 설정되어있지 않으면 OS는 디버거가 설치되어있을 경우 디버거를 실행하고 익셉션이 발생한 프로세스의 제어를 디버거로 넘긴다.
디버거가 없으면 흔히 보게 되는 잘못된 연산 어쩌고 오류를 내고 프로세스를 종료시킨다.
대부분의 경우 익셉션 핸들러가 설정되어있지 않고, 또 일반 유져들의 PC에는 VC++이나 기타 디버거가 설치되어있지 않기 때문에 어떤 문제로 인해 어플리케이션이 크래쉬하게 되면 OS의 연산오류 메시지를보게 되는 것이다.

access_violaion.jpg



브레이크 포인트(Break Point)
앞에서 여러분들은 F9로 빨간 딱지를 찍어보았다. 이것이 브레이크 포인트이다.해봐서 알겠지만 브레이크 포인트에 딱 걸려있으면 변수들의 값을 확인하는 것은 물론 바꿀수도 있다. 그리고 다시 F5를 누르면 중지되었던 프로세스가 계속해서 실행된다.
이런식으로 변수들이나 메모리의 값이 여러분이 의도한 결과인지를중간중간 확인할 수 있는 것이다.

여러분이 F5를 눌러 실행했을때는 디버거가 실질적으로 제어권을 쥐고 있다.그냥 exe를 직접 실행하는것과는 다르다. 디버거는 자식 프로세스로 여러분이 짠 프로그램을 실행했다. 또한 디버그 이벤트를 디버거로 넘기도록 설정해놓았다. 따라서 여러분이 짠 코드에서 디버그 인터럽트, 즉 익셉션이 발생하면 디버거로 그 제어권이 넘어가게 된다.

F9를 눌러 브레이크 포인트를 찍고 실행하게 되면 컴파일러는 프로세스의 코드페이지에서 브레이크 포인트가 찍혀있는 위치를 찾아 int 3(opcode:0xcc) 를 덮어쓴다.
그리고 프로세스를 실행시키면 int 3 을 써넣은 위치에서 익셉션이 발생하고 순간 제어권이 디버거로 넘어가게 된다. 그리고 다시 진행시키면 디버거는 int 3으로 치환된 코드를 원래의 코드로 다시 써넣고 그 부분부터 다시 프로세스를 진행시킨다.


싱글스텝핑(Single Stepping)
위에서 F5를 눌러 프로그램 수행이 멈춘 상태에서 F10으로 한줄만 실행시켰었다.이를 싱글 스텝핑이라고 한다.
매번 모든 위치에 브레이크 포인트를 찍을순 없으므로 주요 지점에 브레이크 포인트를 찍어놓고 한줄씩 실행해가면서 중간값을 확인해볼 수 있다.
인텔 x86 CPU는 플래그 레지스터의 TF플래그를 설정하여 사용한다. 트랩플래그가 설정되면 한 줄 실행할때(여기서의 한줄은 정확히는 어셈블리의 명령 하나)마다 싱글스텝 익셉션이 발생한다. 그러면 마찬가지로 디버거에 제어권이 넘어가고 디버거는 디버깅되는 프로세스의 상태를 유져에게 보여주고 입력을 기다리게 된다. 유져가 프로그램의 흐름을 계속 진행하도록 F5를 누르면 트랩 플래그를 해제하고 프로세스를 진행시킨다. 다시 F10을 눌러 싱글스텝으로실행하면 트랩플래그를 설정하고 프로세스를 진행시킨다.




버그 유형과 원인,대처 요령
프로그램이 크래쉬하게 만드는 버그:
-commit되지 않은 메모리 어드레스 억세스
정상적인 OS하에 돌아가는 모든 소프트웨어는 OS로부터 메모리를 할당받아야만 쓸 수 있다. 스택영역도 물론 프로세스 초기화시에 할당받은 영역이다. 보통 reserve와 commit이라는 과정을 거쳐 메모리를 사용할 수 있게 되는데 commit이 이루어져야 할당받은 어드레스가 실제 물리 메모리에 맵핑된다.
만약 commit되지 않은, 그러니까 물리 메모리에 맵핑 되지 않은 영역을 억세스 하려고 하면 CPU는 익셉션을 발생시킨다.
또한 0번지는 사용이 불가하도록 OS가 설정해놓았으므로 당연히 commit이 되지 않고 억세스 할 수도 없다.

-Stack Overflow
함수 안에서 프로세스의 최대 스택 사이즈보다 크게 스택을 설정한 경우이다.가령 함수 안에서 100메가짜리 배열을 잡았다든가..이러한 경우가 되겠다.

-잘못된 IP 어드레스 실행
EIP에 잘못된 코드 어드레스가 설정되어 억세스 할 수 없는 메모리의 말도 안되는 명령어를 실행하려고 하는 경우다. C/C++만을 사용하는데 이런 현상이 발생했다면 십중팔구 함수 진입시에 설정된 스택사이즈를 넘겨서 스택을 덮어쓴 경우다.

-Heap 크래쉬
메모리를 미리 덩어리로 받아놓고 끊어쓰는 메모리 풀을 힙이라고 한다. 일반적으로 이 힙을 많이 사용하게 된다. malloc(), free()나 new, delete가 힙 함수의 대표적인 예라 할 수 있다.
힙의 특성상 할당받은 사이즈를 넘겨서 덮어쓰게 되면 다른 블럭이 깨져버린다. 힙크래쉬가 발생하면 구현하기 나름이지만 눈치채지 못하게 조용하게 돌아갈수도 있고 어플리케이션이 크래쉬할수도 있다. 또는 파일이 열리지 않기도 한다.

-무한루프
for문이나 while문에서 탈출조건을 잘못 코딩한 경우가 많다. CPU점유율을 100% 먹으며 계속 특정 코드루틴의 루프만 반복하게 된다. 직접적으로 어플리케이션이 크래쉬하진 않지만 실제로 크래쉬한것과 같다. 과거 윈도우즈 9x시리즈까지만 해도 이런 버그는 시스템 전체를 마비시키므로 치명적이었다.

-Resource Leak
말 그대로 자원 누수. 컴퓨터에서 자원이라고 하면 주로 메모리를 뜻한다. 메모리를 할당만 하고 해제하지 않는 경우가 되겠다. 과거 패키지 게임들 중에는 할당받은 메모리를 제대로 해제하지 않아 시간이 흐르면 리소스 부족으로 크래쉬하는 것들도 있었다. 초보자들이 가장 많이 만들어내는 버그다.

-chkesp
스택 포인터가 어긋났다는 것을 표현하고 싶었는데 마땅한 표현이 없어서 chkesp라고 썼다. 시비거는 분이 없기를... push 세번하고 pop한번 했다든가...하는 경우인데 C/C++만 썼을땐 이런 버그는 쉽게 나오지 않는다. VC++의 디버그 모드에선 컴파일러가 _chkesp라는 ESP레지스터 체크 코드를 함수 호출코드 뒷부분에 써넣는다. 그래서 이러한 버그가 있을 경우 디버그 모드에선 바로 잡아낼 수 있다.


크래쉬 하진 않지만 원하는 결과가 나오지 않는 버그:
이 경우보단 차라리 크래쉬 하는 편이 디버깅하기 편하다. 이런 경우는 프로그램의 로직에 문제가 있는 것이므로 그 프로그램의 내막을 모르면 디버깅이 어렵다. 크래쉬하는 버그는 원 소스를 짠 사람이 아니더라도 디버겅에 익숙한 사람이라면 버그를 잡을 수 있지만 이런 경우는 원래 짠 사람이 아니면 소스 내용을 속속들이 알기 전엔 디버깅이 거의 불가능하다.

마치면서...
4년전에 필자는  서버 프로그래밍을 하고 있었다. 지금보다 시스템 지식이 많이 부족했다. 멀티 스레드 상황에서 각종 헤괴한 일이 생기는게 얼마나 당황했던지...
그 때 한 줄기 광명을 안겨준 책이 두 권 있었으니, 한권이 Debugging Application(MS Press, John Robbins) 이고 한권이 Programmin Application For Windows(MS Press, Jeffrey Richiter) 였다. 시스템 지식을 좀 얻고나서부터는 디버깅이 한결 쉬워졌고, 코드에서 버그도 현저하게 줄었다.
내가 파는 책도 아닌데 광고하려는 것은 아니고... 뭔가 거꾸로라고 생각할지 모르지만 프로그래밍을 잘 하려면 디버깅을 잘 해야한다. 디버깅을 잘 하려면 시스템 지식을 많이 알아야한다.그래서 하는 소리다.
디버깅 해보자고 해놓고 인터럽트가 어쩌고 싱글 스텝이 어쩌고 뭔 소리를 하는지 모르겠다...라고 하실 독자들이 계실지 모르겠다. 스스로 읽어봐도 내용이 허접한 것은 필력이 딸리는 것이니 어쩔수가 없다. 다만 의도 자체는 OS와 CPU메카니즘을 강조하고 싶은것임을 알아주셨으면 한다.
간단하게 디버거 사용법을 익혔고 디스어셈블 창도 구경해보았으니 다음 회에서는 VC++로 작성하는 인라인 어셈블리에 대해서 배워보도록 한다. C/C++ 소스와 어떻게 매칭되는지 알면 매우 흥미로울 수도 있다.
다음 회에서 또 뵐때까지 모두들 버닝하시라~







파일 첨부

여기에 파일을 끌어 놓거나 파일 첨부 버튼을 클릭하세요.

파일 크기 제한 : 0MB (허용 확장자 : *.*)

0개 첨부 됨 ( / )
List of Articles
번호 제목 글쓴이 날짜 조회 수
83 여치의 프로그래밍 강좌 #6 file [1] 여치 2005-07-27 29846
» 여치의 프로그래밍 강좌 #5 file 여치 2005-07-27 42032
81 여치의 프로그래밍 강좌 #4 file 여치 2005-07-27 39350
80 여치의 프로그래밍 강좌 #3 file 여치 2005-07-27 35348
79 여치의 프로그래밍 강좌 #2 file 여치 2005-07-27 31837
78 여치의 프로그래밍 강좌 #1 file 여치 2005-07-27 30037
77 지형도 BSP를 사용하시나요? [1] 초보 2005-07-06 26491
76 DirectX 입문용으로 적절한 책이 있을지요? [2] MiR 2005-03-01 41287
75 [re] DirectX 입문용으로 적절한 책이 있을지요? [1] 여치 2005-03-02 30297
74 BSP/Portal/PVS에 대한... guest 2005-02-18 24490
73 [re] BSP/Portal/PVS에 대한... file 여치 2005-02-19 23534
72 3D가속에 관한 질문 [3] 바하무트 2004-12-29 37321
71 [re] 3D가속에 관한 질문 여치 2004-12-29 27613
70 [질문] HeightMap의 퍼포먼스... [1] croove 2004-11-01 28868
69 [상담] 어떻게 해야할까요? . 2004-08-20 26046
68 [re] [상담] 어떻게 해야할까요? [1] 여치 2004-08-21 29021
67 [질문] 힙메모리 라이브러리에대해서. clever98 2004-08-08 32744
66 [re] [질문] 힙메모리 라이브러리에대해서. [1] 여치 2004-08-08 30295
65 [re] [질문] 단편화의 제거는 어떤식으로 하시나요? [1] 웰치스포도주스 2004-11-23 27815
64 개발 인력에 대한 질문 [1] 방문객 108 2004-07-20 23064



XE Login

天安門大屠殺 六四天安門事件 反右派鬥爭 大躍進政策 文化大革命 六四天安門事件 The Tiananmen Square protests of 1989 天安門大屠殺 The Tiananmen Square Massacre 反右派鬥爭 The Anti-Rightist Struggle 大躍進政策 The Great Leap Forward 文化大革命 The Great Proletarian Cultural Revolution 人權 Human Rights 民運 Democratization 自由 Freedom 獨立 Independence 多黨制 Multi-party system 民主 言論 思想 反共 反革命 抗議 運動 騷亂 暴亂 騷擾 擾亂 抗暴 平反 維權 示威游行 法輪功 Falun Dafa 李洪志 法輪大法 大法弟子 強制斷種 強制堕胎 民族淨化 人體實驗 胡耀邦 趙紫陽 魏京生 王丹 還政於民 和平演變 激流中國 北京之春 大紀元時報 九評論共産黨 獨裁 專制 壓制 統一 監視 鎮壓 迫害 侵略 掠奪 破壞 拷問 屠殺 肅清 活摘器官 障テ社會 誘拐 買賣人口 遊進 走私 毒品 賣淫 春畫 賭博 六合彩 台灣 臺灣 Taiwan Formosa 中華民國 Republic of China 西藏 土伯特 唐古特 Tibet 達償ワ喇嘛 Dalai Lama 新疆維吾爾自治區 The Xinjiang Uyghur Autonomous Region free tibet