Debugging Applications By John Robbins Part I 최상호 http://blog.naver.com/tonkex
목차 목차 1 장. Bugs : Where They Come From and how You Solve Them? 2 장. Getting Started Debugging 3 장. Debugging During Coding 4 장. How Do Debuggers Work? 5 장. Power Debugging with the Visual C++ Debugger 6 장. Power Debugging with x86 Assembly Language and the visual C++ Disassembly Window 7 장. Power Debugging with Visual Basic Debugger 8 장. Finding Source and Line Information with Just a Crash Address. 2
목차 목차 9 장. Crash Handlers 10 장. Debugging Windows2000 Services and DLLs That Load into Services. 11 장. Multi-Machine, Multi-process Tracing 12 장. Multi-Threaded Deadlocks 13 장. Automated Testing 14 장. Limited OutputDebugString Calls 15 장. The Debug C Run-Time Library 3
목차 목차 1 장. 버그 : 어디서발생하고어떻게해결할것인가? 2 장. 디버깅시작하기 3 장. 코딩과디버깅병행하기 4 장. 디버거의동작원리 5 장. Visual C++ 디버거를이용한강력한디버깅 6 장. 어셈블리어와 Visual C++ Disassembly 창을이용한강력한디버깅 7 장. Visual Basic 디버거를이용한효과적인디버깅 8 장. Crash 주소만으로소스위치찾아내기 4
목차 목차 9 장. Crash 핸들러 10 장. Windows 2000 서비스와서비스안에서동작하는 dll 디버깅하기. 11 장. Multi-Machine, Multi-process Tracing 12 장. 다중스레드의병목현상 13 장. 테스트자동화 14 장. OutputDebugString 제한하여사용하기 15 장. The Debug C Run-Time Library 5
2 장. 디버깅시작하기 목차 1. Assert, Assert, Assert, and Assert 2. Trace, Trace, Trace and Trace 3. Comment, Comment, Comment and Comment 4. Trust Yourself, But Verify (Unit Testing) 5. Summary 6
소개 7
소개 8
소개 9
3 장. 코딩과디버깅병행하기 목차 1. Assert, Assert, Assert, and Assert 2. Trace, Trace, Trace and Trace 3. Comment, Comment, Comment and Comment 4. Trust Yourself, But Verify (Unit Testing) 5. Summary 10
소개 assert ASSERT _ASSERT, _ASSERTE http://msdn.microsoft.com/library/default.asp?url=/library/enus/vclib/html/_crt_assert.asp http://msdn.microsoft.com/library/default.asp?url=/library/enus/vclib/html/_mfc_assert.asp http://msdn.microsoft.com/library/default.asp?url=/library/enus/vclib/html/_crt_assert.asp ASSERT_KINDOF http://msdn.microsoft.com/library/default.asp?url=/library/enus/vclib/html/_mfc_assert_kindof.asp ASSERT_VALID http://msdn.microsoft.com/library/default.asp?url=/library/enus/vclib/html/_mfc_assert_valid.asp 11
소개 12
4 장. 디버거의동작원리 목차 1. Windows 디버거의종류 2. Debugbee를위해지원하는 Windows OS 기능 3. MinDBG : 간단한 Win32 디버거 4. WDBG : 실제로쓸만한디버거 5. 자기고유의디버거를만들고싶다면.. 6. WDBG 이후에는? 13
4-1. 소개 저자가직접제작한디버거 용어정리 MinDBG : 최소기능을수행하는디버거 WDBG : 실제로쓸만한디버거 Debuger( 디버거 ) : 디버깅관계속에서다른프로세스를제어하는프로세스. Debuggee( 디버그대상 ) : 디버거안에서실행되는프로세스. 디버거를 부모프로세스, Debuggee를 자식프로세스 라고도함. 14
4-2. Windows 디버거의종류 (1/2) Windows OS 에서는두가지형태의디버거가존재한다. 사용자모드 (User-Mode) 디버거커널모드 (Kernel-Mode) 디버거 사용자모드디버거 사용자가만든프로그램을디버깅한다. 대체로고유의 GUI를갖는다. 예 : Visual C++ 디버거 Win32 Debugging API를사용한다. Win32 Debugging API를사용한다는것은디버거와 Debuggee가실행생명주기를같이하는공생관계를갖는다는것을의미한다. MS 또는 Sun의 Java VM, MS Scripting Engine, MS Visual Basic p-code 인터프리터등은자체고유의디버깅환경을제공한다. MSDN, Debugging and Profiling Java Applications MSDN, Active Script Debugging API Objects 15
4-2. Windows 디버거의종류 (2/2) 커널모드디버거 CPU와 OS 사이에디버거가위치하여 OS의동작자체를멈추게할수있다. 타이밍, 동기화관련문제를해결하고자할때유용하다. 커널모드디버거로는사용자코드를디버그할수없다. ( 예외 : SoftICE) 디바이스드라이버개발자들이주로사용한다. 종류 WDEB386 ( Windows 80386 Debugger) i386kd (the Kernel Debugger) WinDBG SoftICE WDEB386 Platform SDK에배포되는 Windows 98 커널모드디버거 Windows 98 virtual device driver (VxD) 개발시에유용. 두대의컴퓨터와널모뎀케이블을이용. 한대에서커널모드로실행하며다른한대로디버그명령수행. 16
4-2. Windows 디버거의종류 (3/2) i386kd Windows 2000 OS 내의 NTOSKRNL.EXE 파일이커널모드디버깅을지원한다. OS 의 Release/Dubug 빌드버전모두사용가능하다. 커널모드디버깅기능을사용하려면, BOOT.INI 파일에다음의내용을추가. /DEBUG 옵션추가 기본포트인 COM1 포트대신다른포트를사용하려면 /DEBUGPORT 옵션사용. 두대의컴퓨터와널모뎀케이블을이용. Windows 2000 OS 내부의상태를알고자할때유용. 콘솔형프로그램이라서소스레벨디버깅에어려움이많아잘사용되지않음. 참고 Using Microsoft s x86 Kernel Debugger MSDN, I386KD.EXE 를사용하여 Windows NT MEMORY.DMP 파일을로드하는방법 17
4-2. 18
4-2. Windows 디버거의종류 (4/2) WinDBG Platform SDK 에포함되어배포되는하이브리드형디버거 사용자모드디버깅과커널모드디버깅을동시에모두제공하지는않는다. i386kd 와동등한기능에 GUI 를갖추고있어장치드라이버개발시에유용하다. Visual C++ 내장디버거보다더강력한기능을제공하지만사용이좀어렵다. 그러나 시간을들여배울만한가치가있다. 제공되는 Command 창으로 WinDBG 확장기능을이용해사용자고유의명령을지 시할수있다. Windows 2000 또는 WindowsNT 에서 Dr.Watson 이제작한덤프파일을읽을수있 다. 이는 crash 된프로그램의정확한상태가기록된덤프파일을디버거로읽어어느 부분에서 crash 가발생했는지확인할수있게한다. 참고 MSDN, Debugging Tools for Windows MSDN, WinDbg Debugger MSDN, Debugger Extension MSDN, Bugslayer (December,1999. January, 2000) 19
4-2. Windows 디버거의종류 (5/2) SoftICE 한대의컴퓨터에서수행되는유일한상용의커널모드디버거 CPU와 OS사이에위치하며 OS를멈추게함으로써응용프로그램을사용자모드에서디버깅할수있다. 다중쓰레드환경의프로그램디버깅에효과적이다. 예 ) SendMessageTimeOut API 를한레벨씩실행시켜가며디버깅. 프로세스간디버깅을용이하게한다. 예 ) out-of-process의 COM 프로그램의디버깅. 메모리영역에 4군데의중단점을설정하여메모리의특정번지에접근하는프로그램의실행을멈추게할수있다. OS에서일어나는각종현상들 ( 동기화이벤트들의상태, HWND 정보, 쓰레드정보, ) 을볼수있는많은명령어를제공한다. 참고 Compuware, SoftICE for Devpartner SoftICE the Basic ( 간단한설치및사용 ) CodeGuru, Getting Started with SoftICE 20
디버깅관련질문 Crash가발생하면동작하는기본디버거의변경은어떻게하나? Windows 98 WIN.INI 파일내의 [AeDebug] 섹션에지정 Windows 2000 Auto 항목 : 값이 0이면 Crash 발생시디버그할지를묻는대화상자가뜬다. 1이면자동으로디버거가실행된다. Debugger 항목 : OS가실행시키는디버거이름이기록되어있다. 프로세스에접근 (attach) 가능한디버거이면된다. UserDebuggerHotKey 항목 : 디버거로진입하고자할때사용하는지정단축키. 21
디버깅관련질문 Crash 가발생하면동작하는기본디버거의변경은어떻게하나? Visual C++ 디버거를 OS 기본디버거로설정하려면. 22
4-3. Debuggee 를위해지원하는 Windows 2000 OS 기능 (1) Windows 2000 힙메모리체크기능 (2) 프로세스실행시자동으로디버거실행하기 (3) 디버그용단축키 23
4-3. Debuggee 를위해지원하는 Windows 2000 OS 기능 (1) Windows 2000 힙메모리체크기능 디버거에서실행되는프로그램은 Windows 2000 OS가디버그힙메모리체크를수행한다. 이힙메모리는 C 런타임라이브러리의디버그힙이아니고 HeapCreate API에의해생성된다. 프로세스들이 Windows 2000의힙을폭넓게사용하기때문에힙과관계된정보를살펴볼필요가있다. 디버그힙메모리체크옵션이설정되면 (GFLAGS.EXE 사용 ) OS는 HeapFree API가호출될때힙을체크한다. 디버거에서는 HeapFree API 가호출될때마다 DebugBreak 함수를호출한다. 디버거상에서실행하지않으면별다른이상없이정상종료하게된다. 참고 MSDN, Matt Pietrek, Under the Hood, Sep. 1999, MSJ. 24
4-3. Debuggee 를위해지원하는 Windows 2000 OS 기능 (1) Windows 2000 힙메모리체크기능 : 힙메모리를잘못사용하는예제 void main(void) { // Create an operating system heap. HANDLE hheap = HeapCreate ( 0, 128, 0 ) ; // Allocate a 10-byte block. LPVOID pmem = HeapAlloc ( hheap, 0, 10 ) ; // Write 12 bytes to a 10-byte block (an overwrite). memset ( pmem, 0xAC, 12 ) ; // Allocate a new 20-byte block. LPVOID pmem2 = HeapAlloc ( hheap, 0, 20 ) ; // Underwrite 1 byte on the second block. char * punder = (char *)( (DWORD)pMem2-1 ); *punder = 'P' ; // Free the first block. This call to HeapFree will trigger a // breakpoint from the operating system debug heap code. HeapFree ( hheap, 0, pmem ) ; // Free the second block. Notice that this call won't report a problem. HeapFree ( hheap, 0, pmem2 ) ; // Free a bogus block. Notice that this call won't report a problem. HeapFree ( hheap, 0, (LPVOID)0x1 ) ; HeapDestroy ( hheap ) ; } 25
4-3. Debuggee 를위해지원하는 Windows 2000 OS 기능 (1) Windows 2000 힙메모리체크기능 : 힙메모리를잘못사용한결과 26
4-3. Debuggee 를위해지원하는 Windows 2000 OS 기능 (1) Windows 2000 힙메모리체크기능 : GFLAGS.EXE 유틸리티파일 (Debugging SDK를설치해야함 ) OS 가어떤 DLL 들을로드하는지볼수 있다. 또한이 DLL 들을어떻게 swapping 하는가확인할수있다. * 실행이미지마다각각의설정값을저 장할수있다. 27
4-3. Debuggee 를위해지원하는 Windows 2000 OS 기능 (1) Windows 2000 힙메모리체크기능 : Show Loader Snaps 옵션설정후 28
4-3. Debuggee 를위해지원하는 Windows 2000 OS 기능 (2) 프로세스실행시자동으로디버거실행하기 가장디버깅하기어려운타입은타프로세스에의해실행되는 Windows 2000 서비스나 COM out-of-process 서버의경우이다. 프로세스를디버깅하려면 DebugBreak API를사용하는데다음의두경우에는제대로 API가실행되지않는다. (1) Windows 2000 서비스 : DebugBreak API에의해디버거가실행되는동안서비 스타임아웃에걸려서비스가종료된다. (2) COM : DebugBreak API가호출되면 COM의에러핸들링루틴이이를오류로인식해 COM 서버를종료시킨다. 29
4-3. Debuggee 를위해지원하는 Windows 2000 OS 기능 (2) 프로세스실행시자동으로디버거실행하기 Windows 2000 OS에서는이를방지하고프로세스시작시제일먼저디버거를실행시키도록하는두가지방법을제공한다. (1) GFLAGS.EXE 유틸리티파일이용 : Image File 탭의 Debugger 항목체크후디버거의위치를입력한다. (2) 레지스트리변경 : Image File Execution Options 키밑에프로세스이름을갖는키를새로만들고그밑에디버거의위치를새항목으로만든다. 30
4-3. Debuggee 를위해지원하는 Windows 2000 OS 기능 (3) 디버그용단축키 ( 핫키 ) 콘솔형프로그램 Ctrl+C 또는 Ctrl+Break 키를누르면 DBG_CONTROL_C 라는특별한예외상황이발 생한다. DBG_CONTROL_C 예외상황은바로디버거로진입하여디버깅을시작할수있도록 한다. GUI 형프로그램 디버거에서프로세스를실행후 F12 키를누르면 DebugBreak API 를바로호출한다. F12 키에다른기능이할당되어있더라도디버그를수행한다. GFLAGS.EXE 유틸리티파일이용 : Image File 탭의 Debugger 항목체크후디버거 의위치를입력한다. WindowsNT 4 에는기본키가 F12 로고정되어있지만 Windows 2000 에서는레지스 트리키값을변경하여기본키를변경할수있다. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\Current Version\AeDebug 키밑의 UserDebuggerHotKey 키값을원하는 VK_* 값으로설정한다. 31
5 장. Visual C++ 디버거를이용한강력한디버깅 목차 1. 진보된중단점기능과그사용법 2. 원격디버깅 3. 팁과꼼수 4. 요약 32
5-1. 진보된중단점기능과그사용법 1. Advanced Breakpoint Syntax and Location Breakpoints 2. Quickly Breaking on Any Function 3. Breakpoints on System or Exported Functions 4. Location Breakpoint Modifiers 5. Global Expression and Conditional Breakpoints 6. Windows Message Breakpoints 33
5-1. 진보된중단점기능과그사용법 중단점을표시하려면원하는소스위치로커서를이동한후단지중단점추가 / 삭제버튼을누르기만하면된다. 이를디버거세계의용어로소스위치에중단점을설정 (setting a location breakpoint) 한다고한다. 소스의특정위치에중단점을삽입하는이행동은단순하지만현대와고대의디버깅의시대를구분하는중요한의미를갖는다. 고대의디버깅시대 중단점이라는것자체가없었다. Crash가발생하기를기다렸다가수십장의 16진수메모리덤프문서를보는것이디버깅의전략이었다. 디버깅을위해출력문 (Trace) 을삽입하고잘실행되기를기대하는믿음뿐이었다. 디버깅의르네상스시대 상위수준의언어가개발되었지만중단점을삽입하여단지어셈블리어수준의디버깅이가능했다. 지역변수를직접보거나소스를보면서디버깅을할수가없었다. 34
5-1. 진보된중단점기능과그사용법 현대의디버깅 복잡한개발툴이만들어지면서비로소소스라인에중단점을삽입하여지역변수등을보기쉽게변환된형태로관찰이가능해졌다. 소스위치기반의중단점삽입이라는단순하지만막강한기능만으로도 99.6% 의디버깅관련문제들을해결할수있다. 중단점삽입의문제점 중단점삽입하여변수를지켜보는방식은금방지루해진다. 10,000번을실행하는 For 구문안에중단점을걸어 9,999번째루프에서의변수값을관찰한다면..? 대안은? 진보된중단점기능을이용하여시간과노력을줄인다. 특정한루프횟수에도달했을때, 표현식이조건에맞을때, 특정변수나메모리값이변경될때에중단점에진입하도록한다. 35
5-1. 진보된중단점기능과그사용법 (1) Advanced Breakpoint Syntax and Location Breakpoints 복잡한개발툴이만들어지면서비로소소스라인에중단점을삽입하여지역변수등을보기쉽게변환된형태로관찰이가능해졌다. 소스위치기반의중단점삽입이라는단순하지만막강한기능만으로도 99.6% 의디버깅관련문제들을해결할수있다. 중단점삽입의문제점 중단점삽입하여변수를지켜보는방식은금방지루해진다. 10,000번을실행하는 For 구문안에중단점을걸어 9,999번째루프에서의변수값을관찰한다면..? 대안은? 진보된중단점기능을이용하여시간과노력을줄인다. 특정한루프횟수에도달했을때, 표현식이조건에맞을때, 특정변수나메모리값이변경될때에중단점에진입하도록한다. 36
5-1. 진보된중단점기능과그사용법 Visual C++ 사용예제 : AdvancedBP.dsw (1) 특정메모리번지에서중단점작동 37
5-1. 진보된중단점기능과그사용법 Visual C++ 사용예제 : AdvancedBP.dsw (2) 특정소스위치에서중단점작동 ( 가장일반적인사용의예 ) 38
5-1. 진보된중단점기능과그사용법 Visual C++ 사용예제 : AdvancedBP.dsw (3) 특정루프조건에서중단점작동 ( 횟수지정 ) 39
5-1. 진보된중단점기능과그사용법 Visual C++ 사용예제 : AdvancedBP.dsw (4) 특정변수의조건을만족할때중단점작동 40
5-1. 진보된중단점기능과그사용법 Visual C++ 사용예제 : AdvancedBP.dsw (5) 특정변수값이변경될때중단점작동 41
5-1. 진보된중단점기능과그사용법 (2) Quickly Breaking on Any Function 소스파일을일일이뒤지지않고바로 BreakAt 에디트박스에중단점을삽입할함수이름을입력한다. 함수이름을잘못입력하면디버거로진입시메시지박스가표시된다. C++ 을사용할경우에는클래스한정자 (Class Qualifier) 까지입력한다. Ex) MFC의 CDialog 클래스의 OnOK() 함수에대한중단점은 CDialog::OnOK 로입력. 오버로딩된함수의중단점삽입시에는모호성을해결하기위한메시지박스가표시된다. 42
5-1. 진보된중단점기능과그사용법 (3) Breakpoints on System or Exported Functions MS Windows 2000이상에서만시스템 DLL의함수에중단점을위치시킬수있다. Windows 98에서는쓰기중복사금지 (copy-on-write protection) 기능이없기때문에중단점을위치시킬수없다. 방법 : COFF (Common Object File Format) 파일을로드하고외부로추출 (export) 하기위해다음과같이설정을한다. 43
5-1. 진보된중단점기능과그사용법 (3) Breakpoints on System or Exported Functions 예 : KERNEL32.DLL 내부의 LoadLibrary 함수에중단점을걸경우 Visual C++ 디버거는완전한심볼정보를갖는파일내용이앞서는계층적인심볼정보접근체계를갖는다. 즉, 소스라인, 함수, 변수, 타입등의모든정보가있는 PDB(Program Database) 파일이항상가장앞에위치한다. 다음에공용함수심볼의정보만을담는 COFF/DBG 파일이위치한다. 마지막으로의사심볼 (pseudo symbol) 형태로외부에노출된 (exported) 이름들이맨끝에위치한다. Dll 이완전한심볼정보를갖고있는경우 44
5-1. 진보된중단점기능과그사용법 (3) Breakpoints on System or Exported Functions 예 : KERNEL32.DLL 내부의 LoadLibrary 함수에중단점을걸경우 ( 계속 ) Windows 2000 용심볼설치를권장한다. 공용심볼에대한정보만을볼수있지만그래도스택 /Disassembly 윈도우에서현재어느함수에있는지정도는파악가능. 심볼정보를로드할수없다면, DUMPBIN.EXE 유틸리티를활용한다. 사용법 : dumpbin /EXPORTS kernel32.dll ANSI 용함수 ( 내부적으로는 LoadLibraryW 가다시호출된다.) UNICODE 용함수 c:\windows\system32 dumpbin /exports /out:c:\result.txt kernel32.dll 45
5-1. 진보된중단점기능과그사용법 (3) Breakpoints on System or Exported Functions 예 : KERNEL32.DLL 내부의 LoadLibrary 함수에중단점을걸경우 ( 계속 ) 함수호출규약을확인한다. 이름장식 (name decoration) 에의해함수이름을만드는데 stdcall 에의해호출되는함수는함수이름앞에 _ 를붙이고함수이름뒤에는 @ 와스택에들어간바이트수 ( 인텔 CPU의경우함수파라미터의개수 * 4 bytes) 를적는다. 예 : 입력파라미터가하나인 LoadLibraryW 함수 -> _LoadLibraryW@4 예 : 입력파라미터가열개인 CreateProcess 함수 -> _CreateProcess@40 예 : 입력파라미터가없는 TlsAlloc 함수 -> _TlsAlloc@0 그러므로, 진보된중단점다이얼로그창에다음과같이입력한다. {,,KERNEL32.DLL}_LoadLibraryW@4 46
5-1. 진보된중단점기능과그사용법 (4) Location Breakpoint Modifiers 디버거의중단점을좀더 스마트 하게사용하게하는루프횟수지정 (skip counts), 조건표현식 (conditional expressions), 변수값변화감지 (variable changes) 기능을사용하자. Skip Counts 지정하기 47
5-1. 진보된중단점기능과그사용법 (4) Location Breakpoint Modifiers Skip Counts 활용하기 : 루프실행중 crash가발생했는데몇번째루프인지알수없을경우. 전체루프실행횟수보다더큰숫자를 Skip Counts 에입력한다. 프로그램을디버그모드에서다시실행시키면 crash 가발생하는데, 이때 Breakpoints 창을열면남은루프횟수가표시되어있다. 20 번째루프까지중단점을무시하도록설정했는데 15 번을남겨놓고서 crash 됨. 즉, 5 번째루프에서에러발생. 48
5-1. 진보된중단점기능과그사용법 (4) Location Breakpoint Modifiers Conditional Expression 사용하기 위치중단점은입력한조건식이참일때에만동작한다. 조건식사용상의규칙 1. C방식의비교연산자만을사용할수있다. 2. 조건식내에서함수호출은불가능하다. 3. 조건식내에서매크로값사용은불가능하다. 4. 변수이름및포인터를직접사용할수있고캐스팅도가능하다. Conditional Expression 활용하기 : 스트링을조건식에서사용하기 (szbuff[0]== p ) && (szbuff[1]== a ) && (szbuff[2]== m ) Conditional Expression 활용하기 : 의사레지스터를조건식에서사용하기 특정쓰레드동작에대한조건식 : @TIB==0x7FFDE00 특정에러 (ERROR_FILE_NOT_FOUND) 에대한조건식 : @ERR=2 49
5-1. 진보된중단점기능과그사용법 (4) Location Breakpoint Modifiers Conditional Expression 활용하기 : 의사레지스터를조건식에서사용하기 ( 계속 ) 조건식에서사용할수있는의사레지스터 50
5-1. 진보된중단점기능과그사용법 (4) Location Breakpoint Modifiers Variable Changes 사용하기 변수의변화감지기능은위치중단점을사용할때에만동작한다. 지켜보고자하는변수가참조하는메모리바이트수 실행결과 51
5-1. 진보된중단점기능과그사용법 (5) Global Expression and Conditional Breakpoints 전역변수나조건표현식에의한중단점은 CPU의디버그레지스터를이용해 4개까지설정할수있다. 디버그레지스터는 1,2,4바이트크기의메모리만을관찰할수있다. 초기화되지않은포인터를이용한메모리쓰기등의 wild write를수행하여무작위위치에서오류발생시등에활용가능하다. 전역변수의사용예 Ex.1) char 형전역변수의첫번째문자가 G 문자로변경될경우 ( 메모리위치 : 0x00404594 번지 ) : 디버그표현식창에 *(char *) 0x00404594== G Ex.2) long 형전역변수의값이변화될때 ( 메모리위치 : 0x004045A0) : 디버그표현식창에 *(long *)(0x004045A0) 입력. 52
5-1. 진보된중단점기능과그사용법 (5) Global Expression and Conditional Breakpoints 주의 : 디버그표현식에전역변수에대한식을쓸때에는포인터형태로기술해야한다. Long 형캐스팅을할경우항상 1 을기술. (CPU 의디버그레지스터가 double-word 크기만을참조할수있기때문 ) 53
5-1. 진보된중단점기능과그사용법 (6) Windows Message Breakpoints 특정윈도우메시지에대해서만중단점을걸고자할경우. SDK를이용하여윈도우프로그래밍을할경우에는 Break at WndProc 드롭다운박스에사용하는윈도우메시지가보여진다. 콤보박스에원하는메시지가없으면직접윈도우메시지숫자를입력한다. MFC를사용하는경우 : 내용추가필요 54
디버깅관련질문 왜중단점이사라지거나건너뛸까? 중단점을제대로사용하려면 Visual C++ IDE를꼭사용한다. 외부에서소스를수정할경우 One or more breakpoint are not positioned on valid lines. This breakpoints have been moved to the next valid line. 메시지가보인다. 디버거는중단점을항상아래방향으로이동시킨다. 따라서코드를임의로삭제하면문제가발생할수있다. 디버거가중단점을제대로동작시키지못하는대부분의경우는 LoadLibarary API를이용하여서명확히사용하지않는 DLL에중단점을걸었기때문이다. 따라서디버거가해당 DLL에대한심볼을제대로사용하도록 Additional DLLs 항목을설정해야한다. 컴파일러최적화기능을사용하면컴파일러가임의로코드를변경시킬수있기때문에중단점이제대로동작하지않을수있다. 55
디버깅관련질문 왜중단점이사라지거나건너뛸까? ( 계속 ) 사용하는 DLL 을명확히디버거에게알리기위한설정 56
5-2. 원격디버깅 원격디버깅의정의 사용자프로그램과디버깅을위한관련데이터 (a tiny debug stub) 와디버거가각각다른컴퓨터상에서 TCP/IP 를통해서로상호작용하는것. 원격디버깅이유용한경우 1) 중요한윈도우활성화코드를디버그해야할때 2) 화면그리기 (drawing/painting) 관련코드를디버그해야할때 3) 사용자프로그램이많은메모리사용을요구할때 4) Windows 98 OS 상에서디버그하고자할때 5) Visual C++ IDE 를모두설치함으로인해발생하는해당수행컴퓨터의환경변화를원치않을때. 참고 MSDN, Debugging Remote Applications MSDN 한글, 원격디버깅설치 서우석, 1394를이용한원격디버깅 57
5-2. 원격디버깅 (1) 중요한윈도우활성화코드를디버그해야할때 윈도우를활성화시키는 WM_SETFOCUS 메시지등을단계적으로디버그할경우. GUI기반의디버거와포커스전환이이루어져서프로그램을단계적으로실행시킬수없다. (2) 화면그리기관련코드를디버그해야할때 Microsft DirectX 를이요하는게임의디버깅. (3) 사용자프로그램이많은메모리를요구할때 최소사양을갖춘컴퓨터에서프로그램을디버깅할경우에는 Debug Build 버전도무겁다! (4) Windows 98 OS 상에서디버그하고자할때 원격디버깅시, 서로다른 OS에서도동작한다. Windows2000 OS상에서디버거동작이더원활하므로디버깅은 Windows 2000에서, 프로그램실행은 Windows 98에서. 58
5-2. 원격디버깅 (5) Visual C++ IDE를모두설치함으로인해발생하는해당수행컴퓨터의환경변화를원치않을때. 개발환경을구축함으로써시스템 DLL의버전의변경되어사용자프로그램과충돌하는 DLL Hell 을겪을경우. 내용추가필요! 59
5-2. 원격디버깅 주의 원격디버깅이끝나면 Visual C++ IDE를다시로컬디버깅상태로전환해야한다.( 원격디버깅관련설정은모든프로젝트에공통으로적용되므로 ) 네트워크부하에민감한시스템이나프로그램을사용하는경우 TCP/IP를사용하는 Visual C++ 디버거대신 WinDBG를사용한다.( 시리얼포트 / 널모뎀케이블이용 ) IEEE 1394 케이블을이용하는방법도있다! 60
5-3. 팁과꼼수 1. Setting Breakpoints 2. The Watch Window (1) Formatting Data and Expression Evaluation (2) Timing Code in the Watch Window (3) Calling Functions in the Watch Window (4) Expanding Your Own Types Automatically 3. The Set Next Statement Command 4. Debugging Visual Basic Compiled Code 61
5-3. 팁과꼼수 1. 중단점설정하기 소스라인,Disassembly 창외에도 Call Stack 창에서도중단점설정이가능하다. 깊게중첩된함수호출일경우유용하다. 설정 : Call Stack 창에서마우스오른버튼을누른다. Call Stack 창에서중단점설정 / 해제 중단점을추가한후제거하지말고대신 비활성화 상태로체크하라. 62
5-3. 팁과꼼수 2. Watch 창 Watch 창에서바로변수의값을변경할수있다. 조건표현식에서사용하였던표현방식을사용할수있다. ( 변수이름을직접입력도가능하다.) (1) 데이터와표현식표현형식을사용하여표시하기 63
5-3. 팁과꼼수 (1) 데이터와표현식표현형식을사용하여표시하기 Watch 창에, 를쓰고정해진각형식에따라덧붙인다. 응용 : COM 프로래밍시에 COM 메서드호출후그결과값을지켜보고자할때 -> Watch 창에 @EAX,hr 이라고기술. (@EAX 레지스터에는함수리턴값이저장되고이를 HRESULT 포맷으로 Watch창에표시하게됨 ) 64
5-3. 팁과꼼수 (1) 데이터와표현식표현형식을사용하여표시하기 ( 계속 ) Formatting Symbols for Watch window Variables 65
5-3. 팁과꼼수 (1) 데이터와표현식표현형식을사용하여표시하기 ( 계속 ) Formatting Symbols for Watch Window Memory Dumps 66
5-3. 팁과꼼수 (1) 데이터와표현식표현형식을사용하여표시하기 ( 계속 ) 배열의값을 Watch Window 로살펴보기 배열이름다음에, 후관찰하고싶은배열의크기입력. Ex) plong,10 Window에표시. : 배열을가르키는포인터 plong 에대하여배열요소 10 개까지 Watch 배열의옵셋을지정하여표시할수도있다. Ex) (pbigarray+100,20) : pbigarray 포인터의 99 번째요소부터 20 개까지창에표시. Watch Window 는거의모든식을다표현할수있다. (2) Watch Window 에서의타이밍관련코드 두지점사이의실행시간을 @CLK 레지스터를이용해측정할수있다. microsecond 단위의초를 milisecond로변환하고 10진수형태로표시한다. 첫번째 @CLK레지스터의값을초기화한다. 67
5-3. 팁과꼼수 (3) Watch Window 에서함수실행하기 Visual Basic 에서의직접실행창처럼함수를직접실행시킬수있다. 변수이름과구별되도록 () 를꼭표시한다. 입력파라미터또는리턴값도모두표현할수있다. 68
5-3. 팁과꼼수 (3) Watch Window 에서함수실행하기 ( 계속 ) 함수실행시주의사항 단일쓰레드환경에서만실행시킬것. ( 멀티쓰레드환경에서실행할경우에는함수실행하고나서 Watch 창에서이를삭제해야함 ) 함수의실행시간이 20 초이내가되도록할것. 데이터확인을위한메모리읽기정도의용도로사용하고, 문제발생시에는 OutputDebugString 또는 printf 등의함수를이용할것. Watch Window 내의함수가실행되는경우 프로그램이실행되어중단점에도달할경우디버그중소스라인을한줄씩실행하는경우 Watch Window에서함수를입력 / 수정하고나서 Enter를치는순간프로그램실행중예외상황이발생하여디버거로진입하는순간 Watch Window 에서디버그함수를실행하고나면이를 Window 에서항상삭제하는 것이바람직하다. 69
5-3. 팁과꼼수 (4) 사용자정의데이터를자동으로 Watch Window 에서확장해서보여주기 내용추가필요 70
5-3. 팁과꼼수 3. 다음구문설정하기 (Set Next Statement) 명령 소스창과 Disassembly 창에서마우스오른버튼을누른후메뉴에서선택하여실행한다. 이는프로그램내에서다음실행점 (Instruction pointer) 를임의의위치로옮길수있다. 또는 CPU의 EIP 레지스터를직접수정하여같은효과를낼수도있다. 최적화된릴리즈빌드에서이기능을사용하려면 disassembly 창에서사용할것. 이명령으로실행점이변경되어실행될때스택에임시변수를만드는작업이수행될때는조심해야한다. 프로그램내부의상태를자주변경시키지않는코드에서사용하는것이바람직. If 구문등에서조건별로수행하는코드들을실행해보는단위테스팅시에유용하게쓰임. Run To Cursor 명령과함께조합해서사용. 71
5-3. 팁과꼼수 4. Visual Basic 의컴파일된코드디버깅하기 P-code로컴파일된 Visual Basic 코드는충분한타입정보를생성하지않기때문에디버깅이어렵다. Compuware 사의 SmartCheck 등의툴을사용하기도한다. 또는직접어셈블리어형태의 Visual Basic 코드를디버깅하는것이더쉽기도하다. (^.^) 생각보다어렵지않다.(?) PDB 파일을생성한다. 72
5-4. 요약 참고자료 MSDN, Visual C++ 디버깅관련자료 MSDN, 디버거관련자료 73