Upload
emmanuelle-michon
View
108
Download
3
Embed Size (px)
Citation preview
jc/md/lp-01/06 Debug 1
Debugging
Élémentaire
jc/md/lp-01/06 Debug 2
Objectif du chapitre
• Premier contact avec les outils de mise au point• Génération en vue de debug• Usage des points d’arrêt, pas à pas• Visualisations diverses
– Code– Variables– Mémoire – Pile– …
jc/md/lp-01/06 Debug 3
Objectifs (1)
• La mise au point de programmes (debugging) nécessite l’emploi de techniques particulières
• Platform Builder offre– Un ensemble d’outils usuels
Exécution du programme en pas à pas Pose ou suppression de points d’arrêt Visualisation des variables, de la mémoire, des registres Suivi des enchaînements de fonctions, etc.
– Un outil « Kernel Tracker » pour visualiser la chronologie des exécutions
jc/md/lp-01/06 Debug 4
Objectifs (2)
• Pour utiliser les possibilités de mise au point, la cible doit être construite dans le mode particulier « Debug » par opposition au mode « Release » qui correspond à une version d’exploitation
• Étude du debugger en deux phases– Visualisations diverses, Breakpoint, etc.– Kernel Tracker ultérieurement
jc/md/lp-01/06 Debug 5
Point de départ
• Générer une plate-forme en mode Debug• Créer et générer une application avec un main
et des fonctions très simples • Exploration (partielle) de l’outil de debug
– Messages– Visualisation du code source– Breakpoint – Visualisation des variables, de la mémoire– Visualisation du code assembleur– Visualisation de la pile
jc/md/lp-01/06 Debug 6
Génération de la plate-forme « Debug »
• Utiliser l’assistant, comme précédemment, avec éventuellement un nouveau nom
• Au pas 6 de l’assistant, modifier les options• Cocher dans les options de la liste « Debug » :
« Enable Image Larger than 32 MB » • Sortir de l’assistant par « Finish »• Sélectionner la configuration active « Debug »• Générer la plate-forme (Build Platform)
jc/md/lp-01/06 Debug 7
Modification des options
jc/md/lp-01/06 Debug 8
Sélection de la taille des images
jc/md/lp-01/06 Debug 9
Sélection configuration : Debug
jc/md/lp-01/06 Debug 10
Génération de la plate-forme
jc/md/lp-01/06 Debug 11
Génération de l’image
jc/md/lp-01/06 Debug 12
Exécution d’une application
• Sans inclusion dans l’imageCréation du .exe
Téléchargement du noyau
Éxécution par la commande « Run Program »
• Avec inclusion dans l’imageCréation du .exe
Refaire une image avec choix de l’option d’insertion
Téléchargement du noyau avec l’application
Exécution à partir de la cible par la méthode Windows
jc/md/lp-01/06 Debug 13
Options de génération
• Pour voir les options de génération avec ou sans inclusion, nous prenons une application de type WCE Application
• Noms de nos applications écrits en majuscules pour les distinguer facilement des applications proposées par Windows CE
• Nom de l’application : BRKP• Nous ajouterons le code par la suite
jc/md/lp-01/06 Debug 14
Choix de l’option pour le projet
jc/md/lp-01/06 Debug 15
Inclusion application dans l’image
jc/md/lp-01/06 Debug 16
Exclusion application de l’image
jc/md/lp-01/06 Debug 17
Application BRKP
• Faire la somme et le produit de deux nombres entiers positifs avec
– Une fonction somme– Une fonction produit– Des variables statiques– Des variables dynamiques– Des passages d’arguments
• Introduire des messages de contrôle
jc/md/lp-01/06 Debug 18
Messages d’aide à la mise au point
• Édition habituelle de messages de contrôle dans l’application par des printf ou équivalents
• En plus, édition de messages par des macros dans la fenêtre de sortie de l’émulateur, et non dans le contexte de la cible
– RETAILMSG en version Retail– RETAILMSG et DEBUGMSG en version Debug
jc/md/lp-01/06 Debug 19
Macro RETAILMSG
• RETAILMSG(cond, printf_exp) • Impression si la condition est vraie de ce qu’on
mettrait dans un printf• Impression faite par une fonction équivalente à
printf mais qui écrit dans la fenêtre de sortie de l’émulateur et non dans la cible émulée
Exemple :RETAILMSG(1,(TEXT("Main: adresse de i= %x\n"),&i));
Équivalent dans la fenêtre de sortie à :printf("Main: adresse de i= %x\n",&i);
jc/md/lp-01/06 Debug 20
Application BRKP (1)
#include "stdafx.h"
//prototypes des fonctionsDWORD dwSomme(DWORD dwA,DWORD dwB);DWORD dwProduit(DWORD dwA,DWORD dwB); DWORD dwValeur; //juste pour avoir une variable statique
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
jc/md/lp-01/06 Debug 21
Application BRKP (2)
{DWORD i,j;
//Visualisation des adresses dans la fenêtre de sortieRETAILMSG(1,(TEXT("Main: adresse de i= %x\n"),&i));RETAILMSG(1,(TEXT("Main: adresse de j= %x\n"),&j));RETAILMSG(1,(TEXT("Main: adresse de valeur=
%x\n"),&dwValeur));//Calcul de somme et produit des entiers positifs 5 et 3
i=5;j=3;
jc/md/lp-01/06 Debug 22
Application BRKP (3)
RETAILMSG(1,(TEXT("Main: i=%u j=%u\n"),i,j));
dwValeur=dwSomme(i,j);
RETAILMSG(1,(TEXT("Main: i+j=%u\n"),dwValeur));
printf(("Main: i=%u j=%u dwValeur =%u \n"),i,j,dwValeur);
dwValeur=dwProduit(i,j);
RETAILMSG(1,(TEXT("Main: i*j=%u\n"),dwValeur));
printf(("Main: i=%u j=%u dwValeur =%u \n"),i,j,dwValeur);
getchar();
return 0;
}
jc/md/lp-01/06 Debug 23
Application BRKP (4)
DWORD dwSomme(DWORD dwA,DWORD dwB)
{
//Addition de A et B par une méthode archaïque
DWORD dwC=0;
while(dwA--)
dwC++;
while(dwB--)
dwC++;
return dwC;
}
jc/md/lp-01/06 Debug 24
Application BRKP (5)
DWORD dwProduit(DWORD dwA,DWORD dwB){
// Multiplication de A et B par une méthode simpliste DWORD dwC;
for(dwC=0;dwB;dwB--)dwC=dwSomme(dwA,dwC);
return dwC;}
jc/md/lp-01/06 Debug 25
Option de génération en mode debug
jc/md/lp-01/06 Debug 26
Configure Remote Connection
jc/md/lp-01/06 Debug 27
Configure Emulator Download Service
jc/md/lp-01/06 Debug 28
Insertion et suppression de breakpoints
• Les breakpoints peuvent être placés ou enlevés avant ou après le lancement de l’application
• Avant lancement du noyau– Positionner le curseur souris sur une ligne du
programme– Faire un click droit pour ouvrir le menu– Faire Insert/Remove Breakpoint
• Après lancement du noyau, il faut que le debugger soit arrêté
jc/md/lp-01/06 Debug 29
Fenêtres en debug
• Dans la fenêtre principale de Platform Builder la fenêtre Workspace est différente et donne accès à des commandes après chargement de la cible
• D’autres fenêtres sont spéciales pour le debug et accessibles par le menu View, sous-menu Debug Windows, ou par une barre de contrôle
• Fenêtres libres ou ancrées en fenêtre principale• Mémorisation des caractéristiques des fenêtres• Fermeture par l’icône Windows
jc/md/lp-01/06 Debug 30
Exemple : fenêtre des variables
jc/md/lp-01/06 Debug 31
Écran avec la fenêtre des variables
Fenêtre nouvelle disponible pour des commandes lignes (shell)
Variables
Fenêtre principale
jc/md/lp-01/06 Debug 32
Groupe de fenêtres flottantes
jc/md/lp-01/06 Debug 33
Exemple de fenêtres ancrées
Registres du CPU
Fenêtre principale
ContexteWatch
Fenêtre nouvelle disponible pour des commandes lignes (shell)
Fenêtre de sortie
jc/md/lp-01/06 Debug 34
Barre de commande « Debug »
• Ouverte comme toutes les barres de commandes par un click droit dans une barre existante et coche de la case
• Une série d’icônes correspond à des commutateurs pour l’ouverture ou la fermeture des fenêtres de debug
• Une autre série correspond à l’exécution du code : Go simple (jusqu’à un point d’arrêt), pas à pas, avec saut d’une fonction, etc.
• Les bulles d’aide sont explicites
jc/md/lp-01/06 Debug 35
Essai de BRKP
• Génération de la plate-forme• Génération de l’application• Génération de l’image• Téléchargement du noyau avec ou sans
l’application suivant les choix• Exécution du programme• Fermeture de la cible• Déconnexion
jc/md/lp-01/06 Debug 36
Après téléchargement de la cible
jc/md/lp-01/06 Debug 37
Cible vierge
jc/md/lp-01/06 Debug 38
Exécution par la commande shell
Commande du shells BRKP
s pour start
jc/md/lp-01/06 Debug 39
Fenêtres du debugger après exécution
MessagesMessages
jc/md/lp-01/06 Debug 40
Cible après exécution
Attente du caractère Entrée
Taper Entrée pour finir BRKP
jc/md/lp-01/06 Debug 41
Pose d’un breakpoint
• Pose avant ou pendant la session de debug• Placer le curseur sur une ligne de code• Ouvrir le menu contextuel par un click droit• Insérer un point d’arrêt, marqué par un rond
rouge en marge (en fait c’est un commutateur qui insère ou supprime un point d’arrêt)
• Relancer le programme s’il ne l’est pas• Au début, on doit observer une flèche jaune
superposée au premier point d’arrêt
jc/md/lp-01/06 Debug 42
Arrêt du debugger
Icône d’arrêt
jc/md/lp-01/06 Debug 43
Après pose des points d’arrêt
jc/md/lp-01/06 Debug 44
Arrêt sur point d’arrêt
jc/md/lp-01/06 Debug 45
Exécution du programme en debug
• Chaque commande Go (menu ou icône) provoque l’exécution du programme jusqu’à :
– Rencontre d’un point d’arrêt– Rencontre d’une erreur d’exécution– Fin normale du programme
• La commande « Run Program » charge le programme dont on donne le nom puis déclenche une commande Go
• Exécution contrôlée en pas à pas par diverses commandes d’avance
jc/md/lp-01/06 Debug 46
Avance d’un pas
• Avance par– Le menu « Debug »– Les touches de fonction du clavier– Les icônes (dessins et bulles explicites)
• Plusieurs types d’avance– Un pas dans la fonction (Step Into)– Un pas en sautant la fonction (Step Over)– Un pas en ressortant de la fonction (Step Out)– Jusqu’au curseur (Run to Cursor)
jc/md/lp-01/06 Debug 47
Avance d’un pas simple
Avance un pas
jc/md/lp-01/06 Debug 48
Après avance d’un pas simple
Fenêtre des variables
i à jour, j ?Messages
jc/md/lp-01/06 Debug 49
Avance d’un pas avec saut
Avance avec saut de la fonction pour
ne pas exécuter toute la fonction en
pas à pas
Avance avec saut
j à jour
jc/md/lp-01/06 Debug 50
Avance avec sortie de la fonction
• Ce type de pas (Step Out) permet de cesser l’examen d’une fonction en pas à pas en retournant directement chez l’appelant
• Utile quand on est entré par inadvertance dans une fonction déjà au point qu’on ne désire pas dérouler en pas à pas
• Utile en particulier quand on est entré dans une fonction fournie par Platform Builder pour laquelle on ne dispose pas du code source
jc/md/lp-01/06 Debug 51
Avance avec sortie
Le pas simple va nous faire entrer dans la fonction printf pour laquelle nous n’avons
pas le code source
Un pas simple
jc/md/lp-01/06 Debug 52
Recherche du code source
Puisque le code source n’est pas sur la machine…
jc/md/lp-01/06 Debug 53
Fenêtre en mode désassemblage
Le pas à pas va nous conduire dans une nouvelle fonction
après une demande de localisation du
code source puisque ici la fonction est aussi inconnue.
jc/md/lp-01/06 Debug 54
Entrée dans la fonction imbriquée
On va sortir de cette fonction et retrouver la
demande de localisation pour le printf
jc/md/lp-01/06 Debug 55
Recherche du code source
Puisque le code source n’est toujours pas sur la machine…
jc/md/lp-01/06 Debug 56
Sortie de la fonction
Le contexte est redevenu printf
jc/md/lp-01/06 Debug 57
Suppression du désassemblage
jc/md/lp-01/06 Debug 58
Quelques pas jusqu’à la fonction
jc/md/lp-01/06 Debug 59
Entrée dans la fonction produit
Le contexte est notre fonction
dwProduit.
Pourquoi 5 ?On continue en
assembleur.
jc/md/lp-01/06 Debug 60
Code assembleur de dwProduit
Malgré la position de la flèche jaune sur le
code source, l’initialisation du for
n’est pas commencée.
jc/md/lp-01/06 Debug 61
Debug en assembleur
Après un pas, dwC est bien initialisée, on
repasse en mode normal
jc/md/lp-01/06 Debug 62
Après quelques pas, dans dwSomme
Le contexte est maintenant celui
de la fonction dwSomme. On
peut aussi voir les autres contextes.
jc/md/lp-01/06 Debug 63
Cible à ce stade
jc/md/lp-01/06 Debug 64
Visualisation des appels de fonctions
L’ouverture de la fenêtre « Call Stack » visualise la pile des appels de fonctions.
jc/md/lp-01/06 Debug 65
Fin de l’exécution
• Terminer le programme avec les commandes de déroulement « Go » ou d’avance par pas
• Quand on arrive sur le getchar() taper le caractère « Entrée » dans la cible.Mais à la suite de frappes au cours des manipulations, il se peut qu’un caractère soit déjà présent dans le tampon d’entrée et alimente le getchar() ; dans ce cas on ne verra pas l’attente du caractère ; il faut poursuivre les avances par pas.
jc/md/lp-01/06 Debug 66
Fin de l’exécution (2)
• Après exécution de la dernière instruction, le système doit encore exécuter des fonctions « épilogues » pour terminer complètement le programme. Il faut donc poursuivre l’avance par le debugger, normalement par des pas « Step Out » jusqu’à obtenir le déchargement de l’application.
• On pourra alors reprendre correctement une nouvelle session de debug pour examiner d’autres possibilités.
jc/md/lp-01/06 Debug 67
Cible à la fin de l’exécution
jc/md/lp-01/06 Debug 68
Fin complète de l’application
Messages indiquant le déchargement de l’application, du module console utilisé
indirectement par notre code et des symboles associés.
La fenêtre cible est revenue à son état initial.
Plus rien à exécuter
Commandes inactives
jc/md/lp-01/06 Debug 69
Nouvelle session
Nouvelle commande start
Commuter en debug source
jc/md/lp-01/06 Debug 70
Fenêtre « Variables »
• Barre « Toolbar » affichée avec le menu contextuel– Nom de la fonction– Arguments
• & symbolise une adresse, comme en C• Clicker un + présent devant un nom offre des
informations liées, adresse, valeur d’une variable, champs d’une structure, etc.
• Trois onglets– « Auto » pour les variables au fil de leur utilisation– « Locals » pour les variables locales– « This » qui correspond au pointeur « this »du C++
jc/md/lp-01/06 Debug 71
Fenêtre « Variables » (2)
• Affichage en hexadécimal ou en décimal• Modification des valeurs des variables en
sélectionnant la partie valeur à modifier et en saisissant la nouvelle valeur
• Modification visualisée par un affichage rouge répercutée dans les autres fenêtres
• Variables gérées automatiquement– Introduction de variable impossible– Suppression de variable impossible
jc/md/lp-01/06 Debug 72
Onglet « Auto » initial
lpCmdLine est un pointeur sur la ligne de commande ; sa
valeur est indiquée ainsi que la chaîne pointée, ici vide
Premier caractère de la chaîne UNICODE, donc ici fin de chaîne
jc/md/lp-01/06 Debug 73
Onglet « Auto » après avance
Variables gérées automatiquement
Modification possible après sélection de ce champ
jc/md/lp-01/06 Debug 74
Onglet « Locals »
Quand une variable est modifiée par une
instruction, elle apparaît en rouge
jc/md/lp-01/06 Debug 75
Onglet « Locals » (2)
Pas de confusion entre les
variables de même nom
Fenêtre du contexte de la fonction produit superposée par copier coller
Fenêtre du contexte de la fonction somme après de nombreux pas
jc/md/lp-01/06 Debug 76
Fenêtres « Watch »
• Fenêtres dans lesquelles on choisit les variables• Introduction de la variable par son nom• Suppression par sélection et « Delete »• Valeur modifiable et reportée dans les autres fenêtres• Modifications visualisées en rouge• Possibilité d’introduire une expression du style langage
C directement ou par le truchement d’une autre fenêtre : « QuickWatch »
• Gestion des variables suivant durée de vie et portée• Quatre onglets équivalents
jc/md/lp-01/06 Debug 77
Exemple « Watch1 » (1)
Un click droit ouvre un menu contextuel dont une entrée
indique le type de la variable.
jc/md/lp-01/06 Debug 78
Exemple « Watch1 » (2)
Capture juste après la
deuxième sortie de la fonction
dwSomme
Au pas suivant dwC prendra la valeur 10
jc/md/lp-01/06 Debug 79
Exemple « Watch1 » (3)
jc/md/lp-01/06 Debug 80
Exemple « QuickWatch »
jc/md/lp-01/06 Debug 81
Visualisation de la mémoire
• Deux fenêtres équivalentes « Memory 1 » et « Memory 2 »
• Affichage à partir de l’adresse fournie– numériquement en hexadécimal ou en décimal – par le nom d’une variable, d’une fonction
• Choix de l’affichage par le menu contextuel en octet, demi-mot, mot
• Modification directe de la mémoire, avec mise à jour dans les autres fenêtres et réciproquement
jc/md/lp-01/06 Debug 82
Exemple de visualisation mémoire
Adresse de i
Valeur de i
Adresse de dwSomme
Début du code de dwSomme
jc/md/lp-01/06 Debug 83
Représentation « Little Endian »
Adresse de i
Valeur de i en 32 bits
Modification arbitraire de i i : poids faibles
dans l’adresse la plus basse
i : poids forts dans l’adresse la
plus haute
jc/md/lp-01/06 Debug 84
Fenêtre « Registers »
• Visualisation des registres du processeur• Menu contextuel pour des options
– Registres flottants– Registres multimédia
• Modification possible en écrivant directement dans le registre
• Utilisables par leur nom symbolique pour fournir– Une adresse pour un pointeur– Une valeur pour un registre de données
jc/md/lp-01/06 Debug 85
Visualisation des registres
Nom symbolique
EAX Nom symbolique
EIP
jc/md/lp-01/06 Debug 86
« Debug » en mode assembleur
• Visualiser le code assembleur par le menu « View », l’icône, le menu contextuel ou encore la touche de fonction
• Toutes les commandes rencontrées dans la mise au point en langage source s’appliquent, en particulier les commandes d’avance par pas
• Les fenêtres de visualisation des registres et de la pile sont particulièrement utiles
jc/md/lp-01/06 Debug 87
Exemple : arrêt sur le breakpoint
Avancer par pas
À suivre
Activer le « Breakpoint »
jc/md/lp-01/06 Debug 88
Après de nombreux pas
Dans dwProduit avant le second appel de
dwSomme
jc/md/lp-01/06 Debug 89
Registres X86
• ESP:Stack Pointer Register– Pointeur de pile
• EBP:Stack-FrameBase Pointer– Pour accéder a des données passées par la pile
• EIP: Instruction Pointer
jc/md/lp-01/06 Debug 90
Exemple : dwValeur=dwSomme(i,j)
PILE
Nouveau ESP
Future valeur de retour
Nouveau EBP
Ancien EBP
Adresse retour
Paramètre 1
Paramètre 2
Ancien ESP
jc/md/lp-01/06 Debug 91
Visualisation de la pile (1)
Pile après appel de dwSomme
Pile avant appel de dwSomme
jc/md/lp-01/06 Debug 92
Visualisation de la pile (2)
Pile après sauvegarde de EBP puis
ECX
jc/md/lp-01/06 Debug 93
Visualisation de la pile (3)
• On peut assez facilement suivre l’évolution de la pile.
• Ici, à partir de l’adresse donnée par le pointeur de pile :
– ECX (A), EBP (1202FC00) sauvegardés par dwSomme
– La partie segment de l’adresse de retour placée par l’instruction call dans dwProduit : call dwSomme
– Les arguments dwA (5) et dwC (A) placés par dwProduit pour dwSomme
– La variable locale dwC de la fonction dwProduit– Puis, même chose pour l’appel de dwProduit par
main
jc/md/lp-01/06 Debug 94
Complément
• Ce ne sont que les principales fonctionnalités du debugger de base ; il reste beaucoup de possibilités à explorer.
• Nous explorerons ultérieurement toute une autre série de fonctionnalités dans le « Kernel Tracker »
• Un dernier groupe de commandes dont certaines sont très évoluées, est fourni par des commandes lignes à saisir dans la fenêtre « Shell » Windows CE accessible par l’icône CE
jc/md/lp-01/06 Debug 95
Conclusion
• Ce chapitre a permis de prendre en main les techniques les plus classiques de mise au point