Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

windbg - k 명령어와 !clrstack을 조합한 호출 스택을 얻는 방법

SOS 확장의 !clrstack 명령어는 관리 호출 스택을 얻을 수 있습니다.

0:000> !clrstack
OS Thread Id: 0x6164 (0)
        Child SP               IP Call Site
000000f26fb6eb28 00007ff97e4c5ef4 [HelperMethodFrame_1OBJ: 000000f26fb6eb28] System.Threading.Thread.JoinInternal(Int32)
000000f26fb6ec30 00007ff904090778 ConsoleApp1.Program.WaitForThreadExit(System.Threading.Thread)
000000f26fb6ec60 00007ff904090634 ConsoleApp1.Program.Main(System.String[])
000000f26fb6ef40 00007ff9636b6793 [GCFrame: 000000f26fb6ef40] 

또한 windbg의 내장 명령어인 k 명령어로는 네이티브 호출 스택을 얻을 수 있습니다.

0:000> k
 # Child-SP          RetAddr           Call Site
00 000000f2`6fb6e4a8 00007ff9`7b29dd20 ntdll!NtWaitForMultipleObjects+0x14
01 000000f2`6fb6e4b0 00007ff9`638569ca KERNELBASE!WaitForMultipleObjectsEx+0xf0
02 000000f2`6fb6e7b0 00007ff9`63856864 clr!WaitForMultipleObjectsEx_SO_TOLERANT+0x62
03 000000f2`6fb6e810 00007ff9`6385665d clr!Thread::DoAppropriateWaitWorker+0x1e4
04 000000f2`6fb6e910 00007ff9`637e37da clr!Thread::DoAppropriateWait+0x7d
05 000000f2`6fb6e990 00007ff9`637e3a68 clr!Thread::JoinEx+0xa2
06 000000f2`6fb6ea30 00007ff9`637e38ec clr!ThreadNative::DoJoin+0xfe
07 000000f2`6fb6eac0 00007ff9`04090778 clr!ThreadNative::Join+0xec
08 000000f2`6fb6ec30 00007ff9`04090634 0x00007ff9`04090778
09 000000f2`6fb6ec60 00007ff9`636b6793 0x00007ff9`04090634
0a 000000f2`6fb6ed10 00007ff9`636b6665 clr!CallDescrWorkerInternal+0x83
0b 000000f2`6fb6ed50 00007ff9`636b736d clr!CallDescrWorkerWithHandler+0x4e
0c 000000f2`6fb6ed90 00007ff9`637b38b0 clr!MethodDescCallSite::CallTargetWorker+0xf8
0d 000000f2`6fb6ee90 00007ff9`637b40fa clr!RunMain+0x1e7
0e 000000f2`6fb6f070 00007ff9`637b3fb7 clr!Assembly::ExecuteMainMethod+0xb6
0f 000000f2`6fb6f360 00007ff9`637b394d clr!SystemDomain::ExecuteMainMethod+0x639
10 000000f2`6fb6f980 00007ff9`637b3732 clr!ExecuteEXE+0x3f
11 000000f2`6fb6f9f0 00007ff9`637b46a4 clr!_CorExeMainInternal+0xb2
12 000000f2`6fb6fa80 00007ff9`6337a56d clr!CorExeMain+0x14
13 000000f2`6fb6fac0 00007ff9`6351a44c mscoreei!CorExeMain+0x112
14 000000f2`6fb6fb20 00007ff9`7df12774 mscoree!CorExeMain_Exported+0x6c
15 000000f2`6fb6fb50 00007ff9`7e490d51 kernel32!BaseThreadInitThunk+0x14
16 000000f2`6fb6fb80 00000000`00000000 ntdll!RtlUserThreadStart+0x21

위의 출력 결과를 보면 중간에 "Call Site"가 주소로만 나오는 영역의 "Child-SP"를 !clrstack과 연결해 보면 실은 관리 메서드 호출임을 알 수 있습니다. 그렇다면 이 2개의 조합된 출력 결과를 얻으려면 어떻게 해야 할까요?

참고로, SOS 확장의 !dumpstack 메서드가 이런 용도로 제공이 되고는 있습니다. 하지만, 아래의 출력 결과에서 볼 수 있는 것처럼 그 내용이 너무 많아 가독성이 많이 떨어집니다.

0:000> !dumpstack
OS Thread Id: 0x6164 (0)
Current frame: ntdll!NtWaitForMultipleObjects+0x14
Child-SP         RetAddr          Caller, Callee
000000f26fb6e4a0 00007ff97b29dd20 KERNELBASE!WaitForMultipleObjectsEx+0xf0, calling ntdll!NtWaitForMultipleObjects
000000f26fb6e4b0 00007ff97e450f20 ntdll!RtlFreeHeap+0x150, calling ntdll!RtlGetCurrentServiceSessionId
000000f26fb6e540 00007ff97b29de1f KERNELBASE!WaitForMultipleObjectsEx+0x1ef, calling ntdll!RtlActivateActivationContextUnsafeFast
000000f26fb6e560 00007ff9636c2471 clr!ListLockEntry::`scalar deleting destructor'+0xe1
000000f26fb6e5a0 00007ff9636b5f7c clr!CrstBase::Leave+0x30, calling ntdll!RtlLeaveCriticalSection
000000f26fb6e5d0 00007ff9636c51dd clr!MethodDesc::MakeJitWorker+0x862, calling clr!CrstBase::Leave
000000f26fb6e660 00007ff9636b6071 clr!ClrFlsIncrementValue+0x29
000000f26fb6e690 00007ff9636c1936 clr!LoaderHeap::RealAllocMemUnsafe+0x236, calling clr!ClrFlsIncrementValue
000000f26fb6e720 00007ff9636b5f7c clr!CrstBase::Leave+0x30, calling ntdll!RtlLeaveCriticalSection
000000f26fb6e740 00007ff963735f08 clr!MethodDesc::IsTightlyBoundToMethodTable+0x21, calling clr!MethodDesc::IsInstantiatingStub
000000f26fb6e750 00007ff9636c1d26 clr!ECall::GetFCallImpl+0x152, calling clr!CrstBase::Leave
000000f26fb6e770 00007ff9636bef85 clr!Precode::SetTargetInterlocked+0x414, calling kernel32!FlushInstructionCacheStub
000000f26fb6e7a0 00007ff9638569ca clr!WaitForMultipleObjectsEx_SO_TOLERANT+0x62, calling kernel32!WaitForMultipleObjectsEx
000000f26fb6e7d0 00007ff9636bba42 clr!Thread::GetFinalApartment+0x1a, calling clr!Thread::GetApartment
000000f26fb6e800 00007ff963856864 clr!Thread::DoAppropriateWaitWorker+0x1e4, calling clr!WaitForMultipleObjectsEx_SO_TOLERANT
000000f26fb6e830 00007ff96379c5f6 clr!ThreadNative::StartInner+0x3ac, calling clr!ObjHeader::LeaveObjMonitor
000000f26fb6e900 00007ff96385665d clr!Thread::DoAppropriateWait+0x7d, calling clr!Thread::DoAppropriateWaitWorker
000000f26fb6e980 00007ff9637e37da clr!Thread::JoinEx+0xa2, calling clr!Thread::DoAppropriateWait
000000f26fb6e9d0 00007ff9637f03eb clr!Thread::IncExternalCount+0x1c, calling clr!GetThread
000000f26fb6ea20 00007ff9637e3a68 clr!ThreadNative::DoJoin+0xfe, calling clr!Thread::JoinEx
000000f26fb6eab0 00007ff9637e38ec clr!ThreadNative::Join+0xec, calling clr!ThreadNative::DoJoin
000000f26fb6ebe8 00007ff9637e3876 clr!ThreadNative::Join+0x76, calling clr!LazyMachStateCaptureState
000000f26fb6ec20 00007ff904090778 (MethodDesc 00007ff903f859c0 +0x28 ConsoleApp1.Program.WaitForThreadExit(System.Threading.Thread)), calling (MethodDesc 00007ff961ee3980 +0 System.Threading.Thread.Join())
000000f26fb6ec50 00007ff904090634 (MethodDesc 00007ff903f859b0 +0x1b4 ConsoleApp1.Program.Main(System.String[])), calling 00007ff904090080 (stub for ConsoleApp1.Program.WaitForThreadExit(System.Threading.Thread))
000000f26fb6ed00 00007ff9636b6793 clr!CallDescrWorkerInternal+0x83
000000f26fb6ed40 00007ff9636b6665 clr!CallDescrWorkerWithHandler+0x4e, calling clr!CallDescrWorkerInternal
000000f26fb6ed50 00007ff9638138af clr!ArgIteratorTemplate<ArgIteratorBase>::GetNextOffset+0xda, calling clr!MetaSig::GetElemSize
000000f26fb6ed80 00007ff9636b736d clr!MethodDescCallSite::CallTargetWorker+0xf8, calling clr!CallDescrWorkerWithHandler
000000f26fb6edd0 00007ff9637b4c69 clr!MethodDesc::IsVoid+0x21, calling clr!MetaSig::IsReturnTypeVoid
000000f26fb6ee80 00007ff9637b38b0 clr!RunMain+0x1e7, calling clr!MethodDescCallSite::CallTargetWorker
000000f26fb6eef0 00007ff97b2b76b3 KERNELBASE!QuirkIsEnabled3+0x23, calling kernel32!QuirkIsEnabled3Worker
000000f26fb6f020 00007ff963823f70 clr!Thread::SetBackground+0x9f, calling clr!ThreadSuspend::UnlockThreadStore
000000f26fb6f060 00007ff9637b40fa clr!Assembly::ExecuteMainMethod+0xb6, calling clr!RunMain
000000f26fb6f090 00007ff97e44af7e ntdll!RtlpAllocateHeapInternal+0xfe, calling ntdll!RtlpLowFragHeapAllocFromContext
000000f26fb6f0e0 00007ff9637fe874 clr!SString::GetUnicode+0x4d, calling clr!_security_check_cookie
000000f26fb6f120 00007ff9638138fe clr!MetaSig::SkipArg+0x2e, calling clr!SigParser::SkipExactlyOne
000000f26fb6f130 00007ff97e451208 ntdll!RtlFreeHeap+0x438, calling ntdll!RtlpIsSubSegmentReuseable
000000f26fb6f170 00007ff9636b6969 clr!EEHeapFreeInProcessHeap+0x45, calling kernel32!HeapFreeStub
000000f26fb6f1a0 00007ff9636ee473 clr!SString::~SString+0x3e
000000f26fb6f1b0 00007ff97e450f20 ntdll!RtlFreeHeap+0x150, calling ntdll!RtlGetCurrentServiceSessionId
000000f26fb6f1e0 00007ff97b28988f KERNELBASE!WaitForSingleObjectEx+0x9f, calling ntdll!NtWaitForSingleObject
000000f26fb6f1f0 00007ff97e450f20 ntdll!RtlFreeHeap+0x150, calling ntdll!RtlGetCurrentServiceSessionId
000000f26fb6f210 00007ff9637643dc clr!AppDomain::GetFriendlyNameForDebugger+0x48, calling clr!SString::GetUnicode
000000f26fb6f270 00007ff9636b6969 clr!EEHeapFreeInProcessHeap+0x45, calling kernel32!HeapFreeStub
000000f26fb6f2c0 00007ff96374bb90 clr!CLRConfig::GetConfigValue+0x14, calling clr!CLRConfig::GetConfigValue
000000f26fb6f2e0 00007ff9636b69b9 clr!operator delete+0x29
000000f26fb6f2f0 00007ff963768b47 clr!MulticoreJitManager::AutoStartProfile+0x60, calling clr!Wrapper<unsigned short * __ptr64,&DoNothing<unsigned short * __ptr64>,&CLRConfig::FreeConfigString,0,&CompareDefault<unsigned short * __ptr64>,2,1>::~Wrapper<unsigned short * __ptr64,&DoNothing<unsigned short * __ptr64>,&CLRConfig::FreeConfigString,0,&CompareDefault<unsigned short * __ptr64>,2,1>
000000f26fb6f310 00007ff9636ee27a clr!Wrapper<IAssemblyName * __ptr64,&DoNothing<IAssemblyName * __ptr64>,&DoTheRelease<IAssemblyName>,0,&CompareDefault<IAssemblyName * __ptr64>,2,1>::~Wrapper<IAssemblyName * __ptr64,&DoNothing<IAssemblyName * __ptr64>,&DoTheRelease<IAssemblyName>,0,&CompareDefault<IAssemblyName * __ptr64>,2,1>+0x52
000000f26fb6f320 00007ff9636b6131 clr!Frame::Pop+0xe, calling clr!GetThread
000000f26fb6f350 00007ff9637b3fb7 clr!SystemDomain::ExecuteMainMethod+0x639, calling clr!Assembly::ExecuteMainMethod
000000f26fb6f380 00007ff9636b4f65 clr!REGUTIL::RegCacheValueNameSeenPerhaps+0x29, calling clr!HashiStringKnownLower80
000000f26fb6f5f0 00007ff9636bd29c clr!AllocateObject+0xbc
000000f26fb6f620 00007ff9636bc7f4 clr!HndCreateHandle+0xe0, calling clr!StressLog::LogOn
000000f26fb6f670 00007ff9638247ad clr!CreateGlobalHandle+0xe, calling clr!GetCurrentThreadHomeHeapNumber
000000f26fb6f6a0 00007ff96377a593 clr!AppDomain::SetupSharedStatics+0xf0, calling clr!ErectWriteBarrier
000000f26fb6f6c0 00007ff9637a55d5 clr!SafeHandle::Init+0x41, calling clr!MethodDesc::GetSlot
000000f26fb6f6f0 00007ff9637ac915 clr!EEStartupHelper+0x795, calling clr!ConfigDWORD::val
000000f26fb6f910 00007ff9637ac155 clr!EEStartup+0x15, calling clr!EEStartupHelper
000000f26fb6f970 00007ff9637b394d clr!ExecuteEXE+0x3f, calling clr!SystemDomain::ExecuteMainMethod
000000f26fb6f9e0 00007ff9637b3732 clr!_CorExeMainInternal+0xb2, calling clr!ExecuteEXE
000000f26fb6fa40 00007ff97e47a670 ntdll!RtlSetLastWin32Error+0x40, calling ntdll!_security_check_cookie
000000f26fb6fa70 00007ff9637b46a4 clr!CorExeMain+0x14, calling clr!_CorExeMainInternal
000000f26fb6fab0 00007ff96337a56d mscoreei!CorExeMain+0x112
000000f26fb6fae0 00007ff963511504 mscoree!GetShimImpl+0x18, calling mscoree!InitShimImpl
000000f26fb6faf0 00007ff96351a4cf mscoree!CorExeMain_Exported+0xef, calling kernel32!GetProcAddressStub
000000f26fb6fb10 00007ff96351a44c mscoree!CorExeMain_Exported+0x6c, calling mscoree!guard_dispatch_icall_nop
000000f26fb6fb40 00007ff97df12774 kernel32!BaseThreadInitThunk+0x14, calling kernel32!guard_dispatch_icall_nop
000000f26fb6fb70 00007ff97e490d51 ntdll!RtlUserThreadStart+0x21, calling ntdll!guard_dispatch_icall_nop

그래서 개인적으로 사용하는 방법이 "DebugDiag Analysis" 도구입니다.

Debug Diagnostic Tool v2 Update 2 
; https://www.microsoft.com/en-us/download/details.aspx?id=49924

이것을 사용하면 분석 결과로 개별 스레드에 대해 ".NET Call Stack"과 "Full Call Stack"을 각각 다음과 같은 식으로 보여줍니다.

.NET Call Stack

[[HelperMethodFrame_1OBJ] (System.Threading.Thread.JoinInternal)] System.Threading.Thread.JoinInternal(Int32) 
ConsoleApp1.Program.WaitForThreadExit(System.Threading.Thread)+28 
ConsoleApp1.Program.Main(System.String[])+1b4 

Full Call Stack

ntdll!NtWaitForMultipleObjects+14 
KERNELBASE!WaitForMultipleObjectsEx+f0 
clr!WaitForMultipleObjectsEx_SO_TOLERANT+62 
clr!Thread::DoAppropriateWaitWorker+1e4 
clr!Thread::DoAppropriateWait+7d 
clr!Thread::JoinEx+a2 
clr!ThreadNative::DoJoin+fe 
clr!ThreadNative::Join+ec 
[[HelperMethodFrame_1OBJ] (System.Threading.Thread.JoinInternal)] System.Threading.Thread.JoinInternal(Int32) 
ConsoleApp1.Program.WaitForThreadExit(System.Threading.Thread)+28 
ConsoleApp1.Program.Main(System.String[])+1b4 
clr!CallDescrWorkerInternal+83 
clr!CallDescrWorkerWithHandler+4e 
clr!MethodDescCallSite::CallTargetWorker+f8 
clr!RunMain+1e7 
[[GCFrame]] 
clr!Assembly::ExecuteMainMethod+b6 
clr!SystemDomain::ExecuteMainMethod+639 
clr!ExecuteEXE+3f 
clr!_CorExeMainInternal+b2 
clr!CorExeMain+14 
mscoreei!CorExeMain+112 
mscoree!CorExeMain_Exported+6c 
kernel32!BaseThreadInitThunk+14 
ntdll!RtlUserThreadStart+21 

즉, 다듬어진 내용으로 k 명령어와 !clrstack의 출력 결과가 합쳐져서 보이는 것입니다.

이런저런 이유와 함께 저는 메모리 덤프 파일을 분석할 때면 무조건 "DebugDiag Analysis" 도구로 분석 결과를 생성한 후 같이 참조하면서 windbg로 분석합니다. ^^




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 10/18/2017]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 31  32  33  34  35  36  37  38  39  [40]  41  42  43  44  45  ...
NoWriterDateCnt.TitleFile(s)
12627정성태5/4/202110300Linux: 38. 라즈베리 파이 제로 용 프로그램 개발을 위한 Eclipse C/C++ 윈도우 환경 설정
12626정성태5/3/202110285.NET Framework: 1056. C# - Thread.Suspend 호출 시 응용 프로그램 hang 현상 (2)파일 다운로드1
12625정성태5/3/20219259오류 유형: 714. error CS5001: Program does not contain a static 'Main' method suitable for an entry point
12624정성태5/2/202113042.NET Framework: 1055. C# - struct/class가 스택/힙에 할당되는 사례 정리 [10]파일 다운로드1
12623정성태5/2/20219692.NET Framework: 1054. C# 9 최상위 문에 STAThread 사용 [1]파일 다운로드1
12622정성태5/2/20216472오류 유형: 713. XSD 파일을 포함한 프로젝트 - The type or namespace name 'TypedTableBase<>' does not exist in the namespace 'System.Data'
12621정성태5/1/202110123.NET Framework: 1053. C# - 특정 레지스트리 변경 시 알림을 받는 방법 [1]파일 다운로드1
12620정성태4/29/202112047.NET Framework: 1052. C# - 왜 구조체는 16 바이트의 크기가 적합한가? [1]파일 다운로드1
12619정성태4/28/202112565.NET Framework: 1051. C# - 구조체의 크기가 16바이트가 넘어가면 힙에 할당된다? [2]파일 다운로드1
12618정성태4/27/202111068사물인터넷: 58. NodeMCU v1 ESP8266 CP2102 Module을 이용한 WiFi UDP 통신 [1]파일 다운로드1
12617정성태4/26/20218774.NET Framework: 1050. C# - ETW EventListener의 Keywords별 EventId에 따른 필터링 방법파일 다운로드1
12616정성태4/26/20218771.NET Framework: 1049. C# - ETW EventListener를 상속받았을 때 초기화 순서파일 다운로드1
12615정성태4/26/20216927오류 유형: 712. Microsoft Live 로그인 - 계정을 선택하는(Pick an account) 화면에서 진행이 안 되는 문제
12614정성태4/24/20219619개발 환경 구성: 570. C# - Azure AD 인증을 지원하는 ASP.NET Core/5+ 웹 애플리케이션 예제 구성 [4]파일 다운로드1
12613정성태4/23/20218646.NET Framework: 1048. C# - ETW 이벤트의 Keywords에 속한 EventId 구하는 방법 (2) 관리 코드파일 다운로드1
12612정성태4/23/20218774.NET Framework: 1047. C# - ETW 이벤트의 Keywords에 속한 EventId 구하는 방법 (1) PInvoke파일 다운로드1
12611정성태4/22/20218028오류 유형: 711. 닷넷 EXE 실행 오류 - Mixed mode assembly is build against version 'v2.0.50727' of the runtime
12610정성태4/22/20217860.NET Framework: 1046. C# - 컴파일 시점에 참조할 수 없는 타입을 포함한 이벤트 핸들러를 Reflection을 이용해 구독하는 방법파일 다운로드1
12609정성태4/22/20219159.NET Framework: 1045. C# - 런타임 시점에 이벤트 핸들러를 만들어 Reflection을 이용해 구독하는 방법파일 다운로드1
12608정성태4/21/202110169.NET Framework: 1044. C# - Generic Host를 이용해 .NET 5로 리눅스 daemon 프로그램 만드는 방법 [9]파일 다운로드1
12607정성태4/21/20218698.NET Framework: 1043. C# - 실행 시점에 동적으로 Delegate 타입을 만드는 방법파일 다운로드1
12606정성태4/21/202112672.NET Framework: 1042. C# - enum 값을 int로 암시적(implicit) 형변환하는 방법? [2]파일 다운로드1
12605정성태4/18/20218659.NET Framework: 1041. C# - AssemblyID, ModuleID를 관리 코드에서 구하는 방법파일 다운로드1
12604정성태4/18/20217384VS.NET IDE: 163. 비주얼 스튜디오 속성 창의 "Build(빌드)" / "Configuration(구성)"에서의 "활성" 의미
12603정성태4/16/20218271VS.NET IDE: 162. 비주얼 스튜디오 - 상속받은 컨트롤이 디자인 창에서 지원되지 않는 문제
12602정성태4/16/20219486VS.NET IDE: 161. x64 DLL 프로젝트의 컨트롤이 Visual Studio의 Designer에서 보이지 않는 문제 [1]
... 31  32  33  34  35  36  37  38  39  [40]  41  42  43  44  45  ...