5
AOûT

ALT.NET #16 : WindDBG, compte rendu par Romain Verdier

Posté par romain dans Comptes Rendus Paris | 8 responses so far

La dernière rencontre ALT.NET avait lieu chez Winwise. Yann Schwartz nous présentait une session (pleine de joie, rappelons-le) au sujet d’un outil méconnu et surpuissant : Windbg. En fait, il s’agissait surtout de voir comment tirer partie de Windbg pour débugger des applications managées ; après tout, c’est ALT.NET. Il y avait une bonne dizaine de personnes (ndYann : c’est faux, on était au moins une bonne douzaine) — les meilleurs d’entre tous –, et ce fut diablement intéressant : instructif, utile, pointu et digeste.

Par contre, Yann ne sait pas coder :

for(int i=0; i< 100000000; i++)
{
   if(!list.Contains(Guid.NewGuid().ToString()))
      list.Add(Guid.NewGuid().ToString());
}

Il faut probablement avoir une maladie mentale pour écrire ça ! C’est en tout cas ce que j’ai pensé sur le coup, en pouffant sur ma chaise (j’étais au fond de la salle). Ensuite, je ne sais plus si je l’ai compris de moi même ou si Yann a dû le préciser d’un air atterré, mais il avait fait exprès d’écrire ça. Parce que d’autres ne font pas exprès, et que ça pose des problèmes.

Windbg est un outil permettant de débugger des applications Windows, ou carrément Windows. Et ouais ! On l’utilise généralement en s’attachant à un processus, ou en analysant un dump existant. Il devient alors possible d’obtenir tout un tas d’informations utiles (sans jeu de mot) : on peut se balader dans la pile d’exécution, inspecter les threads, la mémoire, etc. tout en restant très peu intrusif ; windbg est en effet un outil léger de très bas niveau. C’est particulièrement utile lorsqu’on cherche à savoir d’où provient un problème sur une application qui tourne dans un environnement où il est impossible d’utiliser de profilers, d’outils de développement, et autres moyens de petits joueurs. Si vous voulez débugger une application ASP.NET déployée sur IIS en production, par exemple, quelques droits, une clé usb et windbg suffisent. Amenez quand même votre cerveau, on ne sait jamais.

On peut donc voir ce qui se passe au coeur d’une application native, mais il existe une extension à Windbg, sos, qui offre nombre de fonctionnalités propres à l’inspection et au debug des programmes .NET. Cette extension est elle-même étendue par un autre outil non-officiel, sosex, toujours spécifique à .NET, qui fait gagner +2 en force, +3 en magie et rend accessibles de nouvelles commandes intéressantes.

On a bien senti que Yann voulait rester pratique pour cette présentation, et on l’en remercie. Il s’agissait d’une démo continue et argumentée, en quelque sorte, qui avait pour but de montrer comment trouver et résoudre certains types de bugs à l’aide des outils appropriés. Il ne s’agissait pas d’une présentation qui avait pour but de montrer comment utiliser certains outils à l’aide de bugs appropriés. En fait, il est apparu assez clairement que dans 90% des cas, quelques commandes de sos et/ou de sosex pouvaient suffire à sécher les larmes des sales programmeurs que nous sommes.

Exemples :

  • !DumpHeap -stat : Liste toutes les instances du tas, regroupées par type et triées par taille totale.
  • !Threads : Liste les threads de l’application.
  • !SyncBlk : Liste les blocs de synchronisation, pris ou attendus par les threads de l’application.
  • !GCRoot addr : Affiche qui référence l’instance spécifiée et empêche donc sa collecte par le GC.
  • !dlk : (commande Sosex) : Trouve automatiquement les deadlocks.
  • !refs addr : (commande Sosex) : Affiche le graphe des références d’une instance, i.e. qui la référence, et qui elle référence.
  • Etc.

Pour peu que l’on ait une petite idée de ce qu’on recherche, il devient généralement possible de remonter jusqu’à la source des problèmes en enchainant ces commandes. Les problèmes les plus classiques ainsi que les traitements préconisés ont été classés dans 12 catégories par le Dr Schwartz.

Le docteur Schwartz attend que son assistant l'aide à enfiler ses gants.
Le docteur Schwartz attend que son assistant l’aide à enfiler ses gants.

Les fuites mémoires

  • Symptôme : Votre application se comporte correctement, mais consomme (sans raison valable) de plus en plus de mémoire, sans faire mine de vouloir en rendre, ne serait-ce qu’un peu de temps en temps.
  • Cause courante du mal : Ressources non-managées que l’on oublie de disposer, références oubliées qui empêchent la collecte de certaines instances, etc.
  • Localiser la tumeur : (pseudo-méthode) On lance la commande !DumpHeap -stat pour trouver (en regardant la taille totale occupée par les instances d’un type) quels sont les celles qui sont susceptibles de consommer abusivement la mémoire : il s’agit souvent de tableaux de bytes (buffers, images) ou de strings. On exécute ensuite la commande !DumpHeap avec le paramètre -mt pour afficher la liste détaillée des adresses d’instances d’un type donné. A partir de là, il est souvent possible de retrouver quel(s) objet(s) les maintiennent en vie et qui est responsable des instanciations à l’aide de la commande !GCRoot [adresse].

Les deadlocks

  • Symptômes : L’application se bloque, ne répond plus, mais ne consomme pas de CPU.
  • Cause courante du mal : Plusieurs threads s’interbloquent, en s’attendant mutuellement. C’est pas bien. Il parait que ça s’appelle aussi une étreinte fatale. (?)
  • Localiser la tumeur : On utilise la commande !dlk de sosex ! Il est également possible de s’en sortir en utilisant !SyncBlk, !DumpObj [adresse] et !DumpStackObjects.

Les freezes gourmands

  • Symptômes : Là encore, il se peut que l’application continue à fonctionner, mais en se bloquant anormalement longtemps à certains moments, monopolisant complètement les ressources CPU à la disposition du processus.
  • Cause courante du mal : Boucles infinies, ou presque, recherches linéaires dans des boucles, sérialisation stakhanoviste, etc.
  • Localiser la tumeur : !runaway pour trouver le thread le plus gourmand, ~[nb]s pour passer au thread impétrant numéro [nb], puis !ClrStack pour avoir la pile d’appels pour ce thread.

Ah oui, au fait, il y avait un plan, dans cette présentation. Je viens de parler de la première partie, mais il en avait une seconde.

Avec Windbg & Co. On se rend bien compte qu’il faut souvent commencer comme si on voulait pécher la baleine, pour reserrer petit à petit les mailles du filet et trouver finalement la source du/des problème(s). Cette analyse suit certains patterns assez simples à identifier ; on aimerait donc pouvoir automatiser un peu cette inspection, notamment lorsqu’on travaille sur des dumps énormes ou que l’on cherche à identifier de façon systématique les risques potentiels d’un système, par exemple.

C’est donc sur cette problématique que s’est penché Yann pour la seconde partie de la présentation. La transition n’a pas été oubliée et nous avons eu droit en guise d’interlude à un petit worst-of des langages de programmation qui font saigner les yeux : APL, J, Brainfuck, et, évidemment, le langage de script de windbg. Car s’il existe effectivement quelques moyens d’utiliser windbg programmatiquement, c’est la misère. La première solution consiste à utiliser le langage de script de windbg (ORLY?). La seconde, à passer par Powerdbg, une extension de PowerShell qui communique avec Windbg via TCP (ce dernier peut en effet passer en mode « server »). C’est mieux, mais toujours pas très sexy. Et on aime ce qui est sexy, nous, pas vrai ?

Justement ! Le dernière solution, celle de Yann, est sexy. Ca s’appelle Linqdbg, et c’est comme son nom l’indique du Linq-to-Windbg. Utilisé dans une REPL — Yann utilisait LinqPad pour sa démo — ça permet enfin de chasser le deadlock sans se tordre de douleur. C’est un projet sympa, qui pourrait rapidement séduire ceux qui n’ont pas le courage de windébéger classiquement, ou qui veulent scripter leurs analyses sans apprendre la syntaxe du 3ème langage le plus compliqué du monde (le ROI n’est pas forcément évident). Au niveau technique, Yann vous en parlera probablement mieux que moi sur son blog, mais en deux mots, il s’agit d’un provider Linq qui interagit avec Windbg via TCP, à l’instar de Powerdbg, et qui encapsule les commandes les plus courantes.

Exemple de requêtes :


var instances = from i in Linqdbg.HeapStats()
                where i.Type.IsAssignableFrom(typeof(Toto))
                orderby i.TotalSize desc
                select i;


var leaked = from i in instances
             select i.GCRoot();

C’est malin, et c’est open source : bravo Yann. Si vous parlez C#, c’est un moyen élégant d’analyser finement un programme : on bénéficie de la puissance divine du framework .NET.

En conclusion, la session était vraiment plus intéressante que ce compte-rendu. Je dirais même plus : les pauvres blagues de ce compte rendu sont là pour vous faire oublier qu’il ne sert à rien. Je vous invite donc à jeter un coup d’oeil aux slides de la présentation et à cliquer sur ces quelques liens si vous avez envie d’en apprendre plus au sujet de ce sombre outil :

Merci à Yann pour sa relecture attentive, et son remplissage de trous.

Reader's Comments

  1. Je ne suis pas Joel Spolsky « Codingly |

    [...] ne suis pas Joel Spolsky car je n’ai pas tenu 10 ans avant de sauter le requin. Extrait de mon dernier compte-rendu sur altnetfr.org : Par contre, Yann ne sait pas coder [...]

  2. Jérôme Moly |

    « qui fait gagner +2 en force, +3 en magie »
    –> et c’est là que je me dis « tiens c’est romain qui a du écrire l’article » :D

  3. Philippe Vialatte |

    > Il parait que ça s’appelle aussi une étreinte fatale. (?)

    Au Canada, peut-être ?

    Tres interessant, comme sujet, surtout Linqdbg (m’aurait économisé deux trois poignées de cheveux, ce bidule ;) )

    Rhaaa, a quand les sessions filmées ?

  4. Evilznet.com » Blog Archive » ALT.NET #16 : WindDBG, compte rendu par Romain Verdier |

    [...] Je ne peux pas vous en dire plus car je n’ai pas pu être présent. Mais tout est là. [...]

  5. Sylvain |

    Très bon CR :)

  6. Simon Mourier |

    Windbg est particulièrement utile pour déterminer la cause d’un StackOverflowException quand on n’a pas Visual Studio sous la main. En effet, les StackOverflowException sont pénibles sans debugger, car on n’a pas la StackTrace… sauf avec Windbg :)

  7. Fabrice |

    A noter que j’ai publié récemment un article sur le sujet :
    Détecter et éviter les fuites de mémoire et de ressources dans les applications .NET
    http://weblogs.asp.net/fmarguerie/archive/2009/11/03/article-detect-avoid-memory-leaks.aspx

    Fabrice

  8. ALT.NET #16 : WindDBG, compte rendu par Romain Verdier | Evilznet.com |

    [...] Je ne peux pas vous en dire plus car je n’ai pas pu être présent. Mais tout est là. [...]

Laisser un commentaire

Entrepreneur Press Wordpress Theme