5
votes

Rechercher dans la pile d'appels

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?


1 commentaires

Vous pouvez utiliser Javascript pour écrire vos propres scripts dans WinDbg, voir l'exemple suivant github.com/Microsoft/WinDbg- Échantillons


3 Réponses :


1
votes

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


0 commentaires

4
votes

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 ))


1 commentaires

Merci beaucoup, c'est exactement ce que je recherchais: cela rend Windbg encore plus puissant que Visual Studio :-)



0
votes

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


0 commentaires