windbg 사례 - .NET 예외가 발생한 시점의 오류 분석
이상하게 특정 상황에서 System.TypeInitializationException 예외가 발생하는 현상이 나왔습니다. 다행히 항상 발생해서 다음과 같이 프로세스 덤프를 떠 상황을 살펴봤습니다.
procdump -ma -e 1 -f TypeInit* [...process id...]
windbg에서 덤프 파일을 로드하고 sos 확장을 올린 후,
0:085> .load C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\sos.dll
System.TypeInitializationException 예외가 발생한 스레드를 찾아,
0:085> !threads
DBGHELP: mscorwks - public symbols
d:\symbols\mscorwks.pdb\39E8C83B21A943B2B2DBC56A5E85676A1\mscorwks.pdb
ThreadCount: 64
UnstartedThread: 0
BackgroundThread: 64
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
PreEmptive Lock
ID OSID ThreadOBJ State GC GC Alloc Context Domain Count APT Exception
14 1 3c4 00000000036a8580 1808228 Enabled 00000000c06ae3a0:00000000c06af788 0000000000128a60 0 MTA (Threadpool Worker)
18 2 15cc 00000000036b13a0 b228 Enabled 0000000080436ec8:0000000080437110 0000000000128a60 0 MTA (Finalizer)
19 3 197c 00000000047822b0 80a228 Enabled 0000000000000000:0000000000000000 0000000000128a60 0 MTA (Threadpool Completion Port)
...[생략]...
85 43 c34 000000000b326010 188b228 Enabled 0000000080851f98:0000000080853338 000000000493cc00 1 MTA (Threadpool Worker) System.TypeInitializationException (00000000c039d708)
86 56 1230 000000000a54d010 880b228 Enabled 0000000080478468:0000000080479220 0000000000128a60 0 MTA (Threadpool Completion Port)
...[생략]...
대상 스레드로 문맥 전환을 하고,
0:085> ~85s
예외를 조사했습니다.
0:085> !pe
Exception object: 00000000c039d708
Exception type: System.TypeInitializationException
Message: The type initializer for 'TestLib.MyTestClass' threw an exception.
InnerException: System.AccessViolationException, use !PrintException 00000000c039d4e8 to see more
StackTrace (generated):
SP IP Function
000000000946DFA0 0000000000000001 TestWebSite!TestLib.MyTestClass..ctor()+0x2
000000000946E070 0000064281C70533 TestWebSite!TestLib.TempWebPage.Page_Load(System.Object, System.EventArgs)+0x63
StackTraceString: <none>
HResult: 80131534
친절하게 InnerException을 살펴보라고 하는데,
0:085> !PrintException 00000000c039d4e8
Exception object: 00000000c039d4e8
Exception type: System.AccessViolationException
Message: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
InnerException: <none>
StackTrace (generated):
SP IP Function
000000000F25CAE0 0000000000000001 TestWebSite!TestLib.MyTestClass..cctor()+0x2
StackTraceString: <none>
HResult: 80004003
딱히 정보가 없습니다. 혹시나 해서 대상 메서드를 좀 더 조사해봤지만,
0:085> !name2ee TestWebSite!TestLib.MyTestClass..cctor
Module: 00000642803f6008 (TestWebSite.DLL)
Token: 0x0000000006000360
MethodDesc: 0000064281cb8210
Name: TestLib.MyTestClass..cctor()
Not JITTED yet. Use !bpmd -md 0000064281cb8210 to break on run.
0:085> !dumpmd 0000064281cb8210
Method Name: TestLib.MyTestClass..cctor()
Class: 0000064281cd2c40
MethodTable: 0000064281cb8218
mdToken: 06000360
Module: 00000642803f6008
IsJitted: no
CodeAddr: ffffffffffffffff
0:085> !dumpil 0000064281cb8210
ilAddr = 000000001000db65
IL_0000: ldc.i4.1
IL_0001: stsfld TestLib.MyTestClass::_isFirst
IL_0006: ret
보는 바와 같이, JIT 컴파일되지도 않았기 때문에 System.AccessViolationException이 발생할만한 상황도 아니었고, 게다가 dumpil 명령어로 확인한 cctor의 코드는 어떤 포인터 연산도 포함하지 않았습니다. clrstack을 봐도 System.AccessViolationException 예외가 발생하기 바로 직전의 메서드는 확인할 수 없었고,
0:085> !clrstack
OS Thread Id: 0xc34 (85)
Child-SP RetAddr Call Site
000000000946e070 0000064280bb5719 TestLib.TempWebPage.Page_Load(System.Object, System.EventArgs)
000000000946e0d0 0000064280bb56d4 System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
000000000946e100 0000064280bb5675 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
...[생략]...
000000000946e570 000006428066a599 System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext, System.AsyncCallback, System.Object)
000000000946e5c0 0000064280667178 System.Web.HttpRuntime.ProcessRequestInternal(System.Web.HttpWorkerRequest)
000000000946e630 000006427f5fcda2 System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr, Int32)
Native 콜 스택 결과도 마찬가지였습니다.
0:085> kv
Child-SP RetAddr : Args to Child : Call Site
00000000`0946a798 00000000`77d706af : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!ZwWaitForSingleObject+0xa
00000000`0946a7a0 00000642`7f494b46 : 00000000`00001a0c 00000000`00000000 00000000`00000000 00000000`ffffffff : kernel32!WaitForSingleObjectEx+0x130
00000000`0946a840 00000642`7f494a4f : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : mscorwks!CLREvent::WaitEx+0x15a
00000000`0946a8a0 00000642`7f8ba79b : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : mscorwks!CLREvent::WaitEx+0x63
00000000`0946a950 00000642`7f8baa01 : 00000002`000003f0 00000000`00000000 00000000`00000006 00000000`0180b228 : mscorwks!Thread::WaitSuspendEventsHelper+0xdb
00000000`0946aa20 00000642`7f7af02c : 00000000`00000048 00000000`0b326010 00000002`000003f0 00000642`7f514eb0 : mscorwks!Thread::WaitSuspendEvents+0x11
00000000`0946aa50 00000642`7f9fb68e : ffffffff`fffffffe 00000642`7f55353b 00000000`00141950 00000000`0b326010 : mscorwks! ?? ::FNODOBFM::`string'+0x2170c
00000000`0946aaa0 00000642`7f966b38 : 00000000`0946abc0 00000000`00000000 00000000`00141950 00000000`00000006 : mscorwks!Thread::RareDisablePreemptiveGC+0x10e
00000000`0946ab40 00000642`7f96701a : 00000000`0b326010 00000642`7f53716c 00000000`0476afd0 00000000`0946c090 : mscorwks!Debugger::SendException+0x518
00000000`0946b110 00000642`7f8341ef : 00000000`036a65b8 00000000`0b326010 00000000`04e038e0 00000642`00000000 : mscorwks!Debugger::FirstChanceManagedException+0x2a
00000000`0946b170 00000642`7f4fe870 : 00000000`036a6580 00000000`0946c090 00000000`0946e070 00000000`00000000 : mscorwks! ?? ::FNODOBFM::`string'+0xa68cf
00000000`0946b3c0 00000642`7f4ffcff : 00000642`81c70532 00000642`81cd2e5c 00000000`0946ced0 00000000`0946c398 : mscorwks!ExceptionTracker::ProcessOSExceptionNotification+0x430
00000000`0946c280 00000000`77ee3d4d : 00000642`00000001 00000000`0946e070 00000000`0946ced0 00000000`00000000 : mscorwks!ProcessCLRException+0x19b
00000000`0946c320 00000000`77ee5857 : 00000000`00000001 00000000`00000001 00000000`0946ced0 00000000`0946dfa0 : ntdll!RtlpExecuteHandlerForException+0xd
00000000`0946c350 00000000`77ef2a3d : fffffadf`b37bfeb0 00000000`0946ca00 00000642`81cb8218 00000642`81cb8218 : ntdll!RtlDispatchException+0x1b4
00000000`0946ca00 00000000`77d4dce0 : 00000000`0b326010 00000642`81cb8218 00000000`e0434f4d 00000000`0b326010 : ntdll!KiUserExceptionDispatch+0x2d (TrapFrame @ 00000000`0946ce08)
00000000`0946cfa0 00000642`7f475c05 : 00000000`0b326010 00000642`81cb8218 00000000`e0434f4d 00000000`0b326010 : kernel32!RaiseException+0x5c
00000000`0946d070 00000642`7f8a5b57 : 00000000`c039d708 00000000`00000000 00000642`00000000 00000642`00000001 : mscorwks!RaiseTheExceptionInternalOnly+0x295
00000000`0946d140 00000642`7f8a6866 : 00002026`00000001 00000642`00000000 00009fca`5c79603c 00000000`0f355128 : mscorwks!RaiseTheException+0x57
00000000`0946d170 00000642`7f929d55 : 00000642`81cb8218 00000642`81cb8218 00000000`00000000 00000000`0a4010e0 : mscorwks!BStrFromString+0x66
00000000`0946d1a0 00000642`7f929d6b : 00000000`c039d708 00000000`0a4010e0 00000000`00000000 00000000`0a4010e0 : mscorwks!RealCOMPlusThrow+0x35
00000000`0946d210 00000642`7f80be5e : 00000642`81cb8218 00000642`81cb8218 00000000`00000000 00000000`0a4010e0 : mscorwks!RealCOMPlusThrow+0xb
00000000`0946d240 00000642`7f97f6f8 : 00000000`000001f0 00000642`81cb8218 00000000`00000191 00000642`803f7630 : mscorwks! ?? ::FNODOBFM::`string'+0x7e53e
00000000`0946dcf0 00000642`7f4d71f2 : 00000000`c00afea8 00000000`00000000 00000000`00000000 00000642`7f4e7d5e : mscorwks!MethodTable::CheckRunClassInitThrowing+0x68
00000000`0946dd30 00000642`7f4c9ebb : 00000000`c00b4188 00000000`00000000 00000000`00000000 00000000`0946e1e0 : mscorwks!MethodDesc::DoPrestub+0x192
00000000`0946dee0 00000642`7f5fcc87 : 00000000`808514e0 00000000`c0023820 00000000`8084d918 00000000`0b326010 : mscorwks!PreStubWorker+0x1eb
00000000`0946dfa0 00000642`81c70532 : 00000000`80851ec0 00000000`80851ed8 00000000`c0023820 00000000`c0023820 : mscorwks!ThePreStubAMD64+0x87
00000000`0946e070 00000642`80bb5719 : 00000000`8084d918 00000000`8084d918 00000000`c0023820 00000642`8080ff12 : 0x642`81c70532
00000000`0946e0d0 00000642`80bb56d4 : 00000000`8084d918 00000642`80b36250 00000000`8084d918 00000000`c0023820 : 0x642`80bb5719
00000000`0946e100 00000642`80bb5675 : 00000000`8084d918 00000642`8080ff12 00000000`80851dd8 00000000`80851dd8 : 0x642`80bb56d4
00000000`0946e130 00000642`80bb5532 : 00000000`808514e0 00000642`80667839 00000000`8084d918 00000000`00000000 : 0x642`80bb5675
00000000`0946e170 00000642`80b220d7 : 00000000`8084d918 00000000`0946e1e8 00000000`c03a6901 00000000`0946e201 : 0x642`80bb5532
00000000`0946e1c0 00000642`80b18c5a : 00000000`8084d918 00000000`8084d901 00000000`c04eb001 00000642`8066c08f : 0x642`80b220d7
00000000`0946e280 00000642`80b18b1e : 00000000`8084d918 00000000`80846f78 00000000`8084d901 00000000`0946e3e0 : 0x642`80b18c5a
00000000`0946e2e0 00000642`80b141c7 : 00000000`8084d918 00000642`80a5c431 00000000`80846f78 00000001`00000001 : 0x642`80b18b1e
00000000`0946e340 00000642`81c6fea4 : 00000000`80846f78 00000000`80846f78 00000000`8084d918 00000000`0946e3e0 : 0x642`80b141c7
00000000`0946e390 00000642`80a5c184 : 00000000`8084d918 00000000`80846f78 00000000`c00030d0 00000642`80660546 : 0x642`81c6fea4
00000000`0946e3c0 00000642`80a229d1 : 00000000`80244a80 c2000001`60008e8c 00000000`80242908 00000000`8084b668 : 0x642`80a5c184
00000000`0946e450 00000642`80a20949 : 00000000`80242908 00000000`80244a80 00000000`0946e4f8 00000642`8046a592 : 0x642`80a229d1
00000000`0946e4d0 00000642`80a2056c : 00000000`802447c8 00000000`00000000 00000000`80032528 00000642`80a204ad : 0x642`80a20949
00000000`0946e570 00000642`8066a599 : 00000000`7fff3c60 00000000`0946e650 48d3681c`1b957ce1 00000000`00000000 : 0x642`80a2056c
00000000`0946e5c0 00000642`80667178 : 00000000`c0002ab8 00000000`80846640 00000000`0946e948 00000000`00000002 : 0x642`8066a599
00000000`0946e630 00000642`7f5fcda2 : 00000000`8003e260 00000000`02fe0950 00000000`00000002 ffffffff`fffffffe : 0x642`80667178
00000000`0946e740 00000642`7f5069f3 : 00000000`0946e820 00000000`0946e8f0 ffffffff`fffffffe 00000000`00000000 : mscorwks!CallDescrWorker+0x82
00000000`0946e7a0 00000642`7f521e10 : 00000000`0946e930 00000000`0946eef0 00000000`00000003 00000000`00000003 : mscorwks!CallDescrWorkerWithHandler+0xd3
00000000`0946e840 00000642`7f52217b : 00000000`03314460 00000000`00081800 00000000`00000000 00000642`00000004 : mscorwks!ForwardCallToManagedMethod+0x160
00000000`0946e8e0 00000642`7f542918 : 00000000`0493cc00 00000000`0b326010 ffffffff`fffffffe 00000000`0b326260 : mscorwks!COMToCLRWorkerBody+0x35b
00000000`0946eb40 00000642`7f496506 : 00000000`00000000 00000000`0946ecb8 00000000`0946ef30 00000000`00000000 : mscorwks!COMToCLRWorkerDebuggerWrapper+0x50
00000000`0946ebb0 00000642`7f5fcf1e : 00000000`0b326010 00000000`0946ef30 00000000`02fd4800 00000000`00000000 : mscorwks!COMToCLRWorker+0x366
00000000`0946eea0 00000642`fff582b3 : 00000000`04dbff20 00000000`02fe0950 00000000`00000002 00000000`0946ef90 : mscorwks!GenericComCallStub+0x5e
00000000`0946ef50 00000642`fff58693 : ffffffff`fffffffe 00000000`02fe0950 00000000`0a1ab230 00000000`00000001 : webengine!HttpCompletion::ProcessRequestInManagedCode+0x2a3
00000000`0946f400 00000642`fff9ad04 : 00000642`7fc08ca8 00000642`7fc08ca8 00000642`fff9ace0 00000000`00000001 : webengine!HttpCompletion::ProcessCompletion+0x63
00000000`0946f440 00000642`7f48feb7 : ffffffff`fffffffe 00000000`00000001 00000000`00000000 00000000`00000001 : webengine!CorThreadPoolWorkitemCallback+0x24
00000000`0946f470 00000642`7f4a7bea : 00000000`00000000 00000000`00000000 00000000`00000002 00000000`0b326010 : mscorwks!UnManagedPerAppDomainTPCount::DispatchWorkItem+0x157
00000000`0946f510 00000642`7f421304 : 00000000`00000000 00000000`00000000 00000000`0946ff50 00000000`00000000 : mscorwks!ThreadpoolMgr::WorkerThreadStart+0x1ba
00000000`0946f5b0 00000000`77d6b8ca : 00000000`77d6b890 00000000`00000000 00000000`00000000 00000000`0946ffa8 : mscorwks!Thread::intermediateThreadProc+0x78
00000000`0946ff80 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadStart+0x3a
상황을 보아하니, 아마도 System.TypeInitializationException 예외가 잡히는 시점에는 이미 오류 문맥을 벗어난 것이 아닌가... 하는 생각이 들었습니다. 어쨌든 System.TypeInitializationException 예외 이전에 System.AccessViolationException 예외가 발생한다는 사실을 알았으므로 procdump.exe를 이용해 다시 한번 System.AccessViolationException을 조건으로 덤프를 떴습니다.
procdump -ma -e 1 -f AccessVio* 3628
sos 확장도 다시 로드하고 System.AccessViolationException 예외가 발생한 스레드로 문맥 전환을 한 후, clrstack 명령어를 확인했지만 여전히 관리 코드내에서의 직접적인 원인은 나오지 않았습니다.
0:048> !clrstack
OS Thread Id: 0xcf0 (48)
*** WARNING: Unable to verify checksum for TestUnmanaged64.dll
*** ERROR: Symbol file could not be found. Defaulted to export symbols for TestUnmanaged64.dll -
Child-SP RetAddr Call Site
000000000dcfdd70 0000064280b2e5b9 TestLib.TempWebPage.Page_Load(System.Object, System.EventArgs)
000000000dcfddd0 0000064280b2e574 System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr, System.Object, System.Object, System.EventArgs)
000000000dcfde00 0000064280b2e515 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(System.Object, System.EventArgs)
000000000dcfde30 0000064280b2e3d2 System.Web.UI.Control.OnLoad(System.EventArgs)
000000000dcfde70 0000064280b26337 System.Web.UI.Control.LoadRecursive()
000000000dcfdec0 0000064280b1855a System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
000000000dcfdf80 0000064280b1841e System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
000000000dcfdfe0 0000064280b13b47 System.Web.UI.Page.ProcessRequest()
000000000dcfe040 0000064281896f94 System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
000000000dcfe090 0000064280a5bbb4 ASP.j5_TempWebPage_aspx.ProcessRequest(System.Web.HttpContext)
000000000dcfe0c0 0000064280a22371 System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
000000000dcfe150 0000064280a202e9 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
000000000dcfe1d0 000006428080fc1c System.Web.HttpApplication+ApplicationStepManager.ResumeSteps(System.Exception)
000000000dcfe270 000006428066a599 System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext, System.AsyncCallback, System.Object)
000000000dcfe2c0 0000064280667178 System.Web.HttpRuntime.ProcessRequestInternal(System.Web.HttpWorkerRequest)
000000000dcfe330 000006427f5fcda2 System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr, Int32)
그런데, native 콜 스택에는 제가 작성한 함수의 콜 스택이 나왔습니다.
0:048> kv
Child-SP RetAddr : Args to Child : Call Site
00000000`0dcf2e78 00000000`77d706af : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!ZwWaitForSingleObject+0xa
...[생략]...
00000000`0dcf3220 00000642`7f96701a : 00000000`067a11d0 00000642`7f53716c 00000000`00000001 00000000`00000000 : mscorwks!Debugger::SendException+0x518
00000000`0dcf37f0 00000642`7f8341ef : 00000000`0383de98 00000000`067a11d0 00000000`05022198 00000642`00000000 : mscorwks!Debugger::FirstChanceManagedException+0x2a
00000000`0dcf3850 00000642`7f4fe870 : 00000000`0383de60 00000000`0dcf4770 00000000`0dcfdd70 00000000`00000000 : mscorwks! ?? ::FNODOBFM::`string'+0xa68cf
00000000`0dcf3aa0 00000642`7f4ffcff : 00000642`818976b2 00000642`81c8613c 00000000`0dcf55b0 00000000`0dcf4a78 : mscorwks!ExceptionTracker::ProcessOSExceptionNotification+0x430
00000000`0dcf4960 00000000`77ee3d4d : 00000642`00000000 00000000`0dcfdd70 00000000`0dcf55b0 00000000`00000000 : mscorwks!ProcessCLRException+0x19b
00000000`0dcf4a00 00000000`77ee5857 : 00000000`00000001 00000000`00000000 00000000`0dcf55b0 00000000`0dcfdca0 : ntdll!RtlpExecuteHandlerForException+0xd
00000000`0dcf4a30 00000000`77ef2a3d : 00000000`00000000 00000000`0dcf50e0 00000000`000000c0 00000000`0dcf7960 : ntdll!RtlDispatchException+0x1b4
00000000`0dcf50e0 00000001`80013f70 : 00000000`000000bf 00000000`0a7c4f40 00000001`800809c0 00000000`00000001 : ntdll!KiUserExceptionDispatch+0x2d (TrapFrame @ 00000000`0dcf54e8)
00000000`0dcf5680 00000001`8001b21c : 00000000`0000001c 00000000`0000001c 00000001`80081e20 00000000`000000c0 : TestUnmanaged64+0x13f70
00000000`0dcf5740 00000001`8001379d : 00000000`0dcf63e0 00000000`00000000 00000001`800813b8 00000000`0dcf64c0 : TestUnmanaged64+0x1b21c
00000000`0dcf61b0 00000001`80026848 : 00000000`00000200 00000000`00000000 00720065`00660069 0057002e`00300034 : TestUnmanaged64+0x1379d
00000000`0dcf7910 00000001`8002427a : 00000000`09e568a0 00000000`00000000 00000000`00000000 00000642`803f6008 : TestUnmanaged64+0x26848
00000000`0dcf8040 00000001`800228ef : 00000000`00158330 00000000`0015e208 00000000`0015e208 00000000`06612ed0 : TestUnmanaged64+0x2427a
00000000`0dcfd7d0 00000642`ff8d6443 : 00000000`0aa3b398 00000642`7fc136c0 00000000`0dcfd8b0 00000642`7f4bb54e : TestUnmanaged64+0x228ef
...[생략]...
단지 PDB가 올라오지 않아 "TestUnmanaged64+0x1b21c" 와 같은 식으로만 콜 스택이 나오는 군요. 실제로 lm 으로 확인해 보니 해당 DLL의 pdb가 deferred로 표시되어 있습니다.
0:048> lm
start end module name
00000000`00400000 00000000`00406000 w3wp (deferred)
...[생략]...
00000000`13760000 00000000`1395b000 sybdrvado20 (deferred)
00000000`13970000 00000000`139a3000 WebTestHelper64 (deferred)
00000000`13a60000 00000000`13a6a000 App_Web_h4pa_7ul (deferred)
00000001`80000000 00000001`800c3000 TestUnmanaged64 (deferred)
...[생략]...
000007ff`7fee0000 000007ff`7ffe9000 advapi32 (deferred)
Unloaded modules:
000007ff`7b0f0000 000007ff`7b20e000 RichEd20.dll
000007ff`79230000 000007ff`7924e000 digest.dll
000007ff`7dd50000 000007ff`7dd95000 schannel.dll
00000642`ff4a0000 00000642`ff4aa000 culture.dll
재미있는 것은, TestUnmanaged64.dll이 위치한 동일한 폴더에 TestUnmanaged64.pdb 파일이 있었는데도 ".realod -f" 명령어로는 PDB가 올라오지 않았다는 점입니다.
0:048> .reload -f
...................................*** ERROR: Module load completed but symbols could not be loaded for iisres.dll
Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long.
Run !sym noisy before .reload to track down problems loading symbols.
.........................*** WARNING: Unable to verify checksum for TestUnmanaged64.dll
*** ERROR: Symbol file could not be found. Defaulted to export symbols for TestUnmanaged64.dll -
어쩔 수 없군요. 이럴 때는 noisy 모드를 켜고,
0:048> !sym noisy
noisy mode - symbol prompts on
다시 한번 .reload -f 명령어를 내리면 windbg가 찾으려는 PDB 경로가 함께 출력되므로 이를 검사하면 됩니다.
...[생략]...
SYMSRV: d:\symbols\TestUnmanaged64.pdb\91F30530ADD344D3895F7478DC17499C1\TestUnmanaged64.pdb not found
SYMSRV: http://msdl.microsoft.com/download/symbols/TestUnmanaged64.pdb/91F30530ADD344D3895F7478DC17499C1/TestUnmanaged64.pdb not found
DBGHELP: D:\TestWebSite\TestUnmanaged\bin\Release\TestUnmanaged64.pdb - file not found
*** WARNING: Unable to verify checksum for TestUnmanaged64.dll
*** ERROR: Symbol file could not be found. Defaulted to export symbols for TestUnmanaged64.dll -
DBGHELP: TestUnmanaged64 - export symbols
...[생략]...
저 3개의 경로 중 하나에만 넣어주면 되는데요. 제 경우에는 그냥 "D:\TestWebSite\TestUnmanaged\bin\Release\TestUnmanaged64.pdb"로 위치시키고 다시 .reload -f를 내려 로드를 했습니다. 그럼, 이번에는 다음과 같이 "private symbols & lines" 메시지를 통해 PDB를 정상적으로 로드했음을 확인할 수 있습니다.
...[생략]...
SYMSRV: d:\symbols\TestUnmanaged64.pdb\91F30530ADD344D3895F7478DC17499C1\TestUnmanaged64.pdb not found
SYMSRV: http://msdl.microsoft.com/download/symbols/TestUnmanaged64.pdb/91F30530ADD344D3895F7478DC17499C1/TestUnmanaged64.pdb not found
*** WARNING: Unable to verify checksum for TestUnmanaged64.dll
DBGHELP: TestUnmanaged64 - private symbols & lines
...[생략]...
이 상태에서 kv 콜 스택을 확인하면... 와~~~ ^^
0:048> kv
DBGHELP: kernel32 - public symbols
d:\symbols\kernel32.pdb\19C002F7F64C463C91C1E8CEDF84B0252\kernel32.pdb
Child-SP RetAddr : Args to Child : Call Site
00000000`0dcf2e78 00000000`77d706af : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!ZwWaitForSingleObject+0xa
00000000`0dcf2e80 00000642`7f494b46 : 00000000`00000eb8 00000000`00000000 00000000`00000000 00000000`ffffffff : kernel32!WaitForSingleObjectEx+0x130
...[생략]....
00000000`0dcf5680 00000001`8001b21c : 00000000`0000001c 00000000`0000001c 00000001`80081e20 00000000`000000c0 : TestUnmanaged64!MyNativeType::TestMethod+0x60 [d:\TestWebSite\TestUnmanaged64\MyNativeType.cpp @ 2341]
...[생략]....
00000000`0dcfff80 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadStart+0x3a
소스 코드 라인 번호까지 나왔으니... 게임 끝입니다. ^^
이 문제에서 재미있었던 점이 하나 있는데요. 해당 문제는 Unmanaged 환경의 C++ 코드에서 발생했기 때문에 사실 C/C++의 AccessViolation 예외가 발생하는 것이 정상입니다. 대충 이런 식이어야 하는데요.
Unhandled exception at 0x0fc716b7 (TestUnmanaged64.dll) in w3wp.exe: 0xC0000005: Access violation.
그런데, 쌩뚱맞게도 그것이 Managed 수준으로 넘어와 System.AccessViolationException 예외가 던져졌기 때문에 문제 파악에 혼란이 온 것입니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]