Exception이 발생하여 비정상 종료되는 경우 외에도 디버깅이 필요한 경우는 많죠.
예를 들면, 잘 돌던 어플리케이션이 갑자기 Hang이 걸리는 경우가 있습니다. 보통 특정 조건에서 무한루프에 빠지거나, 탈출조건이 충족되지 않아서 계속 머물러 있는 경우인데요... 개발PC가 아닌 PC에서 가끔 가다 한번씩 발생하는 경우라면... 좀 골치아프죠. ^^

Hang이 걸린 경우 디버깅의 포인트는 각 Thread들이 어디를 실행중인지 (Thread 별 CallStack)을 확인하는 것입니다. 어디서 Thread가 어디를 돌고있는지 확인할 수 있다면 무한루프가 발생했는지도 확인 가능하겠죠.

몇가지 방법을 생각나는대로 적어보겠습니다. 아래의 방법들은 물론 Release 빌드에서 사용 가능한 방법들입니다.

1. Process Explorer 를 이용하는 방법
Process Explorer 와 해당 모듈의 PDB  파일이 있으면 Visual Studio나 다른 디버거가 설치되어 있지 않아도 Thread 별 CPU 사용율과 CallStack을 확인할 수 있습니다. 문제 PC에서 즉시 확인해볼 수 있는 가장 간단한 방법이죠. 아래 포스트를 참고하세요.
http://kuaaan.tistory.com/128


2. 메모리 덤프를 작성하여 개발PC로 가져와 분석하는 방법
말 그대로 현상이 재현된 PC에서 해당 프로세스의 메모리 덤프를 작성한 후 개발PC로 가져와서 PDB와 소스코드를 연결해 분석하는 방법입니다. (기술지원해주시는 분들이 이정도만 해주셔도.. 개발자가 아주 편하죠. ^^)

메모리 덤프 작성방법에 대한 내용은 아래 포스트 참고하시구요...
http://kuaaan.tistory.com/213

Exception이 발생하지 않은 경우에는.. 아래와 같은 방법으로 메모리덤프를 작성할 수 있습니다.

   1) 현상이 발생한 PC에 WinDbg를 설치
 
   2) WinDbg를 관리자 권한으로 실행하여 해당 프로세스에 Attach



    3) 아래와 같은 WinDbg 커맨드를 입력하여 메모리 덤프를 작성합니다.
.dump /ma c:\temp\user.dmp


단지 위의 덤프만 뜰 거라면 Windbg 전체를 설치할 필요는 없구요 Debugee PC에 세가지 파일만 복사해놓으면 됩니다. 아래 첨부파일이 그 세가지 파일입니다. ^^

WindbgMinimum.zip




   4) 작성된 메모리덤프를 개발 PC로 가져와서 PDB와 소스코드를 연결하여 분석합니다. 각 Thread별로 CallStack을 확인하면 되겠죠. 덤프 분석하는 방법은 아래 포스트를 참고하세요.
http://kuaaan.tistory.com/214

## 20130905 내용 추가
   5) Hang 현상의 경우 메모리 덤프를 뜰 때 시간 간격을 두고 두개 이상의 덤프를 떠서 서로 비교해야 정확한 분석이 가능합니다. 덤프 하나만으로 분석을 하다보면... 문제의 스레드가 그 위치에서 멈춰있는 건지... 아니면 무한루프를 도는 중에 우연히 그 위치에서 덤프가 작성된건지... 분간이 어려울 때가 있거든요... ^^ 

      덤프를 여러번 작성하시는건... 그냥, go (g 혹은 F5)와 break (ctrl + break)를 몇 차례 반복하면서 서로 다른 이름의 메모리덤프를 생성하시면 됩니다. ^^


   6) CPU 과점유 현상의 경우 어느 스레드가 CPU를 얼마나 사용하는지를 확인하면 분석에 도움이 되겠죠. "!runaway"라는 WinDbg 명령이 도움이 됩니다.

0:000> !runaway

User Mode Time

  Thread       Time

   0:11e4      0 days 0:00:31.122

   1:1048      0 days 0:00:00.000


이 덤프에는 두개의 스레드가 있고, 그중 0번 스레드가 대부분의 CPU시간(31초)를 사용하고 있군요. 다음과 같이 0번 스레드로 컨텍스트를 변경하여 스레드의 콜스택을 확인해볼 수 있습니다. (이건 그냥... 분석의 예입니다. ^^)
0:001> ~0s
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=00000180 edi=00000000
eip=7713f8b1 esp=004dca68 ebp=004dcad4 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!ZwWaitForSingleObject+0x15:
7713f8b1 83c404          add     esp,4
0:000> kvn
 # ChildEBP RetAddr  Args to Child              
00 004dca68 74f6149d 00000180 00000000 00000000 ntdll!ZwWaitForSingleObject+0x15 (FPO: [3,0,0])
01 004dcad4 761a1194 00000180 ffffffff 00000000 KERNELBASE!WaitForSingleObjectEx+0x98 (FPO: [Non-Fpo])
02 004dcaec 761a1148 00000180 ffffffff 00000000 kernel32!WaitForSingleObjectExImplementation+0x75 (FPO: [Non-Fpo])
03 004dcb00 0020012d 00000180 ffffffff 004dfcb0 kernel32!WaitForSingleObject+0x12 (FPO: [Non-Fpo])
04 004dcb10 001f5fc0 00090000 ffffffff 00000000 _LeoLauncher!XUWaitingForDone+0x1d (FPO: [Non-Fpo]) (CONV: thiscall) 
05 004dfcb0 001f734f 001f0000 00000000 00271a10 _LeoLauncher!wWinMain+0x7b0 (FPO: [Non-Fpo]) (CONV: stdcall) 
06 004dfd40 761a33aa 7efde000 004dfd8c 77159ef2 _LeoLauncher!__tmainCRTStartup+0x11a (FPO: [Non-Fpo]) (CONV: cdecl) 
07 004dfd4c 77159ef2 7efde000 7735f6b9 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
08 004dfd8c 77159ec5 001f73a2 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
09 004dfda4 00000000 001f73a2 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])


※ Windows Vista 이후 PC인 경우 단순하게 작업관리자에서 메모리덤프를 작성할 수도 있습니다. 단, x64 OS에서 실행되는 x86 프로세스인 경우(WOW64) 이런 식으로 덤프를 뜨면 덤프가 x64모드로 작성되기 때문에 분석이 어렵습니다. 이 글을 참고하세요. 




3. 문제의 PC에서 직접 분석하는 방법
   뭐 여차하면 문제 PC에서 직접 분석할 수도 있습니다. 메모리덤프란건 스냅샷이기 때문에 어떤 스레드가 어떤 식으로 움직이고 있는지 그 "과정"같은걸 트레이싱해볼 수는 없죠. 이런 경우 해당 PC에서 직접 디버깅을 해보는 방법이 있습니다.

   1) 현상이 재현된 PC에 WinDbg를 설치
   2) 해당 PC에 관련 소스코드와 PDB 파일을 복사하고, 복사된 위치를 WinDbg의 소스코드 경로와 심볼 경로에 설정한다.
   3) 해당 프로세스에 Attach 후 디버깅한다.

뭐 간단하죠. ^^


Posted by kuaaan
,


사랑합니다. 편안히 잠드소서