J'analyse la mémoire et les vidages sur incident des applications C ++ multithreads.
Comme expliqué dans cette question VisualCommunity , je suis intéressé par tous les fils, qui n'attendent pas et ne dorment pas.
Actuellement, j'obtiens cette réponse à l'aide de Visual Studio (fenêtre Threads
) par:
1. copie de tous les fils dans une feuille Excel (colonne1),
2. copiez les fils filtrés "WaitFor" dans la feuille Excel (colonne2),
3. copiez également les threads filtrés "Sleep" dans la feuille Excel, (au bas de la colonne 2), et
4. utilisez la fonction de feuille de calcul Excel ± MATCH (Column1_1; Column2_ $ 1: Column2_ $ 143; 0)
pour obtenir mes résultats (filtrez ces résultats sur # N / A
) .
J'aimerais savoir si je pourrais faire quelque chose de similaire (mais plus simple) dans Windbg.
Actuellement, je peux demander une liste complète des piles d'appels (en utilisant la commande Windbg ~ * kb
).
Puis-je effectuer une Recherche dans la pile d'appels
dans Windbg (probablement en ajoutant quelque chose à la commande ~ * kb
)? Y a-t-il des possibilités étendues (comme les expressions régulières) possibles?
3 Réponses :
L'extension PDE d'Andrew Richards ajoute une commande ! 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
les commandes doivent être en une seule ligne supprimer le saut de ligne à Where () si vous copiez-collez
@$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
résultat de la commande
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)
la commande pour une condition fausse doit à nouveau être une seule ligne
@$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]
résultat
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 ))
une comparaison de la sortie entre! busy from pde as Suggéré par Lieven par rapport à la commande intégrée légèrement modifiée pour exclure les piles "RemoveIo" et "Wait"
@$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]
résultats
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 ))
Merci beaucoup, c'est exactement ce que je recherchais: cela rend Windbg encore plus puissant que Visual Studio :-)
Il y a aussi la commande ! findstack
. Malheureusement, il a besoin d'un symbole comme paramètre, donc les jokers ou parties de noms ne fonctionneront pas.
Exemple:
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
Vous pouvez utiliser Javascript pour écrire vos propres scripts dans WinDbg, voir l'exemple suivant github.com/Microsoft/WinDbg- Échantillons