IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Tests unitaires et backtrace sous Windows et Linux

Tests unitaires et backtrace sous Windows et Linux


précédentsommairesuivant

II. Afficher l'état de la pile

Les méthodes pour afficher l'état de la pile sont différentes selon les systèmes d'exploitation.

Pour simplifier la gestion multiplatforme, on décide d'avoir une interface très simple. Il s'agira donc simplement d'un appel à une fonction indiquant que la trace de l'erreur sera sauvegardée dans un flux que l'on donnera en paramètre.

Il existe en C++ une fonction permettant de récupérer d'une exception non gérée, set_exception_handler. Malheureusement, elle ne permet pas de gérer les aborts, les erreurs de segmentation dans un code non C++, ...

II-A. Backtrace sous Linux

Sous Linux, il existe un mécanisme de signaux qui permettent d'appeler une fonction dès qu'il y a eu un problème. C'est ce mécanisme qui est utilisé pour cette partie.

La récupération de l'état de la pile sous Linux est relativement aisée, mais très limitée. En effet, seules les fonctions backtrace et backtrace_symbol sont apparemment disponibles. Ces deux fonctions récupèrent des chaînes de caractères préformatées avec le nom de la fonction, l'adresse, ... En revanche, pas de moyen immédiat pour récupérer les modules chargés, ou pour afficher chaque paramètre de chaque fonction appelée. Par défaut, vous pourrez constater que vous n'obtenez pas le nom des fonctions. En effet, pour cela, vous devez compiler avec gcc et l'option -rdynamic, sachant qu'à la fin vous devez obtenir des fichiers objets ELF, le format habituel sous Linux, mais pas sous Windows. Donc cette technique peut ne pas donner le nom des fonctions sous Windows avec MinGW.

Les prochaines étapes consisteront à améliorer cette partie de la récupération de la trace afin qu'elle soit plus complète.

II-B. Backtrace sous Windows

Sous Windows, le problème est plus simple et plus compliqué à la fois. Plus simple car il existe une bibliothèque dédiée à la récupération des informations - pile, paramètres, modules chargés, ... -, s'appelant dbghelp.dll, et il existe en plus un filtre permettant de gérer les exceptions non récupérées. Ce filtre permet d'afficher la fameuse boîte de dialogue sous Windows XP qui demande l'envoi ou non d'un rapport d'erreur.

En revanche, le point plus compliqué, c'est qu'il existe plusieurs versions de la même bibliothèque et que la version la plus récente pour Windows n'est pas forcément celle qui a le numéro de version le plus élevé, car l'équipe de Windows XP utilise des dates différentes... Ce qui fait qu'il vaut mieux installer le logiciel WinDBG qui contient entre autres la bibliothèque dbghelp.dll et a redistribuer pour avoir accès à l'API la plus récente.

De même, la récupération des infos est plus souple et donc plus complexe à mettre en place. On commencera par sauvegarder le nom des modules chargés avec leur taille dans une liste grâce à une fonction callback. Puis, on gèrera le cas délicat du parcours de la pile. Ce parcours est effectué par une fonction, StackWalk64, qui prend en paramètre des structures initialisées grâce à des informations données par le filtre des exceptions non récupérées, entre autres l'adresse de la pile, du compteur programme, ... Grâce à ce parcours récursif, on obtient chaque état de la pile pour la fonction à partir de la levée de l'exception.

Ensuite, il faut vérifier la validité de l'adresse, récupérer le nom de la fonction associée ainsi que le déplacement dans la fonction, le nom du fichier et la ligne, si possible. On pourrait aussi retourner les valeurs des paramètres des fonctions.

Naturellement, ces informations ne sont pas stockées dans le fichier - par exemple, le nom de la fonction, du fichier, la ligne, ... -, tout cela se trouve dans les fichiers .pdb qui devront être fournis avec l'exécutable.

II-C. Exemple d'utilisation

L'exemple d'utilisation est on ne peut plus simple.

 
Sélectionnez
#include <stdexcept>
#include <fstream>
#include "backtrace.h"

int main(int argc, char **argv)
{
  setExceptionHandler("test.txt");

  throw std::runtime_error("Test");
}

Et automatiquement un fichier test.txt est généré lors de la levée de l'exception. Pour moduler selon le pid, le dossier d'exécution, ... c'est à vous de voir.


précédentsommairesuivant

Copyright © 2006 Matthieu Brucher. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.