Windbg学习20(!htrace) .
1.!htrace
!htrace(Handle Trace) 扩展用于显示一个或多个句柄的堆栈回溯信息。
直接用!htrace -?可以看到简单使用说明:
0:000> !htrace -? !htrace [handle [max_traces]] !htrace -enable [max_traces] !htrace -disable !htrace -snapshot !htrace -diff
首先需要用!htrace -enable来告诉操作系统启用栈回溯(这是前提)
!htrace -snapshot !htrace -diff 0:000> !htrace -enable Handle tracing enabled. Handle tracing information snapshot successfully taken.
可以看到,-enable是一个两步操作,首先,启动栈回溯(Handle tracing enabled),
然后,它根据句柄来抓取进程当前状态的快照(Handle tracing information snapshot successfully taken.)
在栈回溯被启用后,windows将立即开始记录所有的句柄创建调用和句柄删除调用,在下一次抓取快照时(-snapshot),!htrace将向操作系统查询所有句柄
创建调用和句柄删除调用的栈回溯,并且把它们显示出来,
这时直接用!htrace会输出以下内容:
0:001> !htrace -------------------------------------- Handle = 0x000007bc - CLOSE Thread ID = 0x000014fc, Process ID = 0x000013f0 0x7c8135dd: kernel32!GetLongPathNameW+0x00000249 0x7854287c: MSVCR90!_check_manifest+0x0000009c 0x78542c22: MSVCR90!__CRTDLL_INIT+0x0000008e 0x78542d5e: MSVCR90!_CRTDLL_INIT+0x0000001e 0x7c92118a: ntdll!LdrpCallInitRoutine+0x00000014 0x7c93b5d2: ntdll!LdrpRunInitializeRoutines+0x00000344 0x7c93fbdc: ntdll!LdrpInitializeProcess+0x0000114b 0x7c93fad7: ntdll!_LdrpInitialize+0x00000183 0x7c92e457: ntdll!KiUserApcDispatcher+0x00000007 -------------------------------------- Handle = 0x000007bc - OPEN Thread ID = 0x000014fc, Process ID = 0x000013f0 0x7c80ef97: kernel32!FindFirstFileW+0x00000016 0x7c8135c5: kernel32!GetLongPathNameW+0x00000231 0x7854287c: MSVCR90!_check_manifest+0x0000009c 0x78542c22: MSVCR90!__CRTDLL_INIT+0x0000008e 0x78542d5e: MSVCR90!_CRTDLL_INIT+0x0000001e 0x7c92118a: ntdll!LdrpCallInitRoutine+0x00000014 0x7c93b5d2: ntdll!LdrpRunInitializeRoutines+0x00000344 0x7c93fbdc: ntdll!LdrpInitializeProcess+0x0000114b 0x7c93fad7: ntdll!_LdrpInitialize+0x00000183 -------------------------------------- Handle = 0x000007c0 - CLOSE Thread ID = 0x000014fc, Process ID = 0x000013f0 0x7c8135dd: kernel32!GetLongPathNameW+0x00000249 0x7854287c: MSVCR90!_check_manifest+0x0000009c 0x78542c22: MSVCR90!__CRTDLL_INIT+0x0000008e 0x78542d5e: MSVCR90!_CRTDLL_INIT+0x0000001e 0x7c92118a: ntdll!LdrpCallInitRoutine+0x00000014 0x7c93b5d2: ntdll!LdrpRunInitializeRoutines+0x000003 .........................
格式一般是句柄值,进程线程, OPEN表示打开句柄的栈回溯,CLOSE表示关闭句柄的栈回溯,那么关键是要找到那些栈回溯打开了句柄,却没有相应的栈回溯来关闭句柄,这可以通过!htrace -diff来实现:
0:000> !htrace -diff Handle tracing information snapshot successfully taken. 0xfa new stack traces since the previous snapshot. Ignoring handles that were already closed... Outstanding handles opened since the previous snapshot: -------------------------------------- Handle = 0x000005b0 - OPEN Thread ID = 0x000007f4, Process ID = 0x000013f0 0x00401657: test1!CServer::GetToken+0x00000047 0x0040136f: test1!CServer::GetSID+0x0000001f 0x004010de: test1!ThreadWorker+0x0000007e 0x7c80b729: kernel32!BaseThreadStart+0x00000037 -------------------------------------- Handle = 0x000005b4 - OPEN Thread ID = 0x00000c34, Process ID = 0x000013f0 0x00401657: test1!CServer::GetToken+0x00000047 0x0040136f: test1!CServer::GetSID+0x0000001f 0x004010de: test1!ThreadWorker+0x0000007e 0x7c80b729: kernel32!BaseThreadStart+0x00000037 -------------------------------------- Handle = 0x000005b8 - OPEN Thread ID = 0x00001650, Process ID = 0x000013f0 0x00401657: test1!CServer::GetToken+0x00000047
很明显了,我们看到在GetToken中有句柄未关闭,所以在使用!htrace时采用的步骤一般是:
1. 在重现泄漏问题之前,启用句柄跟踪(!htrace -enable)
2.执行重现过程,并且让进程句柄泄漏
3.通过!htrace -diff来找出有问题的栈