<4D F736F F D20B5F0B9F6B1EBBFA120B4EBC7CFBFA92E646F63>

Similar documents
Microsoft PowerPoint - chap01-C언어개요.pptx

Windows 8에서 BioStar 1 설치하기

Microsoft PowerPoint - chap06-2pointer.ppt

ISP and CodeVisionAVR C Compiler.hwp

Microsoft Word - windows server 2003 수동설치_non pro support_.doc

슬라이드 1

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

경우 1) 80GB( 원본 ) => 2TB( 복사본 ), 원본 80GB 는 MBR 로디스크초기화하고 NTFS 로포맷한경우 복사본 HDD 도 MBR 로디스크초기화되고 80GB 만큼포맷되고나머지영역 (80GB~ 나머지부분 ) 은할당되지않음 으로나온다. A. Window P

tiawPlot ac 사용방법

Microsoft Word - ntasFrameBuilderInstallGuide2.5.doc

Poison null byte Excuse the ads! We need some help to keep our site up. List 1 Conditions 2 Exploit plan 2.1 chunksize(p)!= prev_size (next_chunk(p) 3

Windows Server 2012

Install stm32cubemx and st-link utility

슬라이드 1

View Licenses and Services (customer)

버퍼오버플로우-왕기초편 10. 메모리를 Hex dump 뜨기 앞서우리는버퍼오버플로우로인해리턴어드레스 (return address) 가변조될수있음을알았습니다. 이제곧리턴어드레스를원하는값으로변경하는실습을해볼것인데요, 그전에앞서, 메모리에저장된값들을살펴보는방법에대해배워보겠습

Microsoft PowerPoint Android-SDK설치.HelloAndroid(1.0h).pptx

JDK이클립스

<41736D6C6F D20B9AEBCADBEE7BDC42E687770>

MF Driver Installation Guide

아이콘의 정의 본 사용자 설명서에서는 다음 아이콘을 사용합니다. 참고 참고는 발생할 수 있는 상황에 대처하는 방법을 알려 주거나 다른 기능과 함께 작동하는 방법에 대한 요령을 제공합니다. 상표 Brother 로고는 Brother Industries, Ltd.의 등록 상

Oracle VM VirtualBox 설치 VirtualBox에서 가상머신 설치 가상머신에 Ubuntu 설치

Microsoft Word - Armjtag_문서1.doc

PathEye 공식 블로그 다운로드 받으세요!! 지속적으로 업그래이드 됩니다. 여러분의 의견을 주시면 개발에 반영하겠 습니다.

금오공대 컴퓨터공학전공 강의자료

슬라이드 1

목차 윈도우드라이버 1. 매뉴얼안내 운영체제 (OS) 환경 윈도우드라이버준비 윈도우드라이버설치 Windows XP/Server 2003 에서설치 Serial 또는 Parallel 포트의경우.

목 차 1. 드라이버 설치 설치환경 드라이버 설치 시 주의사항 USB 드라이버 파일 Windows XP에서 설치 Windows Vista / Windows 7에서 설치 Windows

Microsoft Word - Crackme 15 from Simples 문제 풀이_by JohnGang.docx

Microsoft Word - PLC제어응용-2차시.doc

Microsoft Word - 3부A windows 환경 IVF + visual studio.doc

vRealize Automation용 VMware Remote Console - VMware

SaaS 플랫폼을 위한 Web 2.0기반 서비스 제공 미들웨어 기술 연구

Microsoft Word - src.doc

Microsoft PowerPoint - chap06-1Array.ppt

VPN.hwp

Studuino소프트웨어 설치

SIGIL 완벽입문

API - Notification 메크로를통하여어느특정상황이되었을때 SolidWorks 및보낸경로를통하여알림메시지를보낼수있습니다. 이번기술자료에서는메크로에서이벤트처리기를통하여진행할예정이며, 메크로에서작업을수행하는데유용할것입니다. 알림이벤트핸들러는응용프로그램구현하는데있어

다른 JSP 페이지호출 forward() 메서드 - 하나의 JSP 페이지실행이끝나고다른 JSP 페이지를호출할때사용한다. 예 ) <% RequestDispatcher dispatcher = request.getrequestdispatcher(" 실행할페이지.jsp");

<4D F736F F F696E74202D20B8AEB4AABDBA20BFC0B7F920C3B3B8AEC7CFB1E22E BC8A3C8AF20B8F0B5E55D>

Microsoft PowerPoint - additional01.ppt [호환 모드]

System Recovery 사용자 매뉴얼

Title Here

DCL Debugging Support

MF5900 Series MF Driver Installation Guide

[ 마이크로프로세서 1] 2 주차 3 차시. 포인터와구조체 2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Functi

NTD36HD Manual

untitled

JAVA 프로그래밍실습 실습 1) 실습목표 - 메소드개념이해하기 - 매개변수이해하기 - 새메소드만들기 - Math 클래스의기존메소드이용하기 ( ) 문제 - 직사각형모양의땅이있다. 이땅의둘레, 면적과대각

Microsoft PowerPoint - CSharp-10-예외처리

Microsoft Word - codevision사용법_pdf버전.docx

IRISCard Anywhere 5

< 목차 > Ⅰ. 개요 3 Ⅱ. 실시간스팸차단리스트 (RBL) ( 간편설정 ) 4 1. 메일서버 (Exchange Server 2007) 설정변경 4 2. 스팸차단테스트 10

Microsoft PowerPoint - chap06-5 [호환 모드]

지도상 유의점 m 학생들이 어려워하는 낱말이 있으므로 자세히 설명해주도록 한다. m 버튼을 무리하게 조작하면 고장이 날 위험이 있으므로 수업 시작 부분에서 주의를 준다. m 활동지를 보고 어려워하는 학생에게는 영상자료를 접속하도록 안내한다. 평가 평가 유형 자기 평가

JVM 메모리구조

F120L(JB)_UG_V1.0_ indd

목차 1. 시스템요구사항 암호및힌트설정 ( 윈도우 ) JetFlash Vault 시작하기 ( 윈도우 ) JetFlash Vault 옵션 ( 윈도우 )... 9 JetFlash Vault 설정... 9 JetFlash Vault

윈도우시스템프로그래밍

<4D F736F F F696E74202D20C1A632C0E520C7C1B7CEB1D7B7A5B0B3B9DFB0FAC1A4>

<322EBCF8C8AF28BFACBDC0B9AEC1A6292E687770>

01장

4S 1차년도 평가 발표자료

1. 안드로이드개발환경설정 안드로이드개발을위해선툴체인을비롯한다양한소프트웨어패키지가필요합니다 툴체인 (Cross-Compiler) 설치 안드로이드 2.2 프로요부터는소스에기본툴체인이 prebuilt 라는이름으로포함되어있지만, 리눅스 나부트로더 (U-boot)

WinDbg 사용법

윈도 모바일 6.1을 OS로 사용하는 스마트폰(옴니아2 등)에서의 Tcl/Tk의 사용

Endpoint Protector - Active Directory Deployment Guide

Microsoft PowerPoint - e pptx

PowerPoint 프레젠테이션

중단점활용하기 중단점 (Breakpoint) 의개념은프로그램의특정명령어바로이전에실행을임의로중단하는것으로의 매우간단합니다. 중단점의구현은소프트웨어또는하드웨어로가능합니다. 중단점사용은버그를찾아내고제거하는데매우쉽고간단한방법이며복잡한조합으로사용할수있습니다. 소프트웨어개발자들은

Microsoft PowerPoint SDK설치.HelloAndroid(1.5h).pptx

1

PowerPoint 프레젠테이션

Index 1. Intro Install Connect Scratch 1.4 (Offline Editor) Scratch 2.0 (Online Editor) Connect f

<4D F736F F D D31312D30312D53572D30312DBBE7BFEBC0DABCB3B8EDBCAD5FBFDCBACEB9E8C6F7BFEB2E646F63>

< E20C6DFBFFEBEEE20C0DBBCBAC0BB20C0A7C7D12043BEF0BEEE20492E707074>

비디오 / 그래픽 아답터 네트워크 만약에 ArcGolbe를 사용하는 경우, 추가적인 디스크 공간 필요. ArcGlobe는 캐시파일을 생성하여 사용 24 비트 그래픽 가속기 Oepn GL 2.0 이상을 지원하는 비디오카드 최소 64 MB 이고 256 MB 이상을 메모리

JAVA 플랫폼 개발 환경 구축 및 활용

Microsoft Word - FunctionCall

11장 포인터

gdb 사용법 Debugging Debug라는말은 bug를없앤다는말이다. Bug란, 컴퓨터프로그램상의논리적오류를말하며, 이것을찾아해결하는과정이바로, debugging이다. 초기컴퓨터들은실제벌레가컴퓨터에들어가서오작동을일으키는경우가있었다고하며, 여기서 debug 이라는말이

버퍼오버플로우-왕기초편 3.c언어에서버퍼사용하기 버퍼는 임시기억공간 이라는포괄적인개념이기때문에여러곳에존재할수있습니다. 즉, CPU 에도버퍼가존재할수있으며, 하드디스크에도존재할수있고, CD- ROM 이나프린터에도존재할수있습니다. 그리고앞의예제에서보신바와같이일반프로그램에도

MF3010 MF Driver Installation Guide

6. 설치가시작되는동안 USB 드라이버가자동으로로드됩니다. USB 드라이버가성공적으로로드되면 Setup is starting( 설치가시작되는중 )... 화면이표시됩니다. 7. 화면지침에따라 Windows 7 설치를완료합니다. 방법 2: 수정된 Windows 7 ISO

SBR-100S User Manual

쓰리 핸드(삼침) 요일 및 2405 요일 시간, 및 요일 설정 1. 용두를 2의 위치로 당기고 반시계방향으로 돌려 전날로 를 설정합니다. 2. 용두를 시계방향으로 돌려 전날로 요일을 설정합니다. 3. 용두를 3의 위치로 당기고 오늘 와 요일이 표시될 때까지 시계방향으로

A SQL Server 2012 설치 A.1 소개 Relational DataBase Management System SQL Server 2012는마이크로소프트사에서제공하는 RDBMS 다. 마이크로소프트사는스탠다드 standard 버전이상의상업용에디션과익스프레스 exp

BY-FDP-4-70.hwp

C 프로그램의 기본

Microsoft PowerPoint - ch07 - 포인터 pm0415

금오공대 컴퓨터공학전공 강의자료

슬라이드 1

Tablespace On-Offline 테이블스페이스 온라인/오프라인

A Hierarchical Approach to Interactive Motion Editing for Human-like Figures

<B1E2BCFAB9AEBCAD5FB9DABAB4B1D45F F F64746F72732E687770>

Xcovery 사용설명서

특징 찾아보기 열쇠 없이 문을 열 수 있어요! 비밀번호 및 RF카드로도 문을 열 수 있습니다. 또한 비밀번호가 외부인에게 알려질 위험에 대비, 통제번호까지 입력해 둘 수 있어 더욱 안심하고 사용할 수 있습니다. 나만의 비밀번호 및 RF카드를 가질 수 있어요! 다수의 가

OnTuneV3_Manager_Install

Transcription:

Visual C++ 2008 을이용한디버깅 2008-04-18 http://cafe.naver.com/windev 작성자 : 최호성 (cx8537@naver.com) 본문서는상업적목적으로배포할수없으며저작권은작성자에게있습니다. 이문서의내용은작성자가집필중인책에포함될예정입니다

디버깅에대하여 개발자의실력을평가하는가장좋은방법중하나로디버깅실력을언급하지않을수없습니다. 사실경력 1년차개발자나 3년차개발자나이론에대한지식적수준은많은차이를보이지않는것이일반적입니다. 그러나생산성에있어서는많은차이를보입니다. 이와같은차이를보이는가장결정적인이유가운데하나는디버깅실력때문이라할수있습니다. 물론이는어디까지나제사견이며이에대해반론을제기할분들도계시리라생각합니다. 하지만디버깅기술이개발자의실력을좌우한다는것에는크게이견이없으실것입니다. 윈도우프로그래밍과상관없는이러한내용까지언급하는이유는독자여러분들께디버깅실력의중요성을강조하고싶어서입니다. 스스로지난날을돌아보면서아쉬운것은지금알고있는디버깅기법을좀더일찍알았더라면빨리일을끝내고퇴근해도되었을일들이참많았다는생각이드는것입니다. 최소한일찍퇴근은둘째치더라도밤새는일은없었지않았을까하는생각도해봅니다. 이런이유로이번장에서는 Visual C++ 2008을이용한디버깅기법에대해소개할까합니다. 가장기초적인디버깅방법에서부터원격디버깅기법에이르기까지다양한기법들에대해언급할것입니다. 이설명들을보다완벽하게이해하기위해서는멀티스레드프로그래밍경험이있다는전제와기본적인전산개론지식 ( 정보처리기능사, 기사수준 ) 이필요합니다. 빌드모드 Visual C++ 에서새로운프로젝트를생성하면기본적으로그림과같이디버그모드로설정되어있습니다. 디버그모드는프로그램을개발하는시점에서개발자의디버깅편의를위한코드들이추가된빌드모드 ( 혹은설정 ) 라할수있습니다. 반대로릴리즈모드는디버깅을위한코드들이생략되었을뿐아니라컴파일러가여러분이작성한코드를최적화고성능 2

을극대화하여빌드하는모드입니다. 물론이것이전부는아니지만정말간단하게만이야 기하자면이정도가될수있습니다. 우리가작성하는 C, C++ 코드는고급언어입니다. 이코드는인간이알아보기위한것이지기계 (CPU) 가알아보기위한코드가아닙니다. 이때문에컴파일러는인간이작성한코드를기계가알아볼수있도록변환해줍니다. 이과정을컴파일이라합니다. 여기서중요한것은같은 C 코드라고하더라도컴파일된기계어는기계 (CPU) 에따라서달라질수있다는것입니다. 일반적으로우리가사용하고있는 Visual C++(x86용 Visual C++) 로컴파일한기계어는인텔호환 CPU가인식할수있는기계어 ( 어셈블리어 ) 입니다. 지금이런복잡한이야기를하고있는이유는빌드모드 (Debug, Release) 에따라결과기계어코드가달라지기때문입니다. 논리적으로는동일한코드일것이나컴파일옵션에따라어셈블리코드는완전히달라질수있습니다. 그리고모드에따라크게달라지는것이하나더있습니다. 그것은메모리관리부분입니다. 디버그모드에서는메모리를할당할때코드에서정의한크기만큼메모리가할당되는것이아니라이를추적하기위한정보들을넣기위한공간을포함하여더큰메모리가할당된다고할수있습니다. 이는아주중요한문제입니다. 디버그모드로컴파일된실행파일이릴리즈모드로컴파일된라이브러리 (DLL) 를로드하여함수를호출할경우문제가발생할수있습니다. 이에대해서는차후에좀더자세히언급하도록하겠습니다. 이론적인설명은이정도로해두고직접코드를보면서이해하도록합니다. 다음의코드 는빌드모드에따라결과 ( 어셈블리어 ) 가달라지는것을극단적으로보이는예입니다. 매우간단한코드입니다. 이코드의내용을보면불필요한내용들뿐입니다. Int형기억공간에 10회반복하여 10을할당하는것이전부입니다. 그러므로이함수를수행한다고하더라도논리적인변화나프로그램실행에영향을줄만한내용이사실상없습니다. 다시언급하지만이코드가불필요한내용들이라는사실에주목하시기바랍니다. 이코드를디버그모드로빌드하여디스어셈블한코드를보면다음과같습니다. 3

복잡한어셈블리어코드가나오니당황스러울수있겠으나자세히살펴보면다는몰라도대충이라도내용을어림짐작할수있을것입니다. 특히 ndata = 10; 코드에대한디스어셈블결과는충분히이해할수있는것입니다. ( 0Ah는 16진수 A 즉 10진수 10이됩니다.) 그리고생각보다많은어셈블리명령이필요하다는사실을알수있습니다. 그렇다면동일한코드를릴리즈모드로컴파일했을때는얼마나어셈블리코드가줄어드 는지다음의코드를보시기바랍니다. 4

다시한번당황하셨을수도있겠습니다. 동일한코드를릴리즈모드로빌드한결과어셈블리명령어하나 (ret) 로끝났습니다. 앞서이미언급했듯이작성된코드가불필요한내용들로가득하기때문입니다. 컴파일러가컴파일도중에이를판별하여아무런명령도수행하지않고함수가리턴 (ret) 하도록번역한것입니다. 현재우리가사용하는컴파일러들도지속적으로발전해왔습니다. 이제는단순히기계어로코드를번역하는수준을넘어논리적으로부적절한부분을제거하거나연산속도를증가시키기위해어셈블리레벨에서코드를최적화합니다. 이와관련된내용들은프로젝트설정 (Alt + F7) 에서직접확인할수있습니다. 다음그림 은릴리즈모드일때최적화에대한컴파일러설정화면입니다. 반대로디버그모드일때는다음과같습니다. 이외에도많은설정상의차이가있습니다. 그모든것들에대해언급할수는없으므로보 다자세한정보는 MSDN 이나 Visual C++ 2008 도움말을참고하시기바랍니다. 5

다음의디스어셈블코드는앞서예에서반복문안에 Sleep(1); 을추가하여릴리즈모드로 빌드한것입니다. Sleep() 함수가호출되면서스레드의컨텍스트스위칭이발생하므로실행에큰영향을주게됩니다. 때문에앞서와같이아무것도하지않고리턴하는것이아니라반복문을 10회수행합니다. 그런데어셈블리코드를잘보시면 ndata = 10; 코드는수행하지않는다는것을알수있습니다. 다음의코드는릴리즈모드로빌드하되속도최적화옵션을디버그모드와마찬가지로사 용하지않도록한것입니다. ndata = 10; 코드가어셈블리코드로번역되었음을알수있습 니다. 6

흔히디버그모드가릴리즈모드보다속도가느리다고합니다. 이는우리가작성한코드 가논리적으로동일한결과를얻을수있는전제하에서어셈블리레벨최적화를적용하지 않았기때문이기도하고실제로도어셈블리명령의개수에서차이가나기때문입니다. 선배로써한마디! 상당수의초 / 중급개발자들이디버그모드일때는괜찮다가릴리즈모드로빌드했더니런타임에러가발생한다고불평할때가종종있습니다. 문제는에러가발생한것이아니라이에대해어떻게대응할것인가에있습니다. 에러가발생한근본적인원인을찾아코드를수정하는것이가장바람직한모습이겠으나이런저런변명을늘어놓으면서속도최적화옵션을사용하지않도록하여에러를덮어버리기도합니다. 그래도이정도는양반입니다. 가끔은디버그모드로프로그램을배포하는배짱좋은개발자도보았습니다. 경우에따라최적화옵션을제거해야할수도있겠으나그것은분명다른이유이어야할것입니다. 7

빌드모드에따라어셈블리코드이외에메모리관련처리도다릅니다. 다음의코드는 MFC 위저드가생성한기본프레임코드에늘들어가있는내용입니다. _DEBUG 가정의 (#define) 되어있다면 new 연산자를 DEBUG_NEW 로재정의하라는내용 입니다. 디버그모드일때프로젝트설정을보면다음과같은내용이들어있습니다. 전처리기정의에 _DEBUG 를정의하고있습니다. 릴리즈모드일때는다음그림과같이 NDEBUG 가정의되어있고 _DEBUG 는정의하지않습니다. 그러므로디버그모드로빌드하면 new 연산자의연산이릴리즈모드일때와다를수밖 에없습니다. 다음의코드는 Afx.h 파일에서 DEBUG_NEW 를정의한코드입니다. 8

new 연산이이루어진코드상의구체적인위치를명시하는부분이추가된다는사실을알수있습니다. 이는디버그모드로실행했을때메모리할당및삭제와같은연산을추적하기위한것입니다. 디버그모드로실행한후메모리누수가발생하면 Visual C++ 는구체적인코드위치까지알려줍니다. 다음의코드는 int 형메모리를할당한후해제하지않는코드예입니다 이코드를수행하고프로그램을종료하면출력 (Output) 창에다음과같은메시지가출력됩 니다. Dumping objects -> c:\documents and settings\ 최호성 \my documents\visual studio 2008\projects\modedemo\modedemo\modedemodlg.cpp(171) : {534} normal block at 0x0038BDB0, 4 bytes long. Data: <D3" > 44 33 22 11 Object dump complete. The program '[2484] ModeDemo.exe: Native' has exited with code 0 (0x0). 해제하지않는메모리의크기뿐만아니라구체적인내용까지출력해줍니다. 이를통해서개발자는누수된메모리가할당된위치 ( 예에서는 ModeDemoDlg.cpp의 171번행 ) 를명확히알수있습니다. 디버그모드로프로그램을실행하였다면늘출력화면을주의깊게보시기바랍니다. 개발자가놓친부분에대해알려주는정보가출력될수있습니다. 9

디버그모드와릴리즈모드의차이가지금언급한이것이전부는아니겠으나이두가지 정도만알고있어도충분하리라생각합니다. 이두가지를요약하여정리하면다음과같습 니다. 1 코드최적화옵션에따른기계어의차이 2 메모리할당연산 (new, malloc() 등 ) 시추적을위한코드추가여부 끝으로메모리관리방식의차이때문에발생할수있는문제에대해알아두어야합니다. 이는 DLL과밀접한관련이있습니다. A.EXE라는실행파일이 B.DLL 파일을로딩하여사용한다고가정했을때, 만일 A.EXE는릴리즈모드로빌드된것이고 B.DLL은디버그모드로빌드된것이라면과연 A.EXE는아무문제없이실행될수있을것인지생각해야합니다. 결론부터말씀드리면대부분에러가발생하여프로그램이비정상종료되거나예기치못한실행결과를산출할수도있습니다. 이는매우중요한문제입니다. 초보시절에이런문제에부딪히면쉽게해결하기가어렵습니다. 왜냐하면코드의논리상에는아무런문제가없기때문입니다. 이는완전히지식적인혹은경험적인문제에해당되는것입니다. 다음의그림은이와같은상황을좀더구체적으로설명한가상의코드예입니다. 물론이코드가항상문제를만드는것은아닙니다. 게다가어떤컴파일러를이용하여컴파일했는가에따라결과는달라질수있습니다. 중요한것은언제어느때어떤이유로프로그램이비정상종료될지예측하기어렵다는것입니다. 그러므로실행파일이릴리즈모드로빌드된것이라면당연히연관된 DLL들도릴리즈모드로빌드된것이어야합니다. 하나는디버그모드다른하나는릴리즈모드와같은조합은절대바람직하지않습니다. 10

위치브레이크포인트 Visual C++ 2008의디버거를사용할때가장많이사용하는기능이바로위치브레이크포인트입니다. 아마도지금이글을읽기전에위치브레이크포인트를설정 / 해제하는정도를이미알고있을수도있을것입니다. 하지만지금은모른다고가정하고설명을이어가겠습니다. 위치브레이크포인트는특정코드가실행되는시점이되면디버그할수있도록실행을잠시멈추도록하는역할을합니다. 이위치브레이크포인트는통상 위치 라는말을빼고브레이크포인트라부릅니다. 그런데제가지금구체적으로 위치 라는말을언급하고있는이유는 데이터브레이크포인트 와구별하기위해서입니다. 데이터브레이크포인트에대해서는다음장에서상세히설명할것입니다. 위치브레이크포인트를설정하기위해서는마우스오른쪽버튼을눌러다음그림과같이 팝업메뉴에서 Insert Breakpoint 메뉴를선택하면됩니다. 아니면단축키 F9 키를눌러브 레이크포인트를설정 / 해제할수있습니다. 위치브레이크포인트가설정되면다음그림에서보는것과같이해당소스코드앞에붉은 11

색원표시가나타나게됩니다. 이는이위치에브레이크포인트가설정되었음을의미합니다. 만일해제하고싶다면다시 F9 키를눌러해제하시면됩니다. 이와같이프로젝트내에서설정된브레이크포인트들을소스코드에디터화면에서만확 인할수있는것은아닙니다. Alt + F9 키를눌러브레이크포인트관리윈도우를보시면브 레이크포인트에대한보다자세한정보를볼수있습니다. 다음그림은브레이크포인트관리윈도우화면입니다. PositionBreakDemoDlg.cpp 파일 165 번째행에브레이크포인트가설정되었음을알수있습니다. 12

이름 (Name) 필드에구체적인위치가보이고그항목앞에체크박스가있습니다. 만일이 체크를제거하면브레이크포인트는동작하지않습니다. 코드에서확인하면다음과같이브 레이크포인트표시모양이변경됩니다. 굳이의미를따지자면설정은되어있으나동작하지않는 (Disabled) 브레이크포인트가되 는것입니다. 이처럼설정된브레이크포인트가동작하도록하려면반드시디버그모드로실행하여야 합니다. 그러기위해서다음과같이 Start Debugging 메뉴를선택하거나단축이 F5 를눌 러실행합니다. 13

그러면 Visual C++ 의화면이디버그모드로전환됩니다. 다음그림은필자가주로구성 하는 Visual C++ 의디버그모드화면입니다. 꼭이와같이하실필요는없습니다. 개인취향이나환경에따라적절히설정하시면됩니 다. 다만이와같은설정을추천하는이유는이모든정보를한화면에서봐야할일이자 주발생하기때문입니다. 그러면구체적인실행예를살펴보도록하겠습니다. 14

OnBnClickedButtonBreakpoint() 함수는 PositionBreakDemo 예제에서 Break point 버튼을눌렀을때호출되는함수입니다. 앞서그림에서브레이크포인트에노란색화살표가중첩된것을볼수있는데이노란색화살표가의미하는것은그행을수행하기직전이라는뜻입니다. 그러므로코드에서는 wsprintf() 함수를호출하기직전이됩니다. 프로세스의실행은일시정지된상태를유지합니다. 이상태에서각변수의값이나메모리혹은호출스택을검사하여문제를찾아내면됩니다. 이에대해서는좀더자세히다룰것입니다. 아무튼이상태에서다시 F5 키를누르면다음브레이크포인트가있는위치까지계속실행이됩니다. 이는다음그림과같이브레이크포인트가 163번행과 166번행두곳에설정되었을때 163번행에서브레이크포인트가동작하고다시 F5 키를누르면 166 번행을실행하려할때다시브레이크포인트가동작하는것을의미합니다. 그러므로디버그모드실행은브레이크포인트가나타나기전까지프로세스를실행하는것이라할수있습니다. 만일 163번행의브레이크포인트가동작했을때 F10키를누르면다음브레이크포인트가아니라프로시저단위로실행이됩니다. 다음그림은 F10 키를눌러실행을추적하는화면입니다. 15

이 F10 키는 Step Over 메뉴에대한단축키입니다. Step Into(F11) 메뉴는보다상세하게함수를추적하는메뉴입니다. 만일현재실행할코 드가함수의호출일경우해당함수코드를찾아가한행씩추적하여실행합니다. 대부분의 개발자들이디버깅을하면서가장많이사용하는단축키를정리해보면다음과같습니다. 1 F5 ( 디버그모드실행 ) 2 F9 ( 브레이크포인트설정 / 해제 ) 3 F10 ( 프로시저단위실행 ) 4 F11 ( 행단위실행 ) 아무래도메뉴를선택하는것보다는단축키를이용하는것이훨씬편리할것입니다. 참고로 Ctrl + F5 키를누르면빌드된파일을일반모드로실행합니다. 이때는실행된프로세스와디버거가서로분리되어있으므로디버깅을할수없습니다. 이부분에대해서는 실행중인프로세스연결 에서상세히다룹니다. 16

프로그램디버그데이터베이스와호출스택 빌드모드에따라서빌드결과는확연히차이가난다고이미설명했습니다. 그리고디버그모드실행에대해서도여러분은이미알고있습니다. 그런데여기서한가지중요한사실을묵과하고넘어간부분이있습니다. 그것은상당수의사람들이디버그모드로빌드한경우에만디버깅이가능한것으로알고있다는것입니다. 그러나그것은잘못알고있는것입니다. 빌드모드에상관없이링크가완료된바이너리파일에대한프로그램디버그데이터베이스파일만있다면디버그모드실행이가능합니다. 그렇다면이제는이프로그램디버그데이터베이스파일 (XXX.pdb) 의역할에대해알아야합니다. 우선이파일은빌드된바이너리를디버깅할수있는정보를담고있는파일입니다. 어셈블리코드단위로실행이될때그코드가 C, C++ 소스코드어디에해당하는것인지함수혹은변수이름은무엇인지등에대한정보가담겨있습니다. 다음그림은 PdbDemo 예제의디버그모드설정중에서프로그램디버그데이터베이스 파일과관련된설정을보여주는것입니다. Visual C++ 2008 은기본적으로모드에상관없이 PDB 파일을생성하는것이기본설정입 니다. 이때문에릴리즈모드로빌드했어도 F5 키를누르면디버그모드로실행이되는것입 니다. 그렇다보니아예릴리즈모드로설정한상태에서개발을진행하기도합니다. 다음그림은 PdbDemo 예제를릴리즈모드로빌드했을때생성된 PDB 파일의모습을 윈도우탐색기로확인한것입니다. 17

다음코드는강제로에러를발생시키기위해만든코드예입니다. 릴리즈모드상태에서 F5 키를눌러디버그모드로실행하고 PDB Test 버튼을누르면이코드가실행됩니다. pszbuffer 는 NULL 을가리키고있으므로 wsprintf() 함수가호출되면에러가발생할것입 니다. 159 번행에서에러가발생할것이확실시되므로이행에위치브레이크포인트를설 정하고실행해보면다음과같이에러가발생하는것을확인할수있습니다. 내용을좀보면 PdbDemo.exe 파일이실행되던중 0x77CFB0E9 번지의명령이 0 번지에 쓰기를시도를해서예외처리가되었다고나옵니다. 여기서 Continue 버튼을눌러계속 실행하려해도더이상실행은불가능합니다. 우선실행을중단하기위해 Break 버튼을클릭하면다음그림과같은모습을볼수있 습니다. 18

에러를발생시킨 0x77CFB0E9 번지는 USER32.DLL 라이브러리가제공한어떤함수임을알수있습니다. USER32.DLL은윈도우운영체제라이브러리입니다. 만일이라이브러리에대한 PDB 파일이있었다면보기어려운주소가아니라구체적인함수이름으로출력되었을것입니다. 이부분에대해서는잠시후에다시언급하기로하겠습니다. 지금은이정보가출력된윈도우가어떤것인지에대해알아보겠습니다. 이윈도우는호출스택 (Call Stack) 디버그윈도우입니다. 이호출스택정보를보면함수호출의상관관계에대해알수있습니다. C, C++ 로작성 된프로그램은함수 (main(), WinMain() 함수 ) 로시작해함수로끝난다는것을이미배웠을 19

것입니다. 그리고그함수내부에선언된지역변수들은함수호출시자동으로생성되는스택에그영역이설정되므로자동변수라고한다는것도배웠을것입니다. 이때문에재귀호출과같은것들이가능합니다. 함수가리턴하면각함수호출시생성되었던스택은사라지게됩니다. 그러므로호출스택맨위에보이는것은현재실행중인즉맨마지막에호출된함수가됩니다. 그렇기때문에이정보를알면문제가발생한지점 ( 함수 ) 을쉽게찾아낼수있습니다. 다 음그림에서알수있듯 OnBnClickedButtonPdbtest() 에서에러가발생하였습니다. 그리고 친절하게도소스코드 159 번행이라는것까지알려줍니다. 이정도의정보를알수있다면개발자는에러가발생한위치를판별해내는데아무런문 제가없을것입니다. 한가지아쉬운것은최종적으로에러를발생시킨 0x77CFB0E9 번지 가어떤것인지구체적으로알지못했다는것입니다. 이것이무엇인지구체적으로알아내기위해골치아픈리버스엔지니어링을할수도있을것입니다. 그러나굳이그럴필요가없습니다. 왜냐하면 MS가윈도우운영체제의심볼파일을제공해주기때문입니다. 아래링크를찾아가시면윈도우심볼설치파일을다운로드받을수있습니다. http://www.microsoft.com/whdc/devtools/debugging/symbolpkg.mspx 주의할것은자신이사용하고있는운영체제에맞는것을다운로드받으셔야한다는것입니다. 한글 Windows XP Professional SP2를사용중이라면당연히 XP SP2에해당하는심볼을다운로드받아야합니다. 그런데그부분을잘보시면다시 Retail 버전과 Checked 버전으로나뉘는것을볼수있습니다. 20

Checked 버전은 Debug 버전을의미합니다. 운영체제도프로그램입니다. 따라서릴리즈모드로빌드된버전과디버그모드로빌드된버전이있을수있습니다. 특수한상황이아니라면모두 Retail 버전을설치하였을것입니다. 그러므로반드시 Retail 버전에대한심볼을다운로드받아서설치하여야할것입니다. 이심볼을받아서설치하면다음그림과같은모습을윈도우탐색기로확인할수있습니 다. 많은 PDB 파일들이보일것입니다. 찾아보시면 USER32.DLL 에대한 PDB 도볼수있 습니다. 심볼을설치했다고당장 Visual C++ 디버깅화면에서전과달리함수이름으로호출스택정보가출력되는것은아닙니다. 이심볼들을 Visual C++ 디버거가인식할수있도록설정을변경하여야합니다. 그러기위해서 Tools 의 Options 메뉴를선택하고다음과같이심볼이설치된경로를등록합니다. 이경로는각자다를수있으므로심볼이설치된절대경로를확인하여적절한경로를명시하여야할것입니다. 21

윈도우운영체제심볼설치및등록을마친후앞서의에러코드를실행하여호출스택을 보면좀더구체적인정보가출력되는것을알수있습니다. 굳이윈도우심볼을설치하지않아도디버깅을할수있습니다. 하지만설치및등록해주 시면좀더상세하게원인분석이가능합니다. 그러므로가급적운영체제심볼설치를권장 합니다. 22

데이터브레이크포인트와메모리 데이터브레이크포인트는위치브레이크포인트와달리특정주소공간의값이변경되면동작하는브레이크포인트입니다. 따라서프로그램이지정한메모리의값을바꾸는코드가실행되지않는다면데이터브레이크포인트는동작하지않습니다. 반대로지정한메모리의값이바뀐다면언제든동작합니다. 이글만봐서는이러한브레이크포인트를어떻게활용하여야할지판단이서지않을수도있습니다. 그러나데이터브레이크포인트를잘활용하시면위치브레이크포인트로는해결할수없는문제를해결하거나논리적인버그를손쉽게해결할수있습니다. 그리고대부분의초보개발자들은할당연산자를의심하지않습니다. 또한배열을잘못다뤄서생기는문제를쉽게해결하지못합니다. 여기잘못다뤘다는말은배열의경계를벗어난읽기 / 쓰기문제를말하는것입니다. 그러므로개발자는항상메모리의변화를잘관찰하면서디버깅을해야합니다. 우선데이터브레이크포인트에대해자세히알아보도록하겠습니다. 앞서언급한위치브레이크포인트의설정기준은실행코드였습니다. 그렇기때문에별다른조건이라는것이있을필요성이없었던것입니다. 그러나데이터브레이크포인트는메모리값을기준으로합니다. 그메모리에는어떤값이들어가게될지정해진것이아니므로매우유동적이라할수있습니다. 아래코드를빠르게읽고 AfxMessageBox() 함수가어떤문자열을출력할지예상해보 시기바랍니다. 깊이생각하지않고보면무조건 0 이출력되어야맞을것입니다. 혹시아무리자세히 들여다봐도 0 이출력될것이라고판단되어도너무걱정하시거나스스로를폄하시기지 23

는마시기바랍니다. 반대로답을어느정도맞추신분들은구체적으로어떤값이출력되는 지생각해보시기바랍니다. 그리고그값이빌드모드에상관없이늘같은값인지도고민하 여야합니다. 이예는정말중요한예입니다. 지금은코드가짧기때문에문제점이확연하게보일수있지만코드가길어지고프로그램이커졌을때는전혀다른이야기가됩니다. 아무리경험많은개발자라하더라도실수할수있기때문입니다. 이코드를빌드하여결과를확인하면다음과같습니다. 디버그모드 릴리즈모드 만일앞서코드예에서전역변수선언부분을빼고확인한다면분명 0 을출력하고자 했음을확실히알수있습니다. 다음의코드를다시살펴보시기바랍니다. 163 번행의코드에서 g_nresult 를 0 으로확실하게초기화했습니다. 그렇기때문에 166 번행의코드가수행되면 g_nresult 값이 0 일것이라예상할수있습니다. g_szname 의선 언이한눈에보이지않기때문에무시하고넘어가기쉽습니다. 중요한것은이에러가발생한원인지무엇인지규명하고어떻게해결하여야할지알아야합니다. 여러해결방법이있겠으나이경우제가가장추천하고싶은방법은데이터브레이크포인트를이용하는것입니다. 예제코드의결과적인문제는 g_nresult 값이 0이아닌다른값으로채워졌다는데있습니다. 사실지금은코드가매우짧기때문에 164, 166번행 24

의코드가원인일것이라고직관적으로예측할수있습니다. 이를좀더명확히이해하기위해 OnBnClickedButtonDatabreakpoint() 함수에위치브레 이크포인트를설정하고디버그모드로빌드한후디버그모드로실행합니다. 그러면다음 과같이위치브레이크포인트가동작하는것을볼수있습니다. 이와같이실행이일시중지된상태에서데이터브레이크포인트를설정합니다. 25

Address 항목에 &g_nresult 라고입력합니다. 말그대로어떤주소를입력하면됩니다. 이주소라는것이 32비트시스템에서는당연히 4바이트데이터입니다. 그러므로바이트카운트값을수정할필요없이그냥두면됩니다. 그러면전역변수 g_nresult의값이바뀌는순간에브레이크포인트가작동하게됩니다. 만일 g_nresult의값이 10인데다시 10을할당할경우에는값이변하지않으므로동작하지않습니다. 이점주의하시기바랍니다. 아무튼이러한방법으로데이터브레이크포인트를추가하면다음과같이브레이크포인 트관리윈도우에새로운항목이등록됩니다. 그런데 &g_nresult 라는문자열은없고어떤 16 진수값 (0x00420418) 이들어있습니다. 이값은 g_nresult 변수의주소값입니다. 조사식윈도우 (Watch) 에 &g_nresult 라고입 력해보면확인할수있습니다. 26

이와같이특정변수에대한주소를확인하였다면메모리윈도우를띄우고해당메모리의 값들을직접보면서확인합니다. 주소창에 g_nresult의주소를직접입력하여도되고조사식윈도우에등록한항목을클릭하여메모리윈도우에드롭해도됩니다. 이러한메모리윈도우는최대 4개까지동시에띄워서볼수있습니다. 중요한것은 0x00420418 번지는 g_nresult 변수의주소값이라는사실입니다. 이점을확실히한상태에서예제코드를디버그모드로계속실행합니다. 27

그러면다음과같이데이터브레이크포인트가동작했다는메시지를확인할수있습니다. 참고로한글판 Visual C++ 2008 에서는 적중했다 라는메시지가나옵니다. 이메시지를확인하면디스어셈블리윈도우가나타나면서어느번지의어떤어셈블리명 령을수행하다가값이변경되었는지구체적으로보여주게됩니다. 이어셈블리코드만보고어떤내용인지즉시판별하기는어렵습니다. 그러므로이시점 의호출스택정보를확인합니다. 그러면구체적으로어떤함수인지알수있습니다. 다음 그림에서보면 wsprintf() 함수때문임을알수있습니다. 그리고좀더정확히하기위해메모리윈도우의내용을확인해봅니다. 그러면변경된메 모리의내용이붉은색으로표시됨을알수있습니다. 다음그림은변경된 g_nresult 변수 의메모리내용을보이고있습니다. 28

여기보이는값은 16 진수값입니다. 그러므로 49 가아니라십진수 107 이되는것입니다. 현재디버그모드로실행중이므로 F10 키를눌러어셈블리코드단위로계속실행하도록 합니다. 그러면다음과같이계속값이변하는모습을볼수있습니다. 이때메모리윈도우오른쪽에 ASCII 코드영역을잘보시기바랍니다. 익숙한유니코드 문자열이보입니다. 메모리윈도우의내용을위로몇줄스크롤해보시면보다명확한이유 를알수있게됩니다. 변수는기억공간입니다. Int형기억공간이라해서문자열을쓸수없는것이아닙니다. 반대로문자열을저장하기위한버퍼에 Int 값이나주소를저장못할이유는없습니다. 예제코드의논리적결함은 wsprintf() 함수가 g_szname 버퍼에 This Is TEST STRING 이라는문자열을쓰면서배열의경계를벗어나다른변수 (g_nresult) 의영역을덮어쓰는것에있습니다. 이와같이배열의경계를벗어난읽기 / 쓰기동작은예기치못한치명적인오류를 29

만들어냅니다. 사실프로그램이항상똑같은시점에비정상종료되면이는반가운일입니다. 해당위치의코드를찾아수정하면그만이기때문입니다. 그러나평상시에는잘돌아가다가가끔씩이상한결과를내거나하면그런문제는해결하기가쉽지않습니다. 특히초보개발자에게는심각한수준의스트레스를유발하는원인이됩니다. 그러므로지금설명한사항을잘기억했다가업무에활용하시기바랍니다. 데이터브레이크포인트를활용할수있느냐그렇지않느냐는 1주일씩걸려문제를해결할것이냐아니면 1시간이내에문제를해결할것이냐를가르는중요한디버깅기법입니다. 선배로써한마디! 할당연산자라하더라도가끔은의심할수있어야합니다. 그리고메모리윈도우보는것을두려워하지마시기바랍니다. 16진데이터를직접바라보는일이처음에는분명낯설고어려운일이지만익숙해지고나면프로그램코드를바라보는눈이달라질것입니다. 매트릭스라는영화를보셨습니까? 그렇다면주인공 Neo가다시부활하여바라본세상은검은색안경을쓴요원들이아니라전부코드였습니다. 16진수를보는데익숙해지시기바랍니다. 컴퓨터와 C,C++ 코드에대한이해가달라질것이며언젠가는주인공 Neo처럼새로운세상을보게될것입니다. 조건데이터브레이크포인트 데이터브레이크포인트를잘쓰는단계가되면또불편함을느끼게됩니다. 이유는너무자주브레이크포인트가동작하기때문입니다. 만일 10000번정도루프를도는코드에서특정코드의값이변하는것을확인하고자데이터브레이크포인트나위치브레이크포인트를사용하면귀찮기그지없습니다. 확인할데이터가 9000번쯤루프를돌고난후에야확인되는것이라면이는정말답답한일이아닐수없습니다. 물론 if문하나집어넣고소스코드를수정해서해결하는손쉬운방법도있습니다. 아마도다수의개발자가그런방법을택할것입니다. 그러나루프처럼정해진규칙에따라값이증가하는경우가아니라면어떻게할까요? 임의의값에대응해서브레이크포인트를걸어야하는경우는단순데이터브레이크포인트만으로는한계가있습니다. 그래서등장한것인조건데이터브레이크포인트입니다. 30

조건데이터브레이크포인트는데이터브레이크포인트보다향상된기능을제공합니다. 다음의코드예를보시기바랍니다. g_nresult에 7 이상의값이할당될때만브레이크포인트가동작하도록설정할수있다면값이바뀔때마다동작하는데이터브레이크포인트보다편리하게디버깅을할수있을것입니다. 그러기위해서이미등록된데이터브레이크포인트를조건데이터브레이크포인트로수정합니다. 지금설정한내용은굳이설명하지않아도충분히이해할수있을것입니다. 조건부분에 는 if 문괄호안에쓸수있는조건과동일하다고보시면됩니다. 이조건이참이되면조건 31

브레이크포인트가동작합니다. 즉할당하는값이 rand() 리턴하는임의의값을 10으로나눈나머지가 7보다큰경우에만브레이크포인트가동작합니다. 이와같은조건데이터브레이크를활용하면임의의값이나반복문내에서디버깅해야할때원하는시점을신속하게잡아낼수있습니다. 이러한조건데이터브레이크기능이가장잘활용되는경우는멀티스레드환경이아닐까 생각합니다. 다음의코드예를봅시다. ThreadTest() 함수는총 5개의스레드로실행됩니다. 이함수의내용을요약하면앞서예와유사하게 g_nresult 전역변수에 0~99사이의임의의값을 1000번루프를돌면서할당하고있습니다. 설정된데이터브레이크포인트에다음과같이조건을주고디버그모드로실행해보겠습니다. 5 개의스레드중하나가언젠가는 g_nresult 에 99 를할당할것입니다. 이때, 스레드 32

윈도우를살펴보면다음과같이구체적으로어떤스레드가어느시점에값을변경하였는지 나타납니다. 조건을만족하지않더라도스레드스위칭이발생하면그시점에서스레드의진행이멈추 기도합니다. 각각의스레드는고유한 ID 값을가지고있으므로이를식별하는데는무리가없습니다. 그러나좀더직관적으로디버깅하고자한다면스레드이름을변경하여변화를확인할수도 있습니다. 다음그림은 3556 번스레드의이름을 최호성스레드 라고변경한예입니다. 아무래도사람은숫자보다는문자열이좀더눈에잘들어오므로이런기능을활용해보는것도좋겠습니다. 이외에도멀티스레드환경에서의디버그기능이 Visual C++ 2008에서많이향상되었습니다. 그러한부분들에대해다루는것도좋겠으나이정도의지식만으로도충분하리라생각합니다. 나머지부분들은스스로직접실습해보면서의미를파악하시면됩니다. 33

디버그매크로와함수 빌드모드를디버그로했을때만개발자가볼수있는정보들이출력되도록하기위해디버그매크로가오랜시간동안활용되어왔습니다. 매크로를사용해서얻을수있는최대장점은런타임에실시간으로프로그램의동작상황을모니터링할수있다는것입니다. 이말은브레이크포인트를걸어서프로그램의실행을개발자가임의로중단하여내용을확인하는것이아니라관찰해야할대상을정해주고프로그램의흐름을방해하지않으면서과정을모니터링할수있다는뜻입니다. 다음의코드는 Visual C++ 2008 도움말에들어있는 TRACE 매크로예제입니다. 사용방법 은매우직관적이며 printf() 함수를사용할줄아는개발자라면누구나손쉽게사용할수 있습니다. 이코드를디버그모드로빌드하고실행하면출력윈도우에서다음과같은메시지를실시 간으로확인할수있습니다. 프로그램의흐름을멈추지않기때문에경우에따라서이러한디버깅기법이유용합니다. 특히멀티스레드프로그램을디버깅할때아주유용합니다. 뿐만아니라윈도우서비스프 34

로그램을개발할때도유용하게활용할수있습니다. 사실이부분에대해더자세히설명 해야할것들이남아있으나 Visual C++ 2008 을사용하면굳이매크로를활용하지않아도 되므로구체적인언급은이쯤해두겠습니다. ASSERT() 매크로역시비교적자주사용되는디버그매크로입니다. ASSERT 매크로는글 자그래도단언한다는의미입니다. 다음의코드예를살펴보시기바랍니다. pszbuffer에메모리를할당하다가에러가발생할가능성은사실상잘없습니다. 이에대해제대로에러처리를하려면사실예외처리구조를적용해야할것입니다. 그러나대부분의개발자들이메모리를할당하는연산에대해그런처리를늘하지는않습니다. 구조적인예외처리를하지않는대신예제코드처럼할당된메모리가 NULL 아님을단언하는매크로를넣어주면만에하나단언조건을만족했을때다음과같은에러메시지를출력합니다. 코딩을하는동안디버그모드로빌드된파일을실행했을때종종볼수있는그런모양을하고있습니다. 지금까지설명한두디버그매크로는모두디버그모드일때만동작합니다. 릴리즈모드로빌드하면코드자체가컴파일타임에무시되고컴파일됩니다. 따라서동일한코드를릴리즈모드로빌드하고확인해보면아무런메시지도경고윈도우도출력되지않습니다. 이러한디버그매크로들과더불어반드시알아두어야할디버그메시지출력함수가하나 있습니다. 바로 OutputDebugString() 함수입니다. 다시말씀드리지만이것은매크로가아 35

니라함수입니다. 그러므로릴리즈모드로빌드해도동작합니다. 제경우를말씀드리면사실매크로를활용한디버깅은거의하지않습니다. 개발자체를아예릴리즈모드로하며굳이런타임에메시지를봐야할경우에는 OutputDebugString() 함수를이용합니다. 이방법을이용하면어떤형식의응용프로그램이건메시지모니터링및디버깅이가능합니다. 다음의코드는 OutputDebugString() 함수를이용한예입니다. 이코드를릴리즈모드로빌드하고디버그모드가아니라일반모드로실행한상태에서도디버그메시지를볼수있습니다. 그리고디버그메시지를보기위해굳이덩치큰 Visual C++ 2008 디버거를실행할필요도없습니다. DebugView라는작고간편한프로그램을이용해서실시간으로메시지를보면됩니다. 이 DebugView는과거 Sysinternals에서개발한공개유틸리티입니다. http://www.sysinternals.com에가서무료로다운받을수있습니다. 가보시면알겠지만이사이트가통째로 MS사에인수되었습니다. 덕분에 MSDN 기술문서페이지로링크됩니다. 이사이트의운영자는 Windows Internals의저자로알려진 Mark E. Russinovich 입니다. 다음그림은 DebugView 를실행하여 OutputDebugString() 함수가출력한메시지를확인 한모습입니다. DebugView 에보이는메시지는 OutputDebugString() 함수가생성한메시지뿐만아니라 디버그매크로가생성한메시지들도모두볼수있습니다. 결국이툴을이용하면 Visual 36

C++ 출력윈도우에서볼수있는메시지를모두볼수있게됩니다. 정말여러모로유용한 유틸리티가아닐수없습니다. 결국제가추천하는것은디버그매크로보다는 OutputDebugString() + DebugView 정도 로요약할수있겠습니다. 만일디버그모드로빌드했을때만메시지가나오도록하고싶다 면다음과같이코드를구성하면됩니다. _DEBUG 가정의된경우에만메시지가나오도록코드를수정해주면됩니다. 개인적으로는 코드가눈에거슬린다는이유로이러한방법을잘사용하지않고있으나이방법역시많이 사용되는좋은디버깅기법입니다. 37

실행중인프로세스연결 지금까지설명한디버깅기법들은디버그해야할대상프로그램을 Visual C++ 에서디버그모드로실행했을때가능한것들이대부분이었습니다. 그러한이유때문에실제상황에서의문제를해결하는데큰어려움이따릅니다. 명확하게원인을규명할수는없으나디버그모드로실행할때는빌드모드에상관없이에러가발생하지않는데탐색기를통해실행하면에러가발생하는경우를생각해볼수있습니다. 생각만해도참피곤한일이아닐수없습니다. 이러한문제를해결해야하는주체는당연히해당개발자입니다. 만일에러가발생하는것도즉시늘발생하는것이아니라하루에혹은 1주일에한번어쩌다발생하는경우라면정말골치가아픈일입니다. 이때가장유용한디버깅방법이실행중인프로세스에 Visual C++ 2008 디버거를연결하 는방법입니다. 이는이어서설명할리모드디버그기능과도연계되는것입니다. 다음의코 드예를보면서이기법에대한설명을이어가겠습니다. 이코드를실행하면당연히에러가발생할수밖에없습니다. NULL 포인터에접근했으므 로무조건프로그램을비정상종료됩니다. 이코드는 RemoteDebugDemo 예제의일부이며 릴리즈모드로빌드하고실행합니다. 실행에앞서반드시 PDB 파일을삭제하거나이름을바꿉니다. 그리고소스코드를편집하 38

던 Visual C++ 도종료합니다. 실행해서확인해보면당연히다음과같이에러가발생할것 입니다. 이상태에서 디버그 버튼을클릭하면다음과같이디버깅할디버거를선택하는윈도우 가나타납니다. 이와같은윈도우가출력된것은컴퓨터에디버거가설치되어있기때문입니다. 제경우 에는 Visual C++ 6.0/2005/2008 버전이모두설치되어있으나 6.0 버전은이항목에나타 나지않습니다. 상황재연을위해이상태에서 새인스턴스 Visual Studio 2008 을선택하 39

고확인합니다. 그러면 Visual C++ 가실행되고다음과같이프로그램실행이중단된원인을 보여줍니다. Continue 버튼을클릭하면프로그램을계속다시실행하도록하는것이며 Break 버튼을클릭하면브레이크포인트가동작하는것처럼프로그램의실행을멈추게됩니다. 그러면편집윈도우가 MFC 소스파일을하나열려서다음과같은위치에서에러가발생했음을가리킬것입니다. 이정보만봐서는구체적인에러의내용이나코드위치를알수없습니다. 그러나호출 스택윈도우를보시면다음과같이에러가발생한위치 (0x00401452) 가어디인지구체적으 로알수있습니다. 여기서구체적인함수이름이나오지않고주소로표시된것은에러를발생시킨실행파일 (RemoteDebugDemo.exe) 에대한프로그램디버그데이터베이스파일이없기때문입니다. 40

재연을위해실행에앞서 PDB 파일을삭제하지않았다면분명히구체적인내용이표시되 었을것입니다. 여기서한가지중요한사실을알아야합니다. 에러가발생해서실행이중지된프로세스는말그대로실행이일시중지된것이지종료된상태가아니라는것입니다. 작업관리자를통해확인해봐도해당프로세스는아직종료되지않았음을알수있습니다. 결국실행중인프로세스에디버거가연결되어해당프로세스를디버깅하게된것입니다. 이것이어떤의미를가지는지좀더자세히살펴보겠습니다. 그러기위해서메모장을실행하고 Visual C++ 2008 을실행하고아무프로젝트나열어 놓은후, 다음과같이실행중인메모장 (Notepad.exe) 프로세스에 Visual C++ 디버거를연 결합니다. 41

그리고 Break All 명령을선택하여메모장프로세스를일시정시시킵니다. 그러면메모장프로세스를디버그할수있는디버그모드로 Visual C++ 가전환됩니다. 42

만일여러분이메모장프로그램의 PDB 파일을가지가지고있다면이시점에서호출스 택을확인해서좀더구체적인정보를얻을수있을것입니다. 이와같이실행중인특정프로세스에디버거를연결하면실행을일시중지시키고해당프로세스의실행을감시하는것은물론사용중인메모리의내용까지모두확인할수있습니다. 만일소스코드까지가지고있다면내가개발하는프로그램처럼디버깅이가능할것입니다. 선배로써한마디! 리버스엔지니어링이라는것이결국실행중인프로세스를디버거를통해리어셈블한코드를분석하는일입니다. 실제소스코드나심볼 (PDB) 이없더라도어셈블리코드를이해할수있는개발자라면프로그램의동작을분석하고원하는대로조작할수가있습니다. 스타크래프트의맵핵과같은프로그램들은이러한방법으로얻은정보를바탕으로제작되는크랙소프트웨어입니다. 공부를목적으로그러한시도를해보는것은상관없겠으나악의적인목적을가진소프트웨어를제작배포하는것은불법입니다. 그리고게임가드나핵쉴드와같은프로그램들은이러한디버거가게임프로세스에연결되는것을막고게임프로세스의메모리를다른프로세스가읽지못하도록보호하는역할을합니다. 지금까지설명된내용을바탕으로개발자의일상에적용시켜보도록하겠습니다. 개발자철수는자신이개발중인프로그램이가끔씩비정상종료되는버그가있다는사실을통보받고 1주일이내에이문제를해결하기로하였다고가정하겠습니다. 그러기위해철수는문제가발생한시스템과동일한환경의시스템을구축하고자신이개발한프로그램을실행하고에러가발생할때까지방치합니다. 물론이시스템에는그실행파일을빌드한컴파일러와소스코드 PDB 파일을설치해둡니다. 특히 PDB 파일은실행파일이있는폴더에복사해둡 43

니다. 즉시에러가발생하지않자철수는컴퓨터를켜두고프로그램을실행시켜둔상태에서퇴근합니다. 그리고다음날운좋게도프로그램이에러가났다는메시지를보게됩니다. 이미대상프로세스를분석할모든준비가끝났으므로디버거를실행하여해당프로세스에연결하여호출스택정보및에러를유발한코드를확인합니다. 소스코드까지설치해둔덕분에자신이작성한코드중어디에서에러가발생한것인지구체적으로찾아내서문제를해결합니다. 지금설명한시나리오는프로그램이에러를내주는고마운상황입니다. 이보다더머리 아픈상황도있습니다. 다음의코드를봅시다. 코드의내용은결국임의의값이 100이면루프를탈출하는것입니다. 그런데 100으로나눈나머지가 100이될수는없습니다. 따라서 OnBnClickedButtonLoop() 함수는무한루프를돌게됩니다. 결국프로세스는종료되지도않고아무런에러도내주지않는상태에서마치멈춘것처럼보이게됩니다. 작업관리자를이용해프로세스의상태를확인해보면 응답없음 상태가되어있음을볼수있습니다. 이경우프로세스연결기능을사용하면손쉽게문제를해결할수있습니다. 앞서설명한것처럼해당프로세스의소스코드, PDB 파일을준비하고 Visual C++ 2008을이용하여코드를열고 응답없음 상태에빠진프로세스에연결합니다. 그리고 Break All 명령을선택합니다. 그러면 Visual C++ 2008의디버거는프로세스의실행을일시중지하고다음과같이디버그모드화면으로전환될것입니다. 44

이때호출스택의내용을보면다음과같습니다. 무한루프를돌고있는코드가어디인지직접확인할수있게됩니다. 이는정말편리한기능이아닐수없습니다. 이쯤되면디버깅에어느정도자신감을가져도좋을것입니다. 이와같이실행중인프로세스에 Visual C++ 디버거를연결하여사용할수있는기능은로컬컴퓨터뿐만아니라원격지의컴퓨터에도가능합니다. 이것을가능하게하는것이바로리모트디버그기능입니다. 45

리모트디버그 개발자 PC에서는멀쩡히잘도돌아가는프로그램이어떤사용자PC에서는 1시간에한번꼴로비정상종료된다고가정해봅시다. 이경우개발자는참답답할수밖에없습니다. 원인을규명하기위해결국은해당사용자의 PC를가져오던가본인이직접가서확인해야합니다. 그나마지리적으로가까우면좋겠으나개발자는서울에있는반면사용자는부산에있는경우직접가는일도쉬운일은아닙니다. 이러한문제를해결하는데가장좋은방법은리모트디버그기능을사용하는것입니다. 대한민국은세계최고를다투는네트워크인프라를가지고있습니다. 초고속인터넷사용 자수나인구대비비율에서세계어느곳에도뒤지지않습니다. 그러니이좋은환경을잘 활용하여야할것입니다. 우선로컬 PC에서리모트디버그를테스트해보도록하겠습니다. 이를위해앞서다루었던 RemoteDebugDemo 예제프로젝트를열어두고윈도우탐색기를이용해빌드된 RemoteDebugDeme.exe를실행해둡니다. 그리고 Visual C++ 의디버그메뉴에서 Attch to Process 메뉴를선택합니다. 여기까지는기존의프로세스연결과동일합니다. 그러면프로세스연결을위한윈도우가 나타날텐데여기서 Transport 부분을 Remote 로변경합니다. 46

그러면그림처럼프로세스연결화면이변경될것입니다. 이제는 Qualifier 에리모트 PC 의 IP 주소를입력하여리모트 PC 와연결하여야합니다. 그런데아직리모트디버거를실행하 지않았습니다. 그러므로다음과같은방법으로리모트디버거를실행합니다. 우선윈도우탐색기를실행하여 Visual C++ 2008 이설치된폴더를열고아래와같은경 로에서리모트디버거실행파일의단축키를만듭니다. 47

Visual Studio 설치시특별한변화를주지않았다면아래경로에해당될것입니다. C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\Remote Debugger\x86 이폴더에보면 msvsmon.exe 라는파일이있습니다. 그림처럼이파일에대한단축아이 콘을생성하고속성을열어다음과같이 대상 부분의값을수정합니다. 48

수정한내용은 msvsmon.exe 에 /? 옵션을주어실행하도록변경한것입니다. 그리고실 행을해보면다음과같은내용을볼수있습니다. Visual Studio Remote Debugging Monitor의옵션과내용에대해열거하고있습니다. 여기서주의깊게볼것은 /noauth 옵션과 /anyuser 옵션입니다. 이두옵션은아무런인증없이아무나리모트디버거에연결할수있도록허용하는것입니다. 보안적으로바람직하지는않으나편의를위해당장은이옵션을사용하기로하겠습니다. 다시단축아이콘의속성을열어서다음과같이실행옵션을변경합니다. 그리고실행해보면다음과같은확인메시지를볼수있습니다. 49

내용을확인해보면보안적인위험요소를감수하고실행할것인지를묻는것입니다. 우선은 예 를선택하여실행합니다. 그러면다음과같이윈도우방화벽의보안경고를볼수있습니다. 리모트디버거프로세스가외부의연결을받을수있어야하기때문에 차단해제 를선택하여예외처리해줍니다. 그러고나면리모트디버거가동작하기위해외부연결을아무런조건없이받을것인지설정하는창이나옵니다. 그림처럼모든원격컴퓨터들의리모트디버그요청을받도록합니다. 보안을위해로컬네트워크만연결을받도록하여도무방하겠습니다. 물론외부인터넷에존재하는 PC를리모트디버그할때는모든컴퓨터들이연결될수있도록설정하여야합니다. 50

확인하여설정을완료하면다음과같이리모트디버거모니터링윈도우가나타납니다. 리모트디버거가실행되었고아무런인증장치가없다는경고도보입니다. 이제내 PC에리모트디버거의실행이완료되었으니 Visual C++ 디버거를연결해보기로하겠습니다. 다음그림과같이 Qualifier에원격지 IP주소 ( 현재예에서는나의로컬 PC에연결하므로나자신을지칭하는 127.0.0.1 주소를입력합니다. 그리고엔터키를치면원격컴퓨터의실행중인프로세스리스트가나타납니다. 이제이후의처리는로컬에서실행중인프로세스에연결하는방법과같습니다. 다시우리철수의이야기로돌아가겠습니다. 부산에사는사용자의협조를얻어원격으로 에러가발생한 PC 에연결하는시나리오를순서대로열거하겠습니다. Step 1 원격디버그의대상이되는 PC 의 IP 주소를알아냅니다. 51

상대 PC 의 IP 주소를알아내려면 ipconfig 명령을이용하면됩니다. 그러기위해서다 음과같이 cmd.exe 를실행합니다. 그리고명령프롬프트에 ipconfig 명령을입력하여실행합니다. 원격사용자에게이방법으로 IP 주소를알아내도록합니다. 만일원격사용자가공유기 를사용하고있다면직접연결이불가능하므로주의합니다. 그런경우공유기에연결된 케이블을 PC 에직접연결하여공인 IP 주소를받도록하여야합니다. Step 2 해당 PC에리모트디버거프로그램을전송합니다. 아마도원격의사용자는리모트디버거프로그램을가지고있지않을것입니다. 그러므로리모트디버거프로그램을압축하여해당사용자게메일로보내줍니다. 물론, 다른송수신프로그램이나 FTP를이용하여도무방합니다. 참고로리모트디버거프로그램이있는폴더 (C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\Remote Debugger\x86) 를압축하면대략 4.2MB 정도됩니다. Step 3 리모트디버거를설정하고실행합니다. 원격사용자에게메일을확인하고 /noauth 옵션과 /anyuser 옵션으로리모트디버거를 52

실행하도록합니다. 여기까지진행되면사실대부분의준비가끝납니다. Step 4 해당소스를열고원격으로연결합니다. Visual C++ 2008 을실행하고해당프로젝트를열고대기합니다. Step 5 에러상황이발생하면 Break All 명령을선택하고디버깅을시작합니다. 에러가발생하지않더라도필요하다면리모트디버거에연결하여대상프로세스를살펴 봅니다. Step 6 원인을찾고리모트디버거를종료합니다. 원격 PC 의리모트디버거프로그램을종료하고 Visual C++ 2008 을닫습니다. 다음그림들은이와같은방법을이용하여원격디버그를수행한예입니다. 원격지의 IP 주소는 192.168.20.13 입니다. 이주소는사설주소로써공유기를사용하고있는주소입니다. 여기에연결한 PC는같은공유기에연결된 PC로 IP주소가 192.168.20.6 입니다. 둘다사설주소입니다만같은네트워크세그먼트내에존재하므로직접연결이가능한상황입니다. 다음그림은원격 PC 에원격데스크톱을연결하여리모트디버거를실행해둔상태입니다. 오른쪽에하얗게보이는것은무한루프에빠진 RemoteDebugDemo.exe 프로세스화면입 니다. 다음그림은이 PC 에연결하기위한 Visual C++ 의화면입니다. Qualifier 에원격지 IP 주소 (192.168.20.13) 가들어있습니다. 53

다음그림은원격 PC 의리모트디버거에출력된로그입니다. 원격으로디버그를수행하 는컴퓨터에로그온한사용자계정이름이출력되었습니다. 지금까지설명한디버그방법들을잘활용하시면거의대부분의경우에대한디버깅이가능하리라확신합니다. 특히리모트디버그방법을잘활용하시면큰도움이될것입니다. 개인적으로는이기법을이용하여어떤게임의치명적오류를수정한경험이있습니다. 제대로프로그램을디버깅할수있기위해서는시스템프로그래밍실력은물론필요하다면일부어셈블리코드를이해할수도있어야하고원격디버깅을위해 TCP/IP 네트워크에대한어느정도의지식도가지고있어야합니다. 결국많이알면그만큼버그를만들일이줄어들고혹시발생한버그가있더라도빠르게해결할수있습니다. 54