我正在分析多线程C ++应用程序的内存和崩溃转储。
如this VisualCommunity question中所述,我对所有不等待也不睡觉的线程感兴趣。
目前,我是通过Visual Studio(Threads
窗口)通过以下方式获得答案的:
1.将所有线程复制到Excel工作表(column1),
2.将“ WaitFor”过滤的线程复制到Excel工作表(column2),
3.将“睡眠”过滤的线程也复制到Excel工作表(在第2列的底部),然后
4.使用±{MATCH(Column1_1;Column2_$1:Column2_$143;0)
Excel工作表功能以获取我的结果(在#N/A
上过滤这些结果)。
我想知道我是否可以在Windbg中做类似(但更容易)的事情。
目前,我可以要求完整的调用堆栈列表(使用Windbg命令~* kb
)。
我可以在Windbg中做一个Search call stack
吗(很可能是在~* kb
命令中添加一些内容)?有扩展的可能性(如正则表达式)吗?
答案 0 :(得分:4)
如果复制粘贴,命令必须在单行中删除where()处的换行符
0:057> dx -r1 @$curprocess.Threads.Select(p=>p.Stack).Select(p=>p.Frames).Select(t=>t[1]).Where
( ( p=>p.ToDisplayString().Contains("Wait") == true ))
命令结果
@$curprocess.Threads.Select(p=>p.Stack).Select(p=>p.Frames).Select(t=>t[1]).
Where( ( p=>p.ToDisplayString().Contains("Wait") == true ))
[0x9dc] : ntdll!NtWaitForMultipleObjects + 0xc [Switch To]
[0x480] : ntdll!NtWaitForMultipleObjects + 0xc [Switch To]
[0xc4] : ntdll!NtWaitForMultipleObjects + 0xc [Switch To]
[0xae8] : ntdll!NtWaitForSingleObject + 0xc [Switch To]
[0xeac] : ntdll!NtWaitForKeyedEvent + 0xc [Switch To]
[0xf08] : ntdll!NtWaitForMultipleObjects + 0xc [Switch To]
[0xdd4] : ntdll!NtWaitForSingleObject + 0xc [Switch To]
[0xc64] : ntdll!NtWaitForSingleObject + 0xc [Switch To]
[0x89c] : ntdll!NtWaitForKeyedEvent + 0xc [Switch To]
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[0x162c] : ntdll!NtWaitForKeyedEvent + 0xc [Switch To]
错误条件的命令必须再次为单行
0:057> dx -r1 @$curprocess.Threads.Select(p=>p.Stack).Select(p=>p.Frames).Select(t=>t[1]).Where
( ( p=>p.ToDisplayString().Contains("Wait") == false ))
结果
@$curprocess.Threads.Select(p=>p.Stack).Select(p=>p.Frames).Select(t=>t[1]).
Where( ( p=>p.ToDisplayString().Contains("Wait") == false ))
[0x208] : ntdll!NtRemoveIoCompletion + 0xc [Switch To]
[0x3ec] : ntdll!NtRemoveIoCompletion + 0xc [Switch To]
[0xadc] : user32!NtUserGetMessage + 0xc [Switch To]
[0x1794] : ntdll!NtDelayExecution + 0xc [Switch To]
[0xe78] : ntdll!NtRemoveIoCompletion + 0xc [Switch To]
[0x1164] : ntdll!DbgUiRemoteBreakin + 0x3c [Switch To]
Lieven所建议的pde!busy与内置命令之间的输出比较:稍作修改以排除“ RemoveIo”和“ Wait”堆栈
0:037> dx @$curprocess.Threads.Select(p=>p.Stack).Select(p=>p.Frames).Select(t=>t[1]).Where(
(p=>p.ToDisplayString().Contains("Wait") != true)).Where(p=>p.ToDisplayString().
Contains("Remove") != true)
结果
@$curprocess.Threads.Select(p=>p.Stack).Select(p=>p.Frames).Select(t=>t[1]).
Where( (p=>p.ToDisplayString().Contains("Wait") !=
true)).Where(p=>p.ToDisplayString().Contains("Remove") != true)
[0xd78] : user32!NtUserGetMessage + 0xc [Switch To]
[0xe44] : user32!NtUserGetMessage + 0xc [Switch To]
[0x514] : ntdll!DbgUiRemoteBreakin + 0x3c [Switch To]
0:037> !busy
# 37 TID:0d78 kb kbn kbnL kn knL kpn kPn
# ChildEBP RetAddr
00 1737fdd8 770ccde0 ntdll!KiFastSystemCallRet
01 1737fddc 770cce13 user32!NtUserGetMessage+0xc
xxxx
0b 1737ff24 00000000 ntdll!_RtlUserThreadStart+0x1b
50 TID:0e44 kb kbn kbnL kn knL kpn kPn
# ChildEBP RetAddr
00 1fb8fa18 770ccde0 ntdll!KiFastSystemCallRet
01 1fb8fa1c 770c18d9 user32!NtUserGetMessage+0xc
xxxxxx
07 1fb8fb20 00000000 ntdll!_RtlUserThreadStart+0x1b
53 TID:0514 kb kbn kbnL kn knL kpn kPn
# ChildEBP RetAddr
00 144cf778 7780f20f ntdll!DbgBreakPoint
01 144cf7a8 7748ed6c ntdll!DbgUiRemoteBreakin+0x3c
xxxxxxx
05 144cf848 00000000 ntdll!_RtlUserThreadStart+0x1b
Threads: 3 of 54
Frames : 1
Command: knL
Mode : Basic
答案 1 :(得分:1)
安德鲁·理查兹(Andrew Richards)的PDE扩展名添加了一个!busy
命令
!busy - Equivalent of ~*knL but only displays stacks that are at least
'depth' frames deep (default depth is 1) and are not waiting for:-
~ ntdll!NtWaitFor*
~ ntdll!ZwWaitFor*
~ ntdll!NtRemoveIoCompletion
~ ntdll!ZwRemoveIoCompletion
~ ntdll!NtReplyWaitReceivePort
~ ntdll!ZwReplyWaitReceivePortEx
无法找到所需的下载文件,但您可以通过Channel 9链接ping Andrew。他通常反应很快。
答案 2 :(得分:0)
还有!findstack
命令。不幸的是,它需要一个符号作为参数,因此通配符或部分名称将不起作用。
示例:
0:001> !findstack wow64cpu!WaitForMultipleObjects32
Thread 001, 1 frame(s) match
* 01 0000000006c0eb10 0000000073e0d286 wow64cpu!WaitForMultipleObjects32+0x3b
Thread 003, 1 frame(s) match
* 01 000000000bb3ebf0 0000000073e0d286 wow64cpu!WaitForMultipleObjects32+0x3b