Rim Chaabane. Analyse dynamique de ... - Université Paris 8
Rim Chaabane. Analyse dynamique de ... - Université Paris 8
Rim Chaabane. Analyse dynamique de ... - Université Paris 8
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
Rapport <strong>de</strong> stage <strong>de</strong> DEA Intelligence Artificielle<br />
et Optimisation Combinatoire<br />
Au Laboratoire d Intelligence Artificielle <strong>de</strong><br />
l Université <strong>de</strong> Vincennes <strong>Paris</strong> 8<br />
Réalisé par :<br />
Encadré par :<br />
Mlle CHAABANE <strong>Rim</strong><br />
Mme BALMAS Françoise<br />
Année universitaire<br />
2004-2005
Remerciements<br />
Je remercie en premier lieu ma mère, Dorra, Sami, Manu et Samia ainsi que ses filles,<br />
pour leur soutien, leurs encouragements constants tout au long <strong>de</strong> cette année <strong>de</strong> DEA. Je<br />
remercie énormément Madame Balmas qui m a soutenu et suivi avec gran<strong>de</strong> attention. Je la<br />
remercie également pour ses encouragements, sa confiance et sa précieuse ai<strong>de</strong> et j espère avoir<br />
été à la hauteur <strong>de</strong> ses attentes et <strong>de</strong> sa confiance.<br />
Je remercie mon amie Samia pour ses encouragements et pour son ai<strong>de</strong> dans la relecture du<br />
présent mémoire.<br />
Je salue mes camara<strong>de</strong>s <strong>de</strong> promotion avec qui j ai passé d agréables et mémorables moments. Je<br />
les remercie aussi pour leurs encouragements, leurs conseils et leur ai<strong>de</strong>.<br />
Je remercie finalement l ensemble <strong>de</strong>s professeurs <strong>de</strong>s universités <strong>Paris</strong> 8 et <strong>Paris</strong> 13 pour les<br />
enseignements qu ils nous ont transmis, ainsi que <strong>de</strong> leurs précieux conseils pour notre éventuelle<br />
future carrière dans le domaine <strong>de</strong> la recherche.
Résumé<br />
Ce sujet se place dans le cadre <strong>de</strong> l ai<strong>de</strong> aux développeurs dans leur travail <strong>de</strong> maintenance<br />
<strong>de</strong> programmes. En effet, il arrive souvent que <strong>de</strong>s développeurs aient à travailler sur <strong>de</strong> longs<br />
co<strong>de</strong>s sources qui ont été développés par d autres personnes. Il est donc peu aisé <strong>de</strong> suivre le<br />
fonctionnement <strong>de</strong>s appels <strong>de</strong> fonctions et <strong>de</strong>s variations <strong>de</strong>s variables pendant leur exécution.<br />
Le projet d A nalyse <strong>dynamique</strong> <strong>de</strong> programmes a pour objectif <strong>de</strong> permettre au développeur <strong>de</strong><br />
visualiser graphiquement les changements pendant l exécution du programme à maintenir et <strong>de</strong><br />
visualiser les appels <strong>de</strong> fonctions ainsi que d autres informations. Pour cela, les dépendances <strong>de</strong><br />
données <strong>dynamique</strong>s sont collectées pendant l exécution <strong>de</strong>s programmes, stockées dans une<br />
base <strong>de</strong> données, puis affichées sous forme <strong>de</strong> graphes.<br />
Le projet a déjà été réalisé pour analyser <strong>de</strong>s co<strong>de</strong>s sources en Lisp [BAL 05], le travail effectué<br />
dans ce projet consiste à reproduire cette même analyse pour <strong>de</strong>s programmes sources C. Pour<br />
effectuer cela, nous avons dû modifier un interprète C pour l extraction <strong>dynamique</strong> <strong>de</strong>s données<br />
et traiter ces données pour pouvoir visualiser graphiquement leurs dépendances.
Sommaire<br />
CHAPITRE 1 - INTRODUCTION.................................................................................................................... 9<br />
1.1. QU EST-CE QUE L ANALYSE DE PROGRAMMES ?................................................................................ 9<br />
1.2. OBJECTIFS DU PROJET D ANALYSE DYNAMIQUE DE PROGRAMMES C............................................. 10<br />
1.2.1. Créer un outil d analyse <strong>de</strong> programmes C fiable et évolutif........................................................ 10<br />
1.2.2. Un affichage clair <strong>de</strong>s dépendances <strong>de</strong> données ........................................................................... 11<br />
1.3. PRESENTATION DE L OUTIL D ANALYSE DE PROGRAMMES C.......................................................... 11<br />
CHAPITRE 2 - APPROCHE DE LA PROBLEMATIQUE ET CHOIX DE LA SOLUTION................... 17<br />
2.1. COMMENT EXTRAIRE DYNAMIQUEMENT LES DONNEES D UN PROGRAMME SOURCE EN LANGAGE<br />
C .. 17<br />
2.1.1. Les étapes <strong>de</strong> la compilation <strong>de</strong> GCC............................................................................................ 17<br />
2.1.2. Le choix d une solution.................................................................................................................. 19<br />
2.2. QUELLES DONNEES EXTRAIRE ? ....................................................................................................... 19<br />
2.3. LA REPRESENTATION GRAPHIQUE .................................................................................................... 20<br />
CHAPITRE 3 - LES INTERPRETES C EXISTANTS................................................................................... 24<br />
3.1. UNDERC............................................................................................................................................. 25<br />
3.2. CINT ................................................................................................................................................... 26<br />
3.3. JFL C................................................................................................................................................. 28<br />
3.4. EIC..................................................................................................................................................... 29<br />
3.5. CH ...................................................................................................................................................... 31<br />
3.6. POURQUOI EIC ? ............................................................................................................................... 34<br />
CHAPITRE 4 - EXPLORATION DE L INTERPRETE EIC........................................................................ 34<br />
4.1. SPECIFICITES DE EIC ........................................................................................................................ 36<br />
4.1.1. Installation et compilation............................................................................................................. 36<br />
4.1.2. Les mo<strong>de</strong>s d exécution <strong>de</strong> l Interprète EiC.................................................................................... 36<br />
4.1.2.1. Le mo<strong>de</strong> interactif................................................................................................................................36<br />
4.1.2.2. Le mo<strong>de</strong> batch......................................................................................................................................37<br />
4.1.3. Les différences entre EiC et C ....................................................................................................... 39<br />
4.2. STRUCTURE DE FICHIERS .................................................................................................................. 41<br />
CHAPITRE 5 - DESCRIPTION TECHNIQUE DU TRAVAIL REALISE ................................................. 43<br />
5.1. EXTRACTION DYNAMIQUE DES DONNEES ......................................................................................... 43<br />
5.1.1. Description <strong>de</strong> la procédure d extraction...................................................................................... 45<br />
5.1.2. Modifications apportées à EiC ...................................................................................................... 45<br />
5.1.2.1. I<strong>de</strong>ntification <strong>de</strong>s variables dans EiC...................................................................................................49<br />
5.1.2.2. Enregistrement <strong>de</strong> la <strong>de</strong>rnière ligne utilisant une variable ...................................................................49<br />
5.1.3. Numérotation et compteur d appel <strong>de</strong>s instructions...................................................................... 50<br />
5.1.4. Extensions pour les boucles et l appel <strong>de</strong> fonctions ...................................................................... 54<br />
5.2. AFFICHAGE DU GRAPHIQUE DE DEPENDANCES ENTRE DONNEES..................................................... 55<br />
5.2.1. L outil dot ...................................................................................................................................... 55<br />
5.2.2. Formatage <strong>de</strong> la base <strong>de</strong> données au format dot........................................................................... 56<br />
CHAPITRE 6 - EXEMPLES DE RESULTATS.............................................................................................. 59<br />
6.1. OPERATIONS SUR DES VARIABLES ENTIERES.................................................................................... 59<br />
6.2. CONDITIONNELLES............................................................................................................................ 60
6.2.1. L instruction if............................................................................................................................... 60<br />
6.2.1.1. Cas simples ..........................................................................................................................................60<br />
6.2.1.2. If imbriqués..........................................................................................................................................61<br />
6.2.2. Boucle while .................................................................................................................................. 62<br />
6.2.3. Boucle do while ............................................................................................................................. 64<br />
6.2.4. Boucle for ...................................................................................................................................... 64<br />
6.2.5. Boucles imbriquées........................................................................................................................ 66<br />
6.3. APPELS DE FONCTIONS AVEC ET SANS ARGUMENTS......................................................................... 67<br />
6.3.1. Fonction sans arguments............................................................................................................. 676<br />
6.3.2. Fonction avec arguments............................................................................................................... 68<br />
CHAPITRE 7 - COMPARAISON AVEC L EXISTANT............................................................................... 69<br />
7.1. CALL GRAPH DRAWING INTERFACE ................................................................................................. 69<br />
7.2. ZEUGMA : REPRESENTATION METAPHORIQUE DE PROGRAMMES ................................................... 70<br />
7.3. CARE ................................................................................................................................................ 72<br />
CHAPITRE 8 - CONCLUSION ET PERSPECTIVES .................................................................................. 76<br />
8.1. LIMITES DE NOTRE OUTIL D ANALYSE DYNAMIQUE DE PROGRAMMES C ....................................... 77<br />
8.2. AMELIORATIONS POSSIBLES ............................................................................................................. 77<br />
8.2.1. Prise en charge <strong>de</strong>s spécificités du langage C............................................................................... 77<br />
8.2.2. La numérotation <strong>de</strong>s instructions et le format <strong>de</strong> la base <strong>de</strong> données ........................................... 78<br />
8.2.3. La représentation graphique ......................................................................................................... 79<br />
8.2.4. Vers un outil complet d analyse <strong>dynamique</strong> .................................................................................. 79<br />
ANNEXES............................................................................................................................................................ 85<br />
ANNEXE - I - PROGRAMMES DE TESTS DES INTERPRETES C ET TRACES DE TESTS ....................................... 88<br />
ANNEXE - II - COMMANDES INTERNES A EIC EN MODE INTERACTIF............................................................ 91<br />
ANNEXE - III - DIRECTIVES D APPEL A EIC EN MODE BATCH ....................................................................... 93<br />
ANNEXE - IV - SCRIPT SHELL "EIC_ADPC.SH ............................................................................................... 95<br />
ANNEXE - V - SCRIPTS AWK............................................................................................................................ 98<br />
ANNEXE - VI - EXTRAITS DU CODE SOURCE MODIFIE DE EIC ....................................................................... 99
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Chapitre 1 - Introduction<br />
Ce projet d analyse <strong>dynamique</strong> <strong>de</strong> programmes C, se place dans le cadre <strong>de</strong> travaux <strong>de</strong> recherches<br />
sur l analyse <strong>de</strong> programmes. Ces travaux ont pour but <strong>de</strong> faciliter la compréhension <strong>de</strong><br />
programmes, d ai<strong>de</strong>r les développeurs tenus <strong>de</strong> maintenir <strong>de</strong>s programmes à cerner plus<br />
facilement les actions effectuées par ces <strong>de</strong>rniers et <strong>de</strong> leur éviter la lecture exhaustive <strong>de</strong>s très<br />
nombreuses lignes <strong>de</strong> co<strong>de</strong>s pouvant composer un programme.<br />
Avant <strong>de</strong> détailler les objectifs <strong>de</strong> ce projet, nous commençons par expliquer qu est ce que<br />
l analyse <strong>de</strong> programmes, et les différentes techniques d analyses existant à l heure actuelle. Dans<br />
la <strong>de</strong>uxième section, nous définissons les objectifs du projet d analyse <strong>dynamique</strong> <strong>de</strong> programmes<br />
C. La <strong>de</strong>rnière section donne un aperçu rapi<strong>de</strong> <strong>de</strong>s capacités <strong>de</strong> notre outil d analyse <strong>dynamique</strong><br />
<strong>de</strong> programmes C.<br />
1.1. Qu est-ce que l analyse <strong>de</strong> programmes ?<br />
L analyse <strong>de</strong> programmes est un domaine <strong>de</strong> recherche qui s est développé dans le but <strong>de</strong><br />
comprendre assez rapi<strong>de</strong>ment les propriétés <strong>de</strong>s programmes <strong>de</strong> plus en plus complexes, et dont<br />
la maintenance <strong>de</strong>vient fastidieuse. En effet, il <strong>de</strong>vient nécessaire <strong>de</strong> mécaniser la procédure <strong>de</strong><br />
maintenance d un programme ou du moins d en faciliter la tâche, d autant plus que cette tâche est<br />
la plus coûteuse dans le cycle <strong>de</strong> production d un logiciel. Des étu<strong>de</strong>s ont d ailleurs montré que<br />
20% du coût <strong>de</strong> production est généré lors <strong>de</strong> la phase <strong>de</strong> développement, 40% lors <strong>de</strong> la phase<br />
<strong>de</strong> débuggage et 40% lors <strong>de</strong> la phase d ajout <strong>de</strong> nouvelles fonctionnalités [HAT 97, JAH 00]. Il<br />
est donc évi<strong>de</strong>nt que 80% <strong>de</strong>s dépenses se font lors <strong>de</strong> la phase <strong>de</strong> correction-maintenance d un<br />
logiciel. Ceci explique l importance pour les industries <strong>de</strong> réduire leurs dépenses pour la<br />
maintenance d un programme.<br />
Un analyseur <strong>de</strong> programmes est alors une ai<strong>de</strong> précieuse pour le développeur, car il lui permet <strong>de</strong><br />
comprendre plus facilement ce que fait un programme, en particulier dans le cas où ce <strong>de</strong>rnier fut<br />
développé plusieurs années en arrière et/ ou par différents programmeurs. Un analyseur permet<br />
également <strong>de</strong> détecter plus facilement <strong>de</strong>s erreurs ou <strong>de</strong>s instructions consommatrices en<br />
ressources systèmes, ce qui favorise alors un débuggage et une optimisation <strong>de</strong> co<strong>de</strong> plus rapi<strong>de</strong>s.<br />
Voici une liste possible d utilisation <strong>de</strong>s résultats d outils d analyse [LAN 05] :<br />
Les analyses <strong>de</strong> flots <strong>de</strong> données permettent <strong>de</strong> détecter notamment les variables inutiles<br />
ou les expressions calculées à un point <strong>de</strong> programme donné.<br />
Les analyses d'alias produisent <strong>de</strong>s informations sur le partage entre variables dans les<br />
langages à manipulation explicite <strong>de</strong> pointeurs.<br />
Le filtrage <strong>de</strong> programmes (slicing) consiste à i<strong>de</strong>ntifier les instructions d'un programme<br />
nécessaires au calcul <strong>de</strong> variables données.<br />
Le débuggage est une analyse <strong>dynamique</strong> <strong>de</strong> programmes interactive, qui permet à<br />
l utilisateur <strong>de</strong> spécifier «à la volée » les informations et propriétés qu il désire voir sur<br />
l exécution en cours.<br />
9
Chapitre 1 - Introduction<br />
Le monitoring d exécutions est une analyse <strong>dynamique</strong> <strong>de</strong> programmes non interactive.<br />
Le profileur est un moniteur permettant d avoir <strong>de</strong>s informations relatives au temps<br />
d exécution <strong>de</strong>s différents composants du programme.<br />
Il existe principalement <strong>de</strong>ux classes d'analyses : les analyses <strong>dynamique</strong>s et les analyses statiques.<br />
L'analyse <strong>dynamique</strong> déduit <strong>de</strong>s propriétés d'un programme à partir d'une trace d'exécution<br />
particulière. D un point <strong>de</strong> vue pratique l analyse <strong>dynamique</strong> s avère d une plus gran<strong>de</strong> ai<strong>de</strong> aux<br />
développeurs. Elle permet <strong>de</strong> fournir les valeurs <strong>de</strong>s données manipulées lors <strong>de</strong> l exécution du<br />
programme ainsi que l enchaînement <strong>de</strong>s étapes d exécution <strong>de</strong>s diverses instructions appelées. Il<br />
faut également noter que la précision <strong>de</strong>s informations fournies avec ce type d analyse entraîne la<br />
génération d une masse <strong>de</strong> données, ce qui relève les questions <strong>de</strong> représentation graphique et<br />
éventuellement dans certains cas <strong>de</strong> stockage.<br />
Contrairement à cette analyse <strong>dynamique</strong>, l analyse statique se contente <strong>de</strong> lire le programme en<br />
prenant en compte toutes les possibilités d exécutions. Ainsi, l'analyse statique permet d'établir<br />
<strong>de</strong>s propriétés satisfaites par un programme pour toutes ses exécutions et s avère utile pour<br />
comprendre toutes les possibilités d un programme et pour en voir les limites. L'information<br />
recherchée est en général incalculable ou d'une complexité importante, ce qui implique le fait que<br />
l analyse statique ne peut calculer qu'une approximation <strong>de</strong> la solution idéale.<br />
En conséquence, les résultats <strong>de</strong> l'analyse statique sont moins précis mais plus généraux que ceux<br />
fournis par une analyse <strong>dynamique</strong>. C est pour cette raison que <strong>de</strong>s outils basés sur une analyse<br />
<strong>dynamique</strong>, tels que les moniteurs, les profileurs et les débuggeurs sont nécessaires pour<br />
maintenir ou même développer un programme.<br />
1.2. Objectifs du projet d analyse <strong>dynamique</strong> <strong>de</strong><br />
programmes C<br />
1.2.1. Créer un outil d analyse <strong>de</strong> programmes C fiable et<br />
évolutif<br />
Un prototype d outil d analyse <strong>dynamique</strong> <strong>de</strong> programme, DDFgraph, a déjà été développé par<br />
l équipe <strong>de</strong> recherche du laboratoire d Intelligence Artificielle <strong>de</strong> l université <strong>de</strong> Vincennes (paris 8)<br />
par Françoise Balmas et Harald Wertz, pour le langage Lisp [BAL 05]. Le langage Lisp étant un<br />
langage interprété, il y a donc la possibilité <strong>de</strong> modifier l interprète Lisp afin d en extraire <strong>de</strong>s<br />
informations sur l exécution du programme. Ces informations sont par la suite exploitées pour<br />
générer le graphe <strong>de</strong> dépendances <strong>de</strong>s différentes interactions entre variables, pointeurs ou encore<br />
fonctions du programme source. L objectif du présent projet consiste à reproduire le même<br />
schéma d analyse <strong>de</strong> DDFgraph, mais en l adaptant au langage C qui est un langage compilé<br />
contrairement au Lisp.<br />
10
Chapitre 1 - Introduction<br />
1.2.2. Un affichage clair <strong>de</strong>s dépendances <strong>de</strong> données<br />
Le <strong>de</strong>uxième objectif <strong>de</strong> ce projet est <strong>de</strong> pouvoir donner une représentation graphique claire et<br />
bien structurée <strong>de</strong>s dépendances existant entre les données extraites. Il se trouve qu il n est pas<br />
aisé <strong>de</strong> trouver la bonne représentation <strong>de</strong>s relations entre les données utilisées, du fait que<br />
chaque langage a ses propres spécificités.<br />
Par exemple, le langage C donne la possibilité <strong>de</strong> manipuler <strong>de</strong>s tableaux contrairement au<br />
langage Lisp qui n utilise pas ce type <strong>de</strong> représentations. Il faut alors imaginer une forme <strong>de</strong><br />
représentation graphique montrant les modifications effectuées lors <strong>de</strong> l exécution du programme<br />
sur le tableau. Il faut également que cette <strong>de</strong>rnière soit assez claire pour être comprise du<br />
développeur <strong>de</strong> manière presque intuitive. L étu<strong>de</strong> <strong>de</strong>s représentations possibles est faite dans la<br />
section 2.3 du prochain chapitre.<br />
1.3. Présentation <strong>de</strong> l outil d analyse <strong>de</strong><br />
programmes C<br />
Le projet d analyse <strong>dynamique</strong> <strong>de</strong> programmes écrits en C à pour ambition d adapter l outil<br />
DDFgraph <strong>de</strong> [BAL 05] au langage C, car ce langage, bien qu ancien (crée en 1972 par Denis<br />
Ritchie), est cependant utilisé <strong>de</strong> manière plus importante que le langage Lisp.<br />
L outil d analyse <strong>de</strong> programmes C, réalisé dans le cadre <strong>de</strong> ce projet <strong>de</strong> DEA, offre <strong>de</strong>s<br />
possibilités d évolution <strong>de</strong> par sa base <strong>de</strong> conception. En effet, cet outil repose sur un interprète<br />
C modifié à notre convenance. Cette solution présente l avantage <strong>de</strong> pouvoir améliorer les<br />
performances <strong>de</strong> l outil sans trop d efforts pour comprendre son fonctionnement contrairement à<br />
ce que cela pourrait être avec le compilateur GCC. Il permet actuellement <strong>de</strong> gérer les boucles, les<br />
structures <strong>de</strong> contrôle mais uniquement <strong>de</strong>s objets <strong>de</strong> type entier tels que <strong>de</strong>s variables, <strong>de</strong>s<br />
fonctions, ou encore <strong>de</strong>s tableaux (cf. chapitre 5). Ceci peut être facilement étendu aux autres<br />
types en copiant la technique utilisée pour les types entiers et en l adaptant aux autres.<br />
Notre outil se doit d être une reproduction <strong>de</strong> l outil DDFgraph d analyse <strong>de</strong> programmes Lisp,<br />
pour le langage C. Pour comprendre le concept d analyse <strong>dynamique</strong> <strong>de</strong> ces <strong>de</strong>ux outils, je vais<br />
donner un exemple d utilisation <strong>de</strong> notre outil sur un simple programme C et présenter ce qu on<br />
entend par graphique <strong>de</strong> dépendances entre données. Puis pour comprendre l utilité <strong>de</strong> notre<br />
outil à terme je présente un exemple <strong>de</strong> résultat obtenu grâce à l outil DDFgraph. Cet exemple<br />
permettra <strong>de</strong> voir comment l outil d analyse <strong>dynamique</strong> <strong>de</strong> programme peut mettre en évi<strong>de</strong>nce le<br />
disfonctionnement d un programme bien que le résultat retourné soit visiblement correct.<br />
Il semble important à ce sta<strong>de</strong> d avoir une idée concrète <strong>de</strong> ce qu est une représentation<br />
graphique <strong>de</strong>s dépendances entre données, pour pouvoir abor<strong>de</strong>r la suite du mémoire. Pour cela,<br />
nous présentons le résultat obtenu par notre outil pour un programme C qui effectue <strong>de</strong> simples<br />
opérations sur <strong>de</strong>s variables, le contenu du fichier <strong>de</strong> co<strong>de</strong> source utilisé « ext_affvar.c » est listé ci<strong>de</strong>ssous.<br />
1<br />
2 /*<br />
3 ext_affvar.c<br />
11
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
4 */<br />
5<br />
6<br />
7 int m;<br />
8<br />
9 int main()<br />
10 {<br />
11 int x,y,a,b,c;<br />
12<br />
13 x = 12;<br />
14 y = 8;<br />
15 m = 15;<br />
16 a = x + y;<br />
17 b = x - y;<br />
18 c = a + b;<br />
19 return c;<br />
20 }<br />
::EiC:: : 5 -> [main]<br />
13.- <br />
Def 1-0 12 13<br />
14.- <br />
Def 1-1 8 14<br />
15.- <br />
Def 0-2 15 15<br />
16.- <br />
Use 1-0 13 16<br />
Use 1-1 14 16<br />
Def 1-2 20 16<br />
17.- <br />
Use 1-0 13 17<br />
Use 1-1 14 17<br />
Def 1-3 4 17<br />
18.- <br />
Use 1-2 16 18<br />
Use 1-3 17 18<br />
Def 1-4 24 18<br />
19.- <br />
Use 1-4 18 19<br />
Notre outil a extrait <strong>de</strong> l exécution <strong>de</strong> ce programme l ensemble <strong>de</strong>s informations manipulées, à<br />
savoir les variables définies et leurs valeurs. On peut voir à la suite du co<strong>de</strong> source le format <strong>de</strong>s<br />
données extraites, on peut y distinguer <strong>de</strong>ux types d informations : Use var l1 l2 et Def var val L.<br />
Quand on a Use var l1 l2 cela signifie que l instruction <strong>de</strong> la ligne l2 utilise la variable var<br />
définie en ligne l1, et quand on a Def var val L cela signifie que l instruction <strong>de</strong> la ligne L définit<br />
la variable var avec la valeur val. Prenons par exemple l instruction <strong>de</strong> la ligne 16 du<br />
programme, dans laquelle on affecte à la variable a la somme <strong>de</strong>s valeurs <strong>de</strong> x et y. Dans les<br />
données extraites on peut voir pour l instruction 16 (surlignée en bleu) les informations suivantes :<br />
- Use 1-0 13 16, signifie que l instruction <strong>de</strong> la ligne 16 utilise la variable nommée « 1-<br />
0 » (qui correspond à x) 1 définie auparavant à la ligne 13 du co<strong>de</strong> source (cf. définition<br />
mise en évi<strong>de</strong>nce dans les informations extraites par le surlignage orange).<br />
- Use 1-1 14 16, signifie que l instruction <strong>de</strong> la ligne 16 utilise la variable nommée « 1-<br />
1 » (qui correspond à y) définie auparavant à la ligne 14 du co<strong>de</strong> source (cf. définition<br />
mise en évi<strong>de</strong>nce dans les informations extraites par le surlignage jaune).<br />
- Def 1-2 20 16, signifie que l instruction <strong>de</strong> la ligne 16 définit la variable « 1-2 », c est-àdire<br />
a, avec la valeur 20, somme <strong>de</strong> 12 pour x et 8 pour y.<br />
Ainsi, le format <strong>de</strong> données extraites aussi appelé base <strong>de</strong> données, est assez abstrait et n est donc<br />
pas adapté pour une lecture humaine. En effet, ce format est conçu <strong>de</strong> manière à décomposer le<br />
co<strong>de</strong> source pour mettre en évi<strong>de</strong>nce les dépendances entre ses données (ici variables), que nous<br />
transformons ensuite en un graphe donné en figure 1, il <strong>de</strong>vrait à terme donner le résultat <strong>de</strong> la<br />
figure 2.<br />
1 Les variables sont désignées actuellement par <strong>de</strong>s i<strong>de</strong>ntifiants (comme ils sont distingués dans l interprète) en<br />
attendant que la correspondance avec la table <strong>de</strong>s symboles soit faite afin <strong>de</strong> récupérer leur nom.<br />
12
Chapitre 1 - Introduction<br />
1-0 = 12 1-1 = 8<br />
0-2 = 15<br />
1-2 = 20<br />
1-3 = 4<br />
1-4 = 24<br />
Figure 2. Graphique mettant en évi<strong>de</strong>nce<br />
les dépendances entre les données<br />
manipulées par le programme<br />
« ext_affvar.c »<br />
Figure 2. Même graphique qu en figure 1<br />
avec les i<strong>de</strong>ntifiants <strong>de</strong> variables<br />
remplacés par leurs symboles.<br />
Sur la figure 2, on peut voir les dépendances entre les variables du programme <strong>de</strong> notre exemple<br />
et les lignes qui les référencent. Les lignes d instructions sont représentées par <strong>de</strong>s n uds <strong>de</strong><br />
couleur noire avec le numéro <strong>de</strong> ligne inscrit à leur centre, les variables sont représentées par <strong>de</strong>s<br />
n uds <strong>de</strong> couleur verte avec le nom <strong>de</strong> la variable et sa valeur inscrites à leur centre. Reprenons la<br />
ligne 16 du co<strong>de</strong> source, sur le graphique <strong>de</strong> la figure 2 on peut voir <strong>de</strong>ux flèches dirigées vers le<br />
n ud 16 et partant chacune <strong>de</strong>s variables x et y dont les valeurs respectives sont égales à 12 et 8.<br />
Le n ud 16 renvoie une flèche sur la variable a dont la valeur <strong>de</strong>vient égale à 20.<br />
Comme on peut le voir sur cet exemple, le graphe <strong>de</strong> dépendance entre données nous permet <strong>de</strong><br />
voir assez facilement les liens entre les données du programmes, cette visualisation peut mettre en<br />
évi<strong>de</strong>nce <strong>de</strong>s variables définies mais non utilisées comme le montre également notre exemple<br />
pour la variable m qui est visuellement isolée <strong>de</strong>s autres n uds, ce qui signifie qu elle n a pas été<br />
utilisée dans le co<strong>de</strong> source.<br />
Les travaux <strong>de</strong> [BAL 05] ont montré l intérêt <strong>de</strong> la représentation graphique <strong>de</strong>s dépendances<br />
<strong>dynamique</strong>s pour la compréhension <strong>de</strong> programmes. Elle permet notamment <strong>de</strong> montrer le<br />
fonctionnement général d un programme 2 , <strong>de</strong> suivre ses appels <strong>de</strong> fonctions, <strong>de</strong> détecter<br />
d éventuelles erreurs <strong>de</strong> conceptions ou encore <strong>de</strong> vérifier le comportement du programme. C est<br />
ce que nous montrons dans l exemple suivant où DDFgraph gère une version Lisp du<br />
programme Blocks Word classique <strong>de</strong> l Intelligence Artificielle [WIN 72], qui permet <strong>de</strong><br />
manipuler <strong>de</strong>s objets sur une table. Dans la figure 3, la visualisation <strong>de</strong>s valeurs <strong>de</strong>s variables<br />
globales (en gris foncé dans le graphe) montre l effet du programme : la boite a est mémorisée<br />
2 Pour cela le graphe <strong>de</strong> dépendances est compacté (cf. figure 3) <strong>de</strong> manière à montrer uniquement les valeurs<br />
connues en entrée et en sortie.<br />
13
avec un ensemble <strong>de</strong> propriétés qui vont ensuite permettre au programme <strong>de</strong> la manipuler<br />
correctement.<br />
Figure 3. Graphique con<strong>de</strong>nsé d'un programme d'IA qui place un objet sur une table<br />
Figure 4. Exemple d'utilisation <strong>de</strong> DDFgraph mettant en évi<strong>de</strong>nce une erreur d'exécution<br />
Sur la figure 4, on peut voir le fonctionnement <strong>de</strong> ce même programme qui place un objet <strong>de</strong><br />
type boite <strong>de</strong> dimension 2*2 sur une table <strong>de</strong> dimension 4*4 (la table et les objets sont<br />
représentés comme <strong>de</strong>s matrices). L objet est déposé sur la table en position 1-1 (cf. R-<br />
trouvePlaceSur = ( 1 1) ). Vu les dimensions <strong>de</strong> l objet il sera ainsi placé sur les positions 1-1, 1-2,<br />
2-1 et 2-2 ce qui est correct, puisque la table était initialement vi<strong>de</strong>. Mais en regardant en détail le<br />
comportement <strong>de</strong> la fonction trouvePlaceSur, on remarque que cette <strong>de</strong>rnière vérifie<br />
uniquement la disponibilité <strong>de</strong>s positions 1-1, 1-2, et 2-1 sur la table (soulignés en rouge sur la<br />
14
Chapitre 1 - Introduction<br />
figure) et la vérification <strong>de</strong> la <strong>de</strong>rnière position 2-2 est ignorée. Cela traduit donc un<br />
disfonctionnement du programme, bien que ce <strong>de</strong>rnier donne un bon résultat au final.<br />
Après cet aperçu rapi<strong>de</strong> <strong>de</strong>s possibilités <strong>de</strong> l outil d analyse <strong>de</strong> programmes, nous traitons dans le<br />
chapitre qui suit <strong>de</strong>s problématiques résultant <strong>de</strong> l analyse <strong>dynamique</strong> <strong>de</strong> programmes en langage<br />
C et <strong>de</strong> la génération <strong>de</strong> graphiques <strong>de</strong> dépendances. Dans ce même chapitre nous décrivons les<br />
solutions choisies pour chacune <strong>de</strong>s problématiques. Dans le chapitre 3 nous comparons les<br />
interprètes qui nous étaient accessibles et donnons les raisons pour lesquelles notre choix s est<br />
porté sur l interprète EiC. Les spécificités <strong>de</strong> cet interprète sont détaillées dans le chapitre 4 qui<br />
décrit également les différences entre EiC et le langage C, une <strong>de</strong>scription <strong>de</strong> la structure <strong>de</strong> ses<br />
fichiers sources est également faite dans ce chapitre afin <strong>de</strong> mieux introduire dans la chapitre 5 les<br />
modifications que nous avons apportées à EiC et les techniques utilisées pour générer le<br />
graphique <strong>de</strong> dépendance <strong>de</strong> données. Le chapitre 6 présente plusieurs graphes générés par notre<br />
outil. Le chapitre 7 donne un aperçu <strong>de</strong>s étu<strong>de</strong>s dans le domaine <strong>de</strong> l analyse <strong>dynamique</strong> et dans<br />
celui <strong>de</strong> la représentation graphique <strong>de</strong> programmes. Le chapitre 8 conclu ce mémoire avec une<br />
présentation <strong>de</strong>s principales perspectives.<br />
15
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Chapitre 2 - Approche <strong>de</strong> la<br />
problématique et choix <strong>de</strong> la<br />
solution<br />
Le projet d analyse <strong>dynamique</strong> <strong>de</strong> programmes C pose <strong>de</strong> nombreux problèmes. En effet,<br />
les spécificités du langage C par comparaison au Lisp 3 , nous amènent à nous <strong>de</strong>man<strong>de</strong>r comment<br />
extraire <strong>de</strong> manière <strong>dynamique</strong> les données manipulées par le programme source et plus<br />
particulièrement à quel niveau <strong>de</strong> transformation du programme cela pourrait se faire. De même,<br />
il faut déterminer quels sont les types <strong>de</strong> données à extraire du programme afin d apporter au<br />
développeur une analyse fiable et précise. Enfin, il faut choisir <strong>de</strong> quelle manière représenter<br />
graphiquement l ensemble <strong>de</strong> ces informations <strong>de</strong> manière à avoir une vision claire du<br />
déroulement d un programme.<br />
La section 2.1 ci-<strong>de</strong>ssous traite <strong>de</strong> la question <strong>de</strong> la spécificité du langage C, et présente la solution<br />
choisie pour ce projet. La section suivante 2.2, traite quant à elle du type <strong>de</strong>s données à extraire.<br />
La <strong>de</strong>rnière section 2.3, expose la manière dont les informations extraites sont représentées et la<br />
technique mise en place pour le réaliser.<br />
2.1. Comment extraire <strong>dynamique</strong>ment les<br />
données d un programme source en langage<br />
C ?<br />
Comme nous l avons dit dans le premier chapitre, le projet d analyse <strong>dynamique</strong> <strong>de</strong> programme a<br />
déjà été réalisé pour <strong>de</strong>s programmes écrits en langage Lisp. Ce langage est un langage interprété,<br />
c'est-à-dire que l exécution du programme se résume à un cycle <strong>de</strong> lecture <strong>de</strong>s instructions, ligne<br />
par ligne, puis <strong>de</strong> leur évaluation. Pour analyser <strong>de</strong>s programmes écrits en Lisp il suffit donc <strong>de</strong><br />
modifier l interprète Lisp même, afin <strong>de</strong> lui permettre <strong>de</strong> générer, pendant la lecture et l exécution<br />
<strong>de</strong>s instructions, les données relatives au co<strong>de</strong> à analyser.<br />
Par contre, le langage C est un langage compilé, c'est-à-dire qu exécuter un co<strong>de</strong> source C revient<br />
à le transformer d abord en un programme exécutable (binaire). Les étapes <strong>de</strong> la compilation sont<br />
décrites plus en détail ci-<strong>de</strong>ssous.<br />
2.1.1. Les étapes <strong>de</strong> la compilation <strong>de</strong> GCC<br />
La transformation d un programme C en binaire se déroule en <strong>de</strong>ux étapes indépendantes : le<br />
prétraitement et la compilation proprement dite.<br />
3<br />
Notamment le fait qu il soit compilé plutôt qu interprété.<br />
17
Chapitre 2<br />
Approche <strong>de</strong> la problématique et choix <strong>de</strong> la solution<br />
L étape <strong>de</strong> prétraitement correspond à une modification du texte d un fichier source, basée<br />
essentiellement sur l interprétation d instructions très particulières dites directives à <strong>de</strong>stination du<br />
préprocesseur ; ces <strong>de</strong>rnières sont reconnaissables par le fait qu elles commencent par le symbole<br />
#. Par exemple l instruction #inclu<strong>de</strong> permet au programme source d utiliser <strong>de</strong>s fonctions <strong>de</strong>s<br />
librairies standards ou d autres fichiers <strong>de</strong> co<strong>de</strong> (« hea<strong>de</strong>rs » d extension .h).<br />
L étape <strong>de</strong> compilation consiste à traduire les fichiers sources en langage machine, le résultat <strong>de</strong><br />
cette opération portera le nom <strong>de</strong> «module objet ». Après assemblage <strong>de</strong>s différents modules, un<br />
éditeur <strong>de</strong> lien réunit les modules objets et les fonctions <strong>de</strong> la bibliothèque standard pour<br />
constituer un programme exécutable par la machine.<br />
Sans rentrer plus en détail dans le fonctionnement d un compilateur C on peut voir sur la figure 5<br />
un schéma <strong>de</strong> la compilation [GRU 00] qui résume son cycle jusqu à la génération du fichier<br />
exécutable.<br />
Lecture du texte<br />
du programme<br />
Optimisation du<br />
CI<br />
caractères<br />
CI<br />
<strong>Analyse</strong> lexicale<br />
lexèmes<br />
Génération <strong>de</strong><br />
co<strong>de</strong><br />
Instructions symboliques<br />
Fichier<br />
souce<br />
<strong>Analyse</strong><br />
syntaxique<br />
arbre abstrait<br />
Co<strong>de</strong><br />
intermédiaire<br />
Optimisation du<br />
co<strong>de</strong> cible<br />
Instr. symboliques<br />
Fichier<br />
exécutable<br />
<strong>Analyse</strong><br />
sémantique<br />
Génération <strong>de</strong><br />
co<strong>de</strong> machine<br />
arbre décoré<br />
Suite <strong>de</strong> bits<br />
Génération du<br />
co<strong>de</strong> intermédiaire<br />
Sortie du co<strong>de</strong><br />
exécutable<br />
Partie avant<br />
Compilateur<br />
Partie arrière<br />
Figure 5. Structure d'un compilateur<br />
Dans la section suivante nous étudions à quelle(s) étape(s) <strong>de</strong> la transformation on peut obtenir<br />
les informations sur notre programme source donné en entrée.<br />
18
Chapitre 2<br />
Approche <strong>de</strong> la problématique et choix <strong>de</strong> la solution<br />
2.1.2. Le choix d une solution<br />
Maintenant que nous avons vu la structure d un compilateur C et sachant que le co<strong>de</strong> binaire qu il<br />
génère est uniquement <strong>de</strong>stiné à la machine, il semble évi<strong>de</strong>nt que le programme exécutable en<br />
fin <strong>de</strong> transformation ne peut nous être utile pour notre travail. Une première solution possible<br />
est <strong>de</strong> modifier le compilateur GCC 4 , en y intégrant le co<strong>de</strong> nécessaire à l obtention<br />
d informations <strong>dynamique</strong>s, co<strong>de</strong> qui sera activé pendant l exécution du programme binaire. Ceci<br />
nous permettrait d inclure en co<strong>de</strong> compilé les instructions nécessaires à la génération <strong>de</strong>s<br />
informations <strong>dynamique</strong>s. Cette solution, bien que réalisable, n est pas retenue dans notre projet<br />
car elle <strong>de</strong>man<strong>de</strong> une connaissance assez poussée du compilateur GCC, difficile à acquérir<br />
pendant la durée du projet, d autant plus qu une autre solution plus simple était possible. En effet<br />
il existe <strong>de</strong>s interprètes du langage C, qui permettent d exécuter instruction par instruction chaque<br />
fichier source. On peut voir sur le schéma <strong>de</strong> la figure 7 la différence existant entre un<br />
compilateur et un interprète [GRU 00].<br />
Co<strong>de</strong><br />
source<br />
Co<strong>de</strong><br />
intermédiaire<br />
Machine<br />
prétraitement<br />
Compilation<br />
traitement<br />
Co<strong>de</strong><br />
source<br />
Co<strong>de</strong><br />
intermédiaire<br />
Interprète<br />
prétraitement<br />
traitement<br />
Interprétation<br />
Figure 6. Comparaison entre un compilateur et un interprète<br />
L avantage ici est que la taille du co<strong>de</strong> source d un interprète est beaucoup moins importante que<br />
celle du compilateur GCC. Il est donc plus facile à étudier et par conséquent ses fonctionnalités<br />
sont plus simples à modifier. De plus, l approche à suivre est similaire à l approche suivie pour<br />
l interprète Lisp.<br />
La problématique due à la complexité du compilateur du langage C est <strong>de</strong> cette manière écartée, il<br />
nous reste donc plus qu à trouver un interprète C, assez bien conçu, parmi ceux existant dans<br />
l univers du logiciel libre. L ensemble <strong>de</strong>s interprètes trouvés sont présentés et comparés dans le<br />
chapitre 3.<br />
2.2. Quelles données extraire ?<br />
Dans cette section nous réfléchissons sur le type <strong>de</strong> données à extraire d un fichier source C, ce<br />
qui représente une autre problématique à ce projet. Qui consiste à savoir quelles sont les données<br />
4<br />
Plus précisément l option p du profileur <strong>de</strong> GCC.<br />
19
Chapitre 2<br />
Approche <strong>de</strong> la problématique et choix <strong>de</strong> la solution<br />
que nous pouvons extraire lors <strong>de</strong> l exécution d un programme et ceci sans avoir à modifier le<br />
co<strong>de</strong> source à analyser.<br />
En se basant sur les travaux réalisés au laboratoire d Intelligence Artificielle <strong>de</strong> l Université <strong>Paris</strong> 8<br />
concernant la compréhension <strong>de</strong> programmes, qui consistent à interroger <strong>de</strong>s programmeurs sur<br />
leurs métho<strong>de</strong>s pour lire et comprendre un fichier source [BAL 00], un nombre d informations se<br />
sont avérées intéressantes à tracer :<br />
- Les modifications <strong>de</strong>s valeurs <strong>de</strong> variables (locales ou globales)<br />
- Les noms <strong>de</strong> fonctions appelées, leurs arguments et les valeurs <strong>de</strong> ces <strong>de</strong>rnières tout au<br />
long <strong>de</strong> l exécution du programme<br />
- L interaction entre les fichiers sources.<br />
En effet, la trace <strong>de</strong> ces types d informations permet au programmeur d optimiser son co<strong>de</strong> en<br />
détectant les variables déclarées mais non utilisées ou encore en détectant <strong>de</strong>s erreurs <strong>de</strong><br />
conception du programme, qui font que le programme compile sans aucune erreur mais ne<br />
donne pas le résultat attendu. De même, tracer le passage dans les boucles for/ while/ do permet <strong>de</strong><br />
détecter les boucles sans fin, voire les boucles inutiles.<br />
Dans le cadre <strong>de</strong> ce projet, l ensemble <strong>de</strong>s informations que nous avons choisi d extraire est :<br />
- Les variables et leurs valeurs<br />
- Les fonctions et leurs arguments<br />
- Les tableaux à une dimension<br />
- Les conditions et leur valeur (vraie ou fausse)<br />
- L emplacement dans le co<strong>de</strong> source (fichier, numéro <strong>de</strong> ligne)<br />
- Le nombre d appel d une instruction<br />
En effet les <strong>de</strong>ux <strong>de</strong>rnières informations vont nous permettre <strong>de</strong> savoir <strong>de</strong> quelle ligne du co<strong>de</strong><br />
vient la valeur d une variable utilisée, l utilité <strong>de</strong> ces <strong>de</strong>rnières données est détaillé au chapitre 5.<br />
A terme, nous envisageons d extraire les appels récursifs <strong>de</strong> fonctions, le passage d un pointeur<br />
ou d un tableau en argument d une fonction, et d autres particularités du langage C. Mais le<br />
principal objectif dans ce projet est <strong>de</strong> représenter graphiquement dans un premier temps les<br />
informations listées plus haut. On pourra dans <strong>de</strong>s travaux futurs étendre cette technique à<br />
l ensemble <strong>de</strong>s données manipulées lors <strong>de</strong> l exécution d un programme C (cf. chapitre 8).<br />
2.3. La représentation graphique<br />
Cette section présente une autre problématique <strong>de</strong> notre projet d analyse <strong>dynamique</strong> <strong>de</strong><br />
programmes C qui survient une fois que les données sont extraites. En effet, l extraction <strong>de</strong>s<br />
données du programme en cours d exécution nous amène à nous interroger sur la manière <strong>de</strong><br />
représenter graphiquement ces informations <strong>de</strong> manière <strong>dynamique</strong>. Une réflexion a déjà été<br />
menée pour la représentation <strong>de</strong>s interactions entre données extraites <strong>de</strong> programmes Lisp [BAL<br />
01]. Cette réflexion a conduit à représenter les données telle que l appel à une fonction <strong>de</strong> la<br />
manière suivante pour le langage Lisp :<br />
Soit le co<strong>de</strong> source <strong>de</strong> la fonction som2(x y) qui effectue la somme <strong>de</strong>s carrés <strong>de</strong> <strong>de</strong>ux<br />
nombres, listé ci-<strong>de</strong>ssous dans les lignes 1 à 4.<br />
1. (<strong>de</strong> square (a)<br />
2. (* a a))<br />
3. (<strong>de</strong> som2 (x y)<br />
4. (+ (square x) (square y)))<br />
20
Chapitre 2<br />
Approche <strong>de</strong> la problématique et choix <strong>de</strong> la solution<br />
5. ?<br />
6. ? (som2 3 5)<br />
7. = 34<br />
Sur la figure 8 on peut visualiser le graphique correspondant à l appel <strong>de</strong> (som2 3 5) (cf. ligne<br />
6), avec le détail <strong>de</strong> toutes les relations entre les fonctions et variables utilisées par le programme.<br />
Figure 7. Graphe <strong>de</strong> dépendance pour (som2 3 5) avec toutes les dépendances<br />
En effet, l outil DDFgraph permet <strong>de</strong> gérer non seulement l affichage <strong>de</strong>s interactions entre<br />
variables mais également l affichage <strong>de</strong>s appels entre fonctions. Les variables sont représentées<br />
par <strong>de</strong>s n uds ovales colorés contenant le nom <strong>de</strong> la variable et sa valeur, les fonctions sont<br />
représentées par <strong>de</strong>s rectangles noirs contenant le nom <strong>de</strong> la fonction. Si une fonction renvoie un<br />
résultat, ce <strong>de</strong>rnier est représenté comme une variable dont le nom est le nom <strong>de</strong> la fonction<br />
précédé d un R-. Par exemple, la fonction som2 fait appel à la fonction square pour ses <strong>de</strong>ux<br />
arguments : 3 et 5. Le résultat renvoyé par l appel à som2 est également visible sur le graphique<br />
R-som2 = 34.<br />
Contrairement à la figure 7 où tous les appels effectués sont représentés, la figure 8 présente ce<br />
même graphe <strong>de</strong> dépendances sous forme con<strong>de</strong>nsée, c est-à-dire que seules les entrées/sorties<br />
<strong>de</strong> la fonction som2 sont visibles et que les appels internes à cette fonction sont cachés. Grâce à<br />
l interface graphique <strong>de</strong> l outil DDFgraph, <strong>de</strong> simples manipulations à la souris permettent <strong>de</strong><br />
passer d une représentation à une autre.<br />
21
Chapitre 2<br />
Approche <strong>de</strong> la problématique et choix <strong>de</strong> la solution<br />
Figure 8. Graphe <strong>de</strong> dépendances <strong>de</strong> l'appel <strong>de</strong> (som2 3 5) avec affichage <strong>de</strong>s appels globaux<br />
Il existe d autres types <strong>de</strong> représentations graphiques pouvant être générées par DDFgraph,<br />
comme l affichage sélectif <strong>de</strong>s appels dans un programme ainsi que d autres représentations<br />
toujours interactives permettant au développeur <strong>de</strong> manipuler le graphique à sa guise.<br />
Pour notre outil, nous tâchons <strong>de</strong> traiter <strong>de</strong>s choses simples pour le moment tout en suivant les<br />
définitions <strong>de</strong> représentation <strong>de</strong>s données par DDFgraph. A savoir, les variables seront<br />
représentées par <strong>de</strong>s ellipses et les fonctions par <strong>de</strong>s rectangles, les i<strong>de</strong>ntificateurs <strong>de</strong> boucles<br />
(for, while, do) ainsi que les structures <strong>de</strong> contrôle (if/ else) seront représentés par <strong>de</strong>s<br />
losanges dont les liens partent du sommet droit si la condition est vraie et du gauche sinon. Nous<br />
pouvons voir un exemple <strong>de</strong> cette représentation graphique ci-<strong>de</strong>ssous :<br />
main<br />
X=2<br />
Vrai<br />
if<br />
(x>=1)<br />
Faux<br />
exit<br />
La manière dont sont générés les graphiques <strong>de</strong> dépendances <strong>dynamique</strong>s <strong>de</strong> données est détaillée<br />
dans le chapitre 5. Le chapitre qui suit décrit les différents interprètes C et explique notre choix<br />
d interprète.<br />
22
Chapitre 2<br />
Approche <strong>de</strong> la problématique et choix <strong>de</strong> la solution<br />
23
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Chapitre 3 - Les interprètes C existants<br />
Comme il a été expliqué dans la section 2.1, l extraction <strong>de</strong>s informations d un programme<br />
C en cours d exécution est faite à l ai<strong>de</strong> d un interprète et non pas du compilateur GCC. Il existe<br />
un certain nombre d interprètes du domaine public pour le langage C, dont l utilisation est<br />
principalement orientée pour l apprentissage du langage C. En effet, la particularité d un<br />
interprète <strong>de</strong> permettre à l utilisateur <strong>de</strong> visualiser le résultat <strong>de</strong> chaque instruction après son<br />
exécution, ai<strong>de</strong> les débutants en langage C d en comprendre le fonctionnement plus aisément.<br />
Ce chapitre présente ces interprètes C, les compare, et discute <strong>de</strong>s tests effectués sur ceux qui<br />
sont le plus susceptibles <strong>de</strong> nous ai<strong>de</strong>r à la réalisation du travail d analyse <strong>dynamique</strong> <strong>de</strong>s<br />
programmes C. Les principaux critères requis pour l interprète recherché sont :<br />
- Interpréter le langage C dans toutes ses spécificités (librairies standard du C, pointeurs,<br />
structures, récursivité, etc )<br />
- Disponibilité du co<strong>de</strong> source<br />
- Traitement d un programme source faisant appel à plusieurs fichiers (hea<strong>de</strong>rs et autres<br />
fichiers source .c)<br />
- Prise en charge <strong>de</strong> programmes C avec un grand nombre <strong>de</strong> lignes <strong>de</strong> co<strong>de</strong>s<br />
- Éventuellement un débuggeur intégré<br />
On peut voir dans le tableau ci-<strong>de</strong>ssous un rapi<strong>de</strong> aperçu <strong>de</strong> ces critères pour l ensemble <strong>de</strong>s<br />
interprètes C trouvés :<br />
Interprètes<br />
Langage<br />
Supporte toute<br />
la librairie<br />
standard C ?<br />
Licence<br />
Co<strong>de</strong> source<br />
accessible ?<br />
Débuggeur<br />
intégré ?<br />
Un<strong>de</strong>rC C++/C Non GPL 5 Oui Non<br />
Cint C++/C Non GPL Oui Non<br />
JFL C Mini C Non Payant Non Non<br />
EiC C Oui GPL Oui Oui<br />
Ch C/C++/Ch/Shell Oui GPL Non Non<br />
Figure 9. Tableau récapitulatif <strong>de</strong>s propriétés <strong>de</strong>s interprètes C<br />
Les sous-sections qui suivent décrivent en détail chacun <strong>de</strong> ces interprètes, avec leurs avantages et<br />
leurs inconvénients. Les interprètes proches <strong>de</strong>s critères exposés plus haut sont testés pour en<br />
voir les limites. Dans la <strong>de</strong>rnière sous-section, j explique mon choix d interprète pour réaliser le<br />
travail d analyse <strong>dynamique</strong>, en fonction <strong>de</strong>s critères <strong>de</strong>s interprètes trouvés et <strong>de</strong>s résultats <strong>de</strong><br />
leur test.<br />
5 General Public Licence<br />
24
Chapitre 3<br />
Les interprètes C existants<br />
3.1. Un<strong>de</strong>rC<br />
Cet outil est un interprète plus particulièrement orienté pour le langage C++, développé par<br />
Steve Donovan en 2001 et dont la <strong>de</strong>rnière version date <strong>de</strong> 2003 [DON 02]. L auteur décrit<br />
Un<strong>de</strong>rC comme un interprète compact <strong>de</strong> C++ (« A compact C++ interpreter »), mais il est capable<br />
également d interpréter <strong>de</strong>s programmes C. En effet, il utilise <strong>de</strong>s librairies standard C construites<br />
autour <strong>de</strong> GCC 2.95, ce qui lui confère la capacité <strong>de</strong> supporter la syntaxe <strong>de</strong>s langages C++ et C.<br />
Un<strong>de</strong>rC fonctionne sur <strong>de</strong>s environnements Linux et Windows.<br />
Un<strong>de</strong>rC gère une version <strong>de</strong> «poche » <strong>de</strong>s libraires C++ et permet d importer <strong>de</strong>s librairies<br />
externes. Un<strong>de</strong>rC peut aussi s utiliser comme un interpréteur Shell, c'est-à-dire que les<br />
instructions sont saisies en lignes <strong>de</strong> comman<strong>de</strong>s et offre <strong>de</strong>s comman<strong>de</strong>s internes. Ces<br />
comman<strong>de</strong>s internes permettent entre autres <strong>de</strong> charger un fichier <strong>de</strong> co<strong>de</strong> (#l fichier.c), et<br />
<strong>de</strong> l exécuter (#r fichier.c). Il permet aussi d exécuter dans son interface <strong>de</strong>s comman<strong>de</strong>s<br />
Shell (exemple : #x dir ou #x ls a). Certaines options permettent d avoir un verbose mo<strong>de</strong> et<br />
<strong>de</strong> tracer une fonction lors <strong>de</strong> son exécution.<br />
Prenons le programme « testinterpC.c » listé ci-<strong>de</strong>ssous qui effectue <strong>de</strong>s opérations simples sur <strong>de</strong>s<br />
variables entières.<br />
/*testinterpC.c<br />
*/<br />
#inclu<strong>de</strong> <br />
void main(int argc,char *argv[])<br />
{<br />
int x,y,z,w,v;<br />
x=0;<br />
y=1;<br />
printf("valeur <strong>de</strong> x = %d\n",x);<br />
printf("valeur <strong>de</strong> y = %d\n",y);<br />
z=x+y;<br />
printf("valeur <strong>de</strong> z(x+y) = %d\n",z);<br />
x=3;<br />
y=4;<br />
w=x-y;<br />
v=z*w;<br />
printf("valeur <strong>de</strong> x = %d\n",x);<br />
printf("valeur <strong>de</strong> y = %d\n",y);<br />
printf("valeur <strong>de</strong> w(x-y) = %d\n",w);<br />
printf("valeur <strong>de</strong> v(z*w) = %d\n",v);<br />
}<br />
On peut voir à la figure 10 un aperçu du chargement du co<strong>de</strong> source et <strong>de</strong> son exécution avec les<br />
comman<strong>de</strong>s #l et #r.<br />
L exécution du co<strong>de</strong> testé a nécessité <strong>de</strong> modifier l écriture <strong>de</strong> la déclaration <strong>de</strong> la fonction main()<br />
car Un<strong>de</strong>rC ne prend en compte la fonction main() que ci cette <strong>de</strong>rnière est écrite sous la<br />
forme : void main(int argc, char *argv[]).<br />
Bien que les fonctionnalités d Un<strong>de</strong>rC soient intéressantes, son installation sous Linux ne fut pas<br />
sans peine. En effet, Un<strong>de</strong>rC a été développé sous RedHat 7.0 avec un noyau 1.2.9 et nécessite la<br />
librairie libc 6 pour pouvoir s installer. Or les systèmes Linux actuels sont basés sur <strong>de</strong>s noyaux<br />
beaucoup plus récents (un noyau 2.4.20 pour la RedHat 9.0 -actuelle <strong>de</strong>rnière version-), <strong>de</strong> plus<br />
les nouvelles versions <strong>de</strong> GCC (actuellement la <strong>de</strong>rnière version <strong>de</strong> GCC est 4.0.1) ne supportent<br />
plus la librairie libc6. Donc utiliser Un<strong>de</strong>rC nécessite une ancienne version <strong>de</strong> Linux et/ ou du<br />
compilateur GCC.<br />
25
Figure 10. Exemple d utilisation <strong>de</strong> l interprète Un<strong>de</strong>rC<br />
De plus, nous voulons dans le cadre <strong>de</strong> notre projet pouvoir interpréter <strong>de</strong>s programmes C écrits<br />
suivant la norme ISO99 et basés sur la norme ANSI C. Or Un<strong>de</strong>rC ne supporte pas les librairies<br />
standard C suivantes : « ctype.h », « errno.h », « float.h », « limits.h », « locale.h », « setjmp .h» et « signal.h »,<br />
ce qui signifie qu Un<strong>de</strong>rC ne prend en charge qu environ la moitié <strong>de</strong> la librairie standard C,<br />
contrairement à ce qui est dit dans la documentation <strong>de</strong> l interprète.<br />
Du fait <strong>de</strong> ces limites, surtout en ce qui concerne la prise en charge <strong>de</strong>s librairies standard du C,<br />
et en plus <strong>de</strong> sa lour<strong>de</strong>ur d utilisation (saisie non intuitive dans l interface, messages d erreurs peu<br />
clairs et non documentés, bug dans le report <strong>de</strong>s numéros <strong>de</strong> lignes du co<strong>de</strong> source), l interprète<br />
Un<strong>de</strong>rC n est pas sélectionné pour le reste <strong>de</strong>s tests.<br />
3.2. Cint<br />
Cint est un interpréteur C/C++ qui permet d interpréter à 95% <strong>de</strong> l ANSI/ISO C et à 80% du<br />
C++ d après son auteur Masaharu Goto [GOT 05]. Cet outil a été créé en 1995 et est resté en<br />
développement jusqu à aujourd hui où la <strong>de</strong>rnière version 5.16.2 a été mise en ligne en juillet 2005.<br />
La version sur la quelle se sont portés mes premiers tests est la version 5.15.171 qui comportait<br />
plus <strong>de</strong> bugs que la nouvelle version. Les traces d exécutions et tests <strong>de</strong> cette section ont été<br />
réalisés avec la <strong>de</strong>rnière version <strong>de</strong> l outil.<br />
Tout comme Un<strong>de</strong>rC, Cint permet d exécuter un fichier <strong>de</strong> co<strong>de</strong> C grâce à <strong>de</strong>s comman<strong>de</strong>s<br />
internes. Ces comman<strong>de</strong>s internes servent aussi à interpréter <strong>de</strong>s instructions saisies en ligne <strong>de</strong><br />
comman<strong>de</strong>, il s utilise ainsi comme un interpréteur Shell. Cint supporte l ensemble <strong>de</strong>s librairies<br />
standard du langage C et permet aussi d importer <strong>de</strong>s librairies externes comme pour Un<strong>de</strong>rC.<br />
Cint contient un débuggeur intégré GDB Like pour les programmes à interpréter. De plus, Cint<br />
fonctionne sur plusieurs types d OS dont Windows et Linux, il a même pu l installer sur la<br />
<strong>de</strong>rnière version <strong>de</strong> Mandrake (v. 10.1) sans difficulté, avec un compilateur GCC <strong>de</strong> version 3.4.1.<br />
26
Chapitre 3<br />
Les interprètes C existants<br />
Sur la figure 11 ci-<strong>de</strong>ssous, on peut voir les résultats d exécution du fichier <strong>de</strong> test « testinterpC.c »<br />
donné dans la sous-section 3.2.<br />
Figure 11. Exemple d utilisation <strong>de</strong> Cint sous Linux<br />
Une trace d exécution <strong>de</strong> Cint avec l option <strong>de</strong> trace est donnée en annexe I.<br />
Nous allons exécuter maintenant Cint avec le programme LLisp [GRE 97], qui est un petit<br />
interprète du langage Lisp écrit en C entre les années 1990 et 1997 et comporte environs 1200<br />
lignes <strong>de</strong> co<strong>de</strong> source. On peut voir au préalable une démonstration <strong>de</strong> ce programme :<br />
lysop@ko> ./llisp<br />
Chargement <strong>de</strong> llisp.ini<br />
append<br />
length<br />
assq<br />
equal<br />
member<br />
? 5<br />
= 5<br />
? (car '(a b c))<br />
= a<br />
? (cdr '(a b c))<br />
= (b c)<br />
? bonjour<br />
Atome bonjour, valeur in<strong>de</strong>finie<br />
? (exit)<br />
Bye ...<br />
Exécutons maintenant ce programme via l interprète Cint, en y appelant les mêmes comman<strong>de</strong>s<br />
lisp que dans l exemple donné plus haut :<br />
lysop@ko> cint llisp/eval.c llisp/mem.c llisp/read.c llisp/print.c llisp/std.c<br />
llisp/main.c<br />
Limitation: setjmp() not supported<br />
Le fichier llisp.ini n'existe pas<br />
? 5<br />
= 5<br />
? (car '(a b c))<br />
Elt inconnu en position fonctionnelle 4<br />
Limitation: longjmp() not supported<br />
Liste non lambda en position fonctionnelle 4<br />
27
Limitation: longjmp() not supported<br />
Fonction standard inconnue car<br />
Limitation: longjmp() not supported<br />
car : Nb d'arguments incorrect<br />
Limitation: longjmp() not supported<br />
= (car (quote (a b c)))<br />
? bonjour<br />
Atome bonjour, valeur in<strong>de</strong>finie<br />
Limitation: longjmp() not supported<br />
= un<strong>de</strong>fined<br />
? (cdr '(a b c))<br />
Elt inconnu en position fonctionnelle 5<br />
Limitation: longjmp() not supported<br />
Liste non lambda en position fonctionnelle 5<br />
Limitation: longjmp() not supported<br />
Fonction standard inconnue cdr<br />
Limitation: longjmp() not supported<br />
cdr : Nb d'arguments incorrect<br />
Limitation: longjmp() not supported<br />
= (cdr (quote (a b c)))<br />
? (exit)<br />
Elt inconnu en position fonctionnelle 25<br />
Limitation: longjmp() not supported<br />
Liste non lambda en position fonctionnelle 25<br />
Limitation: longjmp() not supported<br />
Fonction standard inconnue exit<br />
Limitation: longjmp() not supported<br />
exit : Nb d'arguments incorrect<br />
Limitation: longjmp() not supported<br />
= (exit)<br />
?<br />
!!! Middle of loop compilation run. signal(2)<br />
!!! Break in the middle of compiled statement. signal(2)<br />
FILE:print.c LINE:24 cint> exit<br />
Bye... (try 'qqq' if still running)<br />
Message d échappement <strong>de</strong> Cint<br />
On remarque alors que Cint supporte l appel d un programme avec plusieurs fichiers sans avoir<br />
eu à modifier la syntaxe du programme source. Mais nous remarquons également que le<br />
programme ne supporte pas la fonction longjmp() appartenant au fichier d en-tête « setjmp.h »,<br />
ce qui cause une mauvaise exécution du programme LLisp. On peut voit sur la trace d exécution<br />
<strong>de</strong> LLisp ci-<strong>de</strong>ssus que la comman<strong>de</strong> exit, qui permet <strong>de</strong> quitter l interprète lisp, n est pas prise<br />
en compte par Cint étant donné que les initialisations du programme LLisp ne sont pas<br />
effectuées correctement, <strong>de</strong> sorte qu aucune fonction (car, cdr, exit, ..) n est reconnue.<br />
Cet interprète présente quelques avantages surtout dans sa nouvelle version dont plusieurs bugs<br />
ont été corrigés. Mais comme il a été dit en début <strong>de</strong> sa présentation, Cint ne traite que 95% du<br />
langage ANSI/ ISO C et cela s est <strong>de</strong> plus vérifié dans le <strong>de</strong>rnier exemple ; c est pourquoi je ne l ai<br />
pas testé plus en avant.<br />
3.3. JFL C<br />
Ce programme [LUC 05] propose une interface graphique pour saisir les instructions en pseudo<br />
langage C. Le concepteur du programme, Jean-François Lucas, a essentiellement orienté son<br />
projet pour l apprentissage <strong>de</strong> la programmation aux jeunes élèves avec <strong>de</strong> simples fonctions<br />
prédéfinies permettant <strong>de</strong> déplacer une tortue à l écran telles que : av(x) pour un déplacement<br />
<strong>de</strong> x pixels vers l avant, dt(x) pour un déplacement <strong>de</strong> x pixels vers la droite, td/tg(y) pour<br />
28
Chapitre 3<br />
Les interprètes C existants<br />
un déplacement <strong>de</strong> y <strong>de</strong>grés vers la droite/gauche. On peut également y charger <strong>de</strong>s programmes<br />
écrits en pseudo C. Cet interprète C comporte une interface graphique assez intéressante que<br />
l ont peut voir à la figure 12 : un champ <strong>de</strong> saisie à gauche avec en <strong>de</strong>ssous une fenêtre<br />
d affichage <strong>de</strong>s messages d erreurs et les comman<strong>de</strong>s exécutées et également une fenêtre pour la<br />
visualisation <strong>de</strong> l exécution <strong>de</strong>s comman<strong>de</strong>s à droite.<br />
Figure 12. Aperçu <strong>de</strong> l interface JFL C<br />
Figure 13. Exécution d un programme en pseudo langage C dans JFL C<br />
29
Sur la figure 13, on peut voir l exécution d un programme en pseudo C qui vérifie l égalité entre<br />
<strong>de</strong>ux entiers : en cliquant sur le bouton d éclair à l extrême droite <strong>de</strong> la barre d outil, le résultat <strong>de</strong><br />
l exécution du programme est affichée à l écran <strong>de</strong> droite. On peut voir dans cet exemple que JFL<br />
C utilise <strong>de</strong>s fonctions qui lui sont propre pour gérer l affichage à l écran <strong>de</strong> droite (ve() pour<br />
vi<strong>de</strong>r l ecran et ct() pour cacher la tortue) et <strong>de</strong>s termes i<strong>de</strong>ntiques au C tels que if pour le<br />
contrôle et printf() pour l affichage mais comme on peut l observer leur syntaxe diffère <strong>de</strong><br />
celle du langage C.<br />
JFL C propose un style <strong>de</strong> présentation intéressant pour le travail d analyse que l on veut faire<br />
avec la représentation graphique. On pourrait en effet, à terme, adopter cette stratégie en<br />
affichant à gauche le co<strong>de</strong> source interprété et à droite le graphique <strong>de</strong> dépendances généré par<br />
l interpréteur, avec une troisième fenêtre pour afficher le résultat d exécution.<br />
Malheureusement, cet outil n interprète que 140 instructions propres à l outil et non au langage C.,<br />
et ne gère pas les pointeurs dans sa version actuelle. De plus le co<strong>de</strong> source <strong>de</strong> l outil n est pas<br />
disponible, et la version testée est en pério<strong>de</strong> d essai. Ce programme est donc assez limité quant à<br />
ce qu on recherche comme interprète <strong>de</strong> langage C.<br />
3.4. EiC<br />
EiC, Extensive Interactive C, a été conçu par Edmon J. Breen en 1995 [BRE 00] et a connu <strong>de</strong>s<br />
améliorations jusqu en 2000. Cet outil est dédié entièrement à l interprétation du langage C. Il<br />
permet ainsi <strong>de</strong> saisir <strong>de</strong>s instructions C en ligne <strong>de</strong> comman<strong>de</strong>s comme les <strong>de</strong>ux premiers<br />
programmes précé<strong>de</strong>mment décrits (Un<strong>de</strong>rC et Cint). Il gère l ensemble <strong>de</strong>s librairies standard du<br />
langage C ainsi que les librairies OpenGL, SQL et permet avec <strong>de</strong>s comman<strong>de</strong>s internes <strong>de</strong><br />
générer <strong>de</strong>s graphes avec gplot. L intégration <strong>de</strong> ces librairies à EiC nécessite cependant la<br />
recompilation <strong>de</strong> celui-ci. Notre objectif actuel ne nécessite pas l utilisation <strong>de</strong> ces librairies et<br />
fonctionnalités, mais leur intégration à l outil nous ouvre <strong>de</strong>s possibilités à l avenir pour l analyse<br />
<strong>de</strong> programmes C faisant appel à d autres librairies que les librairies standard C.<br />
En plus <strong>de</strong> ces possibilités, l interprète EiC a la possibilité <strong>de</strong> s exécuter sur un grand nombre <strong>de</strong><br />
plateformes telles que Linux (elf), SUN SPARC SOLARIS 2.x, SUN SOLARIS/ i386 SUN OS<br />
4.1.x, DEC ALPHA OSF 3.x et 4.x, SGI IRIX 6.x, FreeBSD, W32 et d autres encore. La liste<br />
complète peut être consultable sur le site consacré à l outil [BRE 00].<br />
La documentation fournie avec le programme EiC est bien faite, non complète mais suffisante<br />
pour son utilisation (187 pages en format .pdf). Le co<strong>de</strong> source est disponible aussi bien pour<br />
Windows que pour Linux, ce qui nous intéresse plus étant donné que c est l environnement pour<br />
lequel il existe <strong>de</strong>s outils <strong>de</strong> développement dans le domaine public. Il existe également une<br />
documentation technique mais non achevée.<br />
La figure 14 donne un aperçu <strong>de</strong> l utilisation <strong>de</strong> l outil sous linux, spécialement comment l utiliser<br />
pour interpréter le programme « testinterpC.c » en mo<strong>de</strong> interactif et en mo<strong>de</strong> batch. En mo<strong>de</strong><br />
interactif les instructions sont interprétée une à une (cf. figure 14 déclaration <strong>de</strong> la variable x et<br />
son affectation avec la valeur 10) et le fichier « testinterpC.c » doit être chargé dans l interprète avec<br />
la directive #inclu<strong>de</strong>, puis il est exécuté en faisant appel à la fonction main() qui y est définie.<br />
En mo<strong>de</strong> batch, le fichier source est donné en argument à la comman<strong>de</strong> eic et l exécution du<br />
programme est immédiate.<br />
30
Chapitre 3<br />
Les interprètes C existants<br />
lysop@yak> ./eic<br />
*************************************************************************<br />
EiC V4.3.0 - Copyright (c) 1995 to 2000, by Edmond J. Breen<br />
EiC comes `as is' and with ABSOLUTELY NO WARRANTY OF MERCHANTIBILITY AND<br />
FITNESS OF PURPOSE<br />
*************************************************************************<br />
(void)<br />
EiC 1> int x;<br />
(void)<br />
EiC 2> x = 10;<br />
10<br />
EiC 3> #inclu<strong>de</strong> testinterpC.c<br />
(void)<br />
Mo<strong>de</strong> interactif<br />
EiC 4> main();<br />
valeur <strong>de</strong> x = 0<br />
valeur <strong>de</strong> y = 1<br />
valeur <strong>de</strong> z(x+y) = 1<br />
valeur <strong>de</strong> x = 3<br />
valeur <strong>de</strong> y = 4<br />
valeur <strong>de</strong> w(x-y) = -1<br />
valeur <strong>de</strong> v(z*w) = -1<br />
0<br />
EiC 5> :exit<br />
lysop@yak> ./eic testinterpC.c<br />
valeur <strong>de</strong> x = 0<br />
valeur <strong>de</strong> y = 1<br />
valeur <strong>de</strong> z(x+y) = 1<br />
valeur <strong>de</strong> x = 3<br />
Mo<strong>de</strong> batch<br />
valeur <strong>de</strong> y = 4<br />
valeur <strong>de</strong> w(x-y) = -1<br />
valeur <strong>de</strong> v(z*w) = -1<br />
lysop@yak><br />
Figure 14. Aperçu <strong>de</strong> l utilisation <strong>de</strong> EiC sous Linux<br />
Bien que cet outil semble complet en ce qui concerne sa prise en charge <strong>de</strong> l ensemble du langage<br />
C, un <strong>de</strong>rnier test va me permettre <strong>de</strong> vérifier ses possibilités à gérer tout type <strong>de</strong> programme C.<br />
Pour cela, je teste l interprète pour le programme LLisp, vu dans la section 3.2.<br />
lysop@yak> ./eic llisp/main.c<br />
Warning: in llisp/read.c near line 158: Unreachable co<strong>de</strong> at line 157<br />
Warning: in stdlib.h near line 31: 2nd prototype for builtin -> malloc<br />
Warning: in stdlib.h near line 39: 2nd prototype for builtin -> free<br />
Chargement <strong>de</strong> llisp/llisp.ini<br />
append<br />
length<br />
assq<br />
equal<br />
member<br />
? 5<br />
= 5<br />
? (car '(a b c))<br />
= a<br />
? (cdr '(a b c))<br />
= (b c)<br />
? bonjour<br />
Atome bonjour, valeur in<strong>de</strong>finie<br />
? (times 5 6)<br />
= 30<br />
? (add1 8)<br />
= 9<br />
? (plus 8 9)<br />
31
= 17<br />
? (exit)<br />
Bye ...<br />
lysop@yak><br />
Comme on peut le voir sur cette trace d exécution, les programme LLisp s exécute normalement<br />
et sans générer <strong>de</strong> messages d erreurs pendant son exécution. Cependant l exécution du<br />
programme source <strong>de</strong> LLisp a nécessité <strong>de</strong> mettre l ensemble du co<strong>de</strong> source au format standard<br />
mo<strong>de</strong>rne <strong>de</strong> C. En effet, étant donné que ce programme <strong>de</strong> test est assez ancien, il est<br />
entièrement écrit avec l ancienne syntaxe du langage C (exemple : nom_fonction(x, y) int<br />
x, float y ; {..}). Il a donc fallu mettre les définitions <strong>de</strong> fonctions au standard (void<br />
nom_fonction(int x, float y) {..}) et la fonction main() au format : int<br />
main(){..return 0 ;}. Il a fallu également redéfinir le prototype <strong>de</strong> certaines fonctions<br />
standard, telles que malloc() et free(). En effet, la fonction free() doit retourner un type<br />
void, alors que le programme LLisp déclarait cette fonction comme retournant un type char, ce<br />
qui explique les messages d alertes affichés lors <strong>de</strong> l appel au programme LLisp via EiC, mais ces<br />
alertes n empêchent pas EiC d exécuter le programme d interprète LLisp correctement. Il a<br />
également fallu inclure en début du fichier « main.c » chaque fichier auquel il fait appel sous la<br />
forme : #inclu<strong>de</strong> fichier.c .<br />
Bien que l interprète EiC nécessite une mise en forme <strong>de</strong>s anciens programmes C aux <strong>de</strong>rnières<br />
normes ANSI et ISO C, il rassemble <strong>de</strong>s caractéristiques assez proches <strong>de</strong> l interprète recherché<br />
puisqu il gère l ensemble <strong>de</strong>s spécificités du langage C : toutes les fonctions <strong>de</strong>s librairies standard,<br />
les pointeurs, les structures <strong>de</strong> contrôles, les fonctions récursives notamment.<br />
3.5. Ch<br />
L outil Ch est développé par SoftIntegration Corporation [SOF 05] <strong>de</strong>puis 2001 à nos jours. En effet<br />
cet outil est toujours en perpétuelles améliorations. Ch était à la base dédié à interpréter le langage<br />
C et <strong>de</strong>stiné aux programmeurs désirant apprendre le langage C. Il a évolué pour servir<br />
essentiellement au développeurs systèmes. Il permet dans sa version actuelle <strong>de</strong> prendre en<br />
charge aussi bien le langage C que le langage C++. Il a également son propre langage Ch, qui se<br />
positionne dans sa syntaxe entre le langage C et le C++. Ce langage possè<strong>de</strong> une syntaxe prenant<br />
en compte celle <strong>de</strong>s <strong>de</strong>ux langages C et C++, ce qui permet au développeur d écrire son co<strong>de</strong> en<br />
mélangeant les syntaxes et les fonctions <strong>de</strong>s <strong>de</strong>ux langages avec les fonctions propres au langage<br />
Ch. En effet, le langage Ch possè<strong>de</strong> <strong>de</strong>s fonctions supplémentaires qui permettent entre autres <strong>de</strong><br />
connaître le type d une chaîne <strong>de</strong> caractère (elementtype(var)) ou encore <strong>de</strong> connaître si une<br />
chaîne <strong>de</strong> caractère est un mot clé du langage (iskey(int)). On peut voir ci-<strong>de</strong>ssous un<br />
exemple <strong>de</strong> script Ch et le résultat <strong>de</strong> son exécution :<br />
Fichier : « compare.ch »<br />
#!/bin/ch -S<br />
#inclu<strong>de</strong><br />
int main() {<br />
char s[]="abcd";<br />
string_t p="abcd";<br />
printf("strcmp(s, p) = %d\n",strcmp(s, p));<br />
}<br />
Figure 15. Exemple d'utilisation d'un script Ch<br />
32
Chapitre 3<br />
Les interprètes C existants<br />
Comme on peut le voir sur la figure 15, la fonction strcmp() n est pas celle <strong>de</strong> la librairie<br />
standard C puisque le fichier hea<strong>de</strong>r «string.h » dans lequel elle est définie n a pas été inclus au<br />
programme «compare.ch ». De plus cette fonction compare <strong>de</strong>ux chaînes <strong>de</strong> caractères <strong>de</strong> types<br />
différents l une <strong>de</strong> type char * comme en C et l autre chaîne est <strong>de</strong> type string_t qui est un<br />
type propre au langage Ch. On peut aussi remarquer que le co<strong>de</strong> Ch est enregistré dans un fichier<br />
d extension .ch, qui contient en première ligne l appel à l interprète Ch sous la forme :<br />
# !/bin/ch S .<br />
L interprète Ch offre <strong>de</strong> plus la possibilité d utiliser <strong>de</strong>s comman<strong>de</strong>s Shell, awk et <strong>de</strong>s librairies<br />
graphiques telles que OpenGL. Il permet, comme Un<strong>de</strong>rC, Cint et EiC, <strong>de</strong> saisir <strong>de</strong>s instructions<br />
C en ligne <strong>de</strong> comman<strong>de</strong>s et d exécuter un fichier écrit en C <strong>de</strong> manière aisée. On peut voir cela à<br />
la figure 16.<br />
Figure 16. Aperçu <strong>de</strong> l exécution du programme testinterpC.c par Ch<br />
Ch est accompagné <strong>de</strong> trois documents (<strong>de</strong> type pdf <strong>de</strong> plus <strong>de</strong> 1000 pages en tout) et man, assez<br />
complets, permettant <strong>de</strong> mieux comprendre son langage et son fonctionnement.<br />
Ch existe en version standard gratuite, dédiée à la recherche et aux étudiants, et une version<br />
professionnelle payante. Nous avons testé la version standard <strong>de</strong> Ch dans l espoir <strong>de</strong> pouvoir<br />
obtenir le co<strong>de</strong> source par la suite, malheureusement sans succès. Les tests réalisés sont les<br />
mêmes que ceux appliqués à l outil EiC étant donnés que l outil gère toute la bibliothèque<br />
standard C, ainsi que les principaux éléments pouvant construire un quelconque programme<br />
source C, c'est-à-dire essentiellement : les pointeurs, les tableaux, l appel <strong>de</strong> fonctions, gestion <strong>de</strong>s<br />
boucles, la récursivité et encore les structures <strong>de</strong> contrôle.<br />
Ch permet aussi <strong>de</strong> gérer un co<strong>de</strong> source avec grand nombre <strong>de</strong> lignes <strong>de</strong> co<strong>de</strong>s. Il a été<br />
cependant incapable d exécuter le co<strong>de</strong> <strong>de</strong> l interprète Lisp constitué <strong>de</strong> plusieurs fichiers sources,<br />
ceci bien qu il supporte en théorie la possibilité d interpréter ce type <strong>de</strong> programmes sources. En<br />
effet, l exécution <strong>de</strong> programmes composés <strong>de</strong> plusieurs fichiers sources nécessite <strong>de</strong>s<br />
manipulations préalables sur ce <strong>de</strong>rnier. Le co<strong>de</strong> source n étant <strong>de</strong> toute manière pas accessible,<br />
les tests pour cet outil n ont pas été au <strong>de</strong>là.<br />
Le langage Ch permettrait aussi <strong>de</strong> créer <strong>de</strong>s programmes avec <strong>de</strong>s points <strong>de</strong> contrôle grâce aux<br />
fonctions Ch, mais cela nécessite une étu<strong>de</strong> plus approfondie <strong>de</strong> ses capacités, difficile à réaliser<br />
du fait du manque <strong>de</strong> documentation à ce sujet.<br />
33
3.6. Pourquoi EiC ?<br />
Après avoir exposé les spécificités <strong>de</strong> chaque interprète, le nombre d interprètes réellement<br />
utilisable pour le projet, s avère assez limité comparé à ce qu on espérait au départ, à savoir un<br />
interprète capable <strong>de</strong> prendre en charge le langage C avec toutes ses possibilités, et dont le co<strong>de</strong><br />
source soit dans le domaine public. En effet, tous les interprètes disponibles soit ne prennent pas<br />
en charge à 100% la bibliothèque standard C (cf. Un<strong>de</strong>rC, Cint et JFL C), soit prennent en charge<br />
l ensemble <strong>de</strong> la librairie mais nécessitent <strong>de</strong> modifier le co<strong>de</strong> source à analyser (cf. EiC pour la<br />
fonction main() par exemple). De plus la gestion <strong>de</strong>s programmes sources faisant appel à<br />
plusieurs fichiers n est pas assez bien gérée par les <strong>de</strong>ux <strong>de</strong>rniers interprètes EiC et Ch, bien qu ils<br />
gèrent <strong>de</strong> manière assez complète les spécificités du langage C. Cint parvient à exécuter ce type <strong>de</strong><br />
programmes d une manière assez proche <strong>de</strong> celle <strong>de</strong> gcc mais ne supporte pas la librairie standard<br />
« setjmp.h » <strong>de</strong> même que d autres librairies standard, du moins l ensemble <strong>de</strong>s fonctions qui y sont<br />
définies.<br />
Bien que Ch soit un très bon outil d interprétation du langage C, il n a pas son co<strong>de</strong> source<br />
accessible, ce qui rend impossible la possibilité <strong>de</strong> lui intégrer la fonctionnalité d analyse <strong>de</strong><br />
programmes. Cint malgré sa facilité d utilisation, ne supporte qu à 95% les spécificités du langage<br />
C (ANSI ET ISO C).<br />
C est pour ces raisons que mon choix s est orienté vers EiC qui a l avantage <strong>de</strong> prendre en charge<br />
l ensemble <strong>de</strong> la libraire standard C 6 et d avoir son co<strong>de</strong> source accessible. Il nécessitera <strong>de</strong><br />
manipuler le co<strong>de</strong> source au préalable (surtout pour les anciens co<strong>de</strong>s sources). Malgré le fait que<br />
EiC n ait plus été amélioré <strong>de</strong>puis 2000, il reste un interprète assez bien conçu et le plus complet<br />
<strong>de</strong> part son débuggeur intégré et d autres fonctionnalités comme la trace d un programme qui<br />
font défaut à l heure actuelle dans Ch et qui n est pas assez performante dans Cint.<br />
Dans le chapitre 4 qui suit, je détaille les spécificités <strong>de</strong> l interprète EiC, les possibilités qu il offre<br />
ainsi que les limites qu'il impose.<br />
6<br />
A l exception <strong>de</strong> la librairie <br />
34
Chapitre 3<br />
Les interprètes C existants<br />
35
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Chapitre 4 - Exploration <strong>de</strong> l interprète<br />
EiC<br />
Après avoir vu dans le chapitre précé<strong>de</strong>nt les aspects généraux <strong>de</strong> EiC, ses contraintes, ses<br />
avantages ainsi que les raisons pour lesquelles il s est imposé comme unique solution pour notre<br />
projet, ce chapitre décrit l interprète EiC <strong>de</strong> manière plus précise d un point <strong>de</strong> vue technique.<br />
Dans les paragraphes qui suivent, j expose en un premier temps les spécificités <strong>de</strong> l interprète<br />
EiC puis je décris l organisation <strong>de</strong> ses fichiers sources. En effet, une prise <strong>de</strong> connaissance du<br />
fonctionnement et <strong>de</strong> l organisation du programme EiC permet <strong>de</strong> mieux abor<strong>de</strong>r la modification<br />
<strong>de</strong> son co<strong>de</strong> source.<br />
4.1. Spécificités <strong>de</strong> EiC<br />
Cette section détaille l utilisation <strong>de</strong> EiC, présente ses limitations <strong>de</strong> syntaxe pour les co<strong>de</strong>s<br />
sources C ainsi que ses possibilités encourageantes pour la réalisation <strong>de</strong> notre objectif.<br />
4.1.1. Installation et compilation<br />
La version utilisée <strong>de</strong> EiC est la version source pour le système Unix. Elle peut être librement<br />
téléchargée sur le site officiel [BRE 00]. Le co<strong>de</strong> source a été installé sur une machine SunOS (5.9<br />
Generic, sun4u, sparc) du Laboratoire d Intelligence Artificielle <strong>de</strong> l Université <strong>Paris</strong> 8 7 .<br />
L installation du programme n est pas entièrement automatique ; elle nécessite la modification<br />
d un fichier <strong>de</strong> configuration <strong>de</strong> EiC puis <strong>de</strong> l exécution <strong>de</strong> quelques comman<strong>de</strong>s dont un make<br />
install pour l installation propre du programme sur la machine SunOS.<br />
Après installation du co<strong>de</strong> source <strong>de</strong> l interprète EiC, une variable d environnement propre à EiC<br />
HOMEofEiC doit être initialisée avec le chemin du répertoire <strong>de</strong> EiC, dans le fichier « .bashrc » ou<br />
directement dans un terminal Korn Shell. Cette variable permet à EiC <strong>de</strong> connaître le chemin<br />
vers les fichiers constituants la librairie standard du C.<br />
4.1.2. Les mo<strong>de</strong>s d exécution <strong>de</strong> l Interprète EiC<br />
4.1.2.1. Le mo<strong>de</strong> interactif<br />
EiC, comme son nom l indique est un interprète interactif. Ce mo<strong>de</strong> est lancé directement à partir<br />
du prompt Shell par la comman<strong>de</strong> suivante : $eic.<br />
Un prompt EiC s affiche alors invitant l utilisateur à saisir les instructions C :<br />
7<br />
Notons que c est uniquement sur cette plateforme que nous avons pu à ce jour compiler les sources <strong>de</strong> EiC.<br />
36
Chapitre 4<br />
Exploration <strong>de</strong> l interprète EiC<br />
lysop@yak> ./eic<br />
*************************************************************************<br />
EiC V4.3.0 - Copyright (c) 1995 to 2000, by Edmond J. Breen<br />
EiC comes `as is' and with ABSOLUTELY NO WARRANTY OF MERCHANTIBILITY AND<br />
FITNESS OF PURPOSE<br />
*************************************************************************<br />
(void)<br />
EiC 1> #inclu<strong>de</strong> stdio.h<br />
(void)<br />
EiC 2> printf("Hello world");<br />
Hello world 11<br />
EiC 3><br />
Comme on peut le voir sur cet exemple, on peut saisir <strong>de</strong>s instructions C tout comme on pourrait<br />
les saisir dans un fichier texte ou encore un éditeur <strong>de</strong> co<strong>de</strong> C. Observons <strong>de</strong> plus près la<br />
première instruction saisie dans cet exemple : on peut voir que le fichier « stdio.h » inclus n est pas<br />
entouré par les caractères < > comme on le fait normalement en C. Ceci montre qu il subsiste<br />
<strong>de</strong>s différences entre le C et le C <strong>de</strong> EiC entré interactivement. Ces différences vont être abordées<br />
dans la section 4.1.3. Quand EiC est exécuté en mo<strong>de</strong> interactif, il charge en mémoire certains<br />
fichiers hea<strong>de</strong>rs <strong>de</strong> la librairie standard du C, la liste <strong>de</strong> ces fichiers peut être visualisé et même<br />
paramétrée dans le fichier « starteic.h », qui est appelé lors <strong>de</strong> l appel au programme EiC. Le<br />
lancement <strong>de</strong> EiC en mo<strong>de</strong> interactif crée un fichier d historisation «EiChist.lst » qui permet <strong>de</strong><br />
stocker les comman<strong>de</strong>s exécutées <strong>de</strong>puis le début du programme EiC, ce fichier est utilisé pour<br />
faciliter la saisie <strong>de</strong>s comman<strong>de</strong>s dans ce mo<strong>de</strong>.<br />
Il existe également <strong>de</strong>s comman<strong>de</strong>s internes au mo<strong>de</strong> interactif <strong>de</strong> EiC, qui permettent entre autre<br />
<strong>de</strong> charger en mémoire un fichier <strong>de</strong> co<strong>de</strong> C, <strong>de</strong> visualiser le co<strong>de</strong> intermédiaire que traite le<br />
préprocesseur ou encore <strong>de</strong> donner le temps d exécution d un programme dans l interprète. Ces<br />
comman<strong>de</strong>s sont appelées par le caractère «: » suivi du nom <strong>de</strong> la comman<strong>de</strong>, puis suivant la<br />
comman<strong>de</strong> un ou plusieurs arguments. Par exemple la comman<strong>de</strong> :exit permet <strong>de</strong> quitter le<br />
mo<strong>de</strong> interactif <strong>de</strong> EiC, ou encore :<br />
EiC 3> void fonction (int x){ int y; y = x+6; printf("y = %d\ n",y); }<br />
(void)<br />
EiC 4> :show fonction (4);<br />
fonction -> Func (<br />
x: int<br />
) returning void<br />
4<br />
La comman<strong>de</strong> :show, comme on peut le voir ci-<strong>de</strong>ssus, permet <strong>de</strong> montrer la structure <strong>de</strong> la<br />
fonction définie en ligne 3 avec le type <strong>de</strong>s paramètres passés en arguments, ici l argument x est<br />
<strong>de</strong> type int, et la fonction retourne un type void. La valeur 4 retournée en <strong>de</strong>rnier correspond<br />
à la valeur <strong>de</strong> l argument x.<br />
L ensemble <strong>de</strong>s ces fonctions sont listées avec leur <strong>de</strong>scription en annexe II.<br />
Exemple d exécution <strong>de</strong><br />
la comman<strong>de</strong> <strong>de</strong> trace<br />
EiC 8> :trace<br />
EiC 9> fonction (4);<br />
9,<br />
[fonction] 3,y = 10<br />
[::EiC::] 9,<br />
(void)<br />
EiC 10> :listco<strong>de</strong><br />
0:halt<br />
(void)<br />
EiC 11> fonction (4);<br />
0:pushptr b2868<br />
1:bump 1<br />
2:checkar 1 1<br />
3:pushint 4<br />
4:stoval<br />
5:pushint 1<br />
6:eiccall<br />
Visualisation du co<strong>de</strong><br />
intermédiaire généré par<br />
EiC pour la fonction :<br />
fonction(4)<br />
37
Chapitre 4<br />
Exploration <strong>de</strong> l interprète EiC<br />
7:halt<br />
y = 10<br />
Pour l exemple donné pour la comman<strong>de</strong> <strong>de</strong> trace, le nombre 9 correspond à la ligne EiC à partir<br />
<strong>de</strong> laquelle est exécutée l instruction tracée, puis le nom <strong>de</strong> la fonction est affiché entouré <strong>de</strong> [ ]<br />
avec le numéro <strong>de</strong> ligne EiC où elle a été définie. Comme la fonction est définie sur une seule<br />
ligne, seul ce numéro apparaît, suivi du résultat <strong>de</strong> l appel à printf() avec la valeur <strong>de</strong> y qui<br />
comme on peut le remarquer égale à la somme <strong>de</strong> 4 (valeur <strong>de</strong> x) et <strong>de</strong> 6. Après exécution <strong>de</strong><br />
cette fonction d après la trace obtenue, EiC revient à la ligne 9 où fonction(4) à été appelée.<br />
Le mo<strong>de</strong> interactif permet également d exécuter une instruction qui tient sur plusieurs lignes. Ceci<br />
s effectue <strong>de</strong> <strong>de</strong>ux manières, la première étant <strong>de</strong> placer un antislash («\ ») à la fin <strong>de</strong> chaque<br />
instruction sauf à la <strong>de</strong>rnière comme on peut le voir sur l exemple suivant :<br />
EiC 1> double sqr(double x)\<br />
EiC 2> {\<br />
EiC 3> return x*x;\<br />
EiC 4> }<br />
(void)<br />
EiC 5> sqr(2);<br />
4<br />
La <strong>de</strong>uxième manière est d utiliser le préprocesseur <strong>de</strong> EiC pour inclure la suite d instructions.<br />
Pour cela, les instructions sont saisies dans un fichier qui sera alors inclus grâce à la directive<br />
#inclu<strong>de</strong> du préprocesseur. Pour reprendre l exemple présenté précé<strong>de</strong>mment, on crée le<br />
fichier « sqr.c » (ci-<strong>de</strong>ssous à droite), puis on le charge dans EiC comme suit :<br />
EiC 6> #inclu<strong>de</strong> sqr.c<br />
(void)<br />
EiC 7> sqr(2);<br />
4<br />
/* Fichier sqr.c<br />
*/<br />
#inclu<strong>de</strong> <br />
double sqr (double x)<br />
{<br />
return x*x;<br />
}<br />
Après avoir aperçu les particularités du mo<strong>de</strong> interactif <strong>de</strong> l interprète EiC, je vais détailler les<br />
autres possibilités offertes par le mo<strong>de</strong> non interactif <strong>de</strong> EiC.<br />
4.1.2.2. Le mo<strong>de</strong> batch<br />
Comme il a été dit précé<strong>de</strong>mment, EiC peut s exécuter en mo<strong>de</strong> batch, c est-à-dire à la manière<br />
d une comman<strong>de</strong> Shell dans un environnement Linux, ce mo<strong>de</strong> n étant d ailleurs possible qu en<br />
environnements Unix ou Linux. Cette option d EiC permet aussi d interpréter <strong>de</strong>s fichiers <strong>de</strong><br />
co<strong>de</strong> source C sans avoir à les charger au préalable, comme c est le cas en mo<strong>de</strong> interactif. Pour<br />
exécuter le co<strong>de</strong> C contenu dans le fichier « var.c » listé ci-<strong>de</strong>ssous, il suffit <strong>de</strong> saisir au niveau du<br />
prompt Shell la comman<strong>de</strong> suivante : $> eic var.c.<br />
1 /*<br />
2 var.c<br />
3 fichier simple qui affecte une variable<br />
4 */<br />
5 #inclu<strong>de</strong> <br />
6 int main()<br />
7 {<br />
8 int x;<br />
9 x = 12;<br />
10 printf("x = %d\n", x);<br />
11 return 0;<br />
12 }<br />
Résultat d exécution :<br />
lysop@yak> ./eic var.c<br />
x = 12<br />
38
Chapitre 4<br />
Exploration <strong>de</strong> l interprète EiC<br />
Le fichier est alors exécuté sans pour autant générer un fichier binaire, comme le ferait un<br />
compilateur. Notons que le programme « var.c » n est exécuté par l appel à EiC en mo<strong>de</strong> batch<br />
que s il contient la définition d une fonction main(). En effet, la fonction main est considérée<br />
par EiC comme le point <strong>de</strong> départ du programme. Cette remarque s applique aussi au mo<strong>de</strong><br />
interactif <strong>de</strong> EiC, qui ne permet pas d exécuter un fichier source C sans que ce <strong>de</strong>rnier possè<strong>de</strong> la<br />
définition d une fonction main(). Les prototypes possibles pour définir la fonction main()<br />
sont décrits dans la sous-section 4.1.3.<br />
Avec l appel <strong>de</strong> EiC en mo<strong>de</strong> batch, le fichier <strong>de</strong> co<strong>de</strong> source qu on lui donne en argument est<br />
considéré avec tous les fichiers hea<strong>de</strong>rs qu il inclut comme une seule unité à traduire et à<br />
interpréter. De plus, il n y a aucun fichier d historisation (« EiChist.lst ») créé, contrairement à<br />
l utilisation du mo<strong>de</strong> interactif.<br />
Il existe <strong>de</strong>s particularités d exécution qui sont communs aux mo<strong>de</strong>s batch et interactif : le mo<strong>de</strong><br />
batch possè<strong>de</strong> la possibilité <strong>de</strong> spécifier <strong>de</strong>s options d exécution, certaines ont même les mêmes<br />
fonctionnalités que celles du mo<strong>de</strong> interactif. Seul le mo<strong>de</strong> d activation <strong>de</strong> ces options change<br />
d un mo<strong>de</strong> à l autre. On a vu dans la section précé<strong>de</strong>nte que les options sont toujours précédées<br />
par le caractère «: ». Pour le mo<strong>de</strong> batch, les options sont toujours précédées du caractère «- », à<br />
la suite <strong>de</strong> ce caractère on peut cumuler les options les unes après les autres, tout comme les<br />
comman<strong>de</strong>s Shell en environnement Unix/ Linux. La liste complète <strong>de</strong> ces options est donnée en<br />
annexe II. Quelques options sont cependant présentées ci-<strong>de</strong>ssous avec la trace <strong>de</strong> leur exécution.<br />
Mais avant cela, voici le format général <strong>de</strong> la comman<strong>de</strong> eic peut être utilisée en mo<strong>de</strong> batch :<br />
eic [-Directives pour le préprocesseur C] [-Options pour EiC] [ [fichier] [arguments] ]<br />
Ci-<strong>de</strong>ssous quelques exemples d utilisation <strong>de</strong>s options p, t et c qui permettent respectivement<br />
d afficher le co<strong>de</strong> interprété avant <strong>de</strong> l exécuter, <strong>de</strong> tracer les instructions effectivement exécutées<br />
et enfin <strong>de</strong> mesurer le temps d exécution <strong>de</strong>s instructions :<br />
1. ./eic -ptc var.c<br />
2. int _Argc = 1;char *_Argv[] = {"var.c",(void*)0};<br />
3. : 0<br />
4. int main()<br />
5. {<br />
6. int x;<br />
7. x = 12;<br />
8. return x;<br />
9. }<br />
10. : 0<br />
11. main();<br />
12. 5,<br />
13. [main] 9,10,<br />
14. [::EiC::]<br />
15. : 0<br />
Dans cet exemple, on exécute le fichier « var.c » (cf. ci-<strong>de</strong>ssous). La ligne 1 correspond à l appel <strong>de</strong><br />
la comman<strong>de</strong> eic avec les trois options ptc, décrites plus haut. La ligne suivante montre la<br />
première ligne interprétée par EiC (comme on a activé l option p pour l affichage <strong>de</strong>s instructions<br />
interprétées), qui correspond à l affectation <strong>de</strong>s variables internes à EiC :_Argc et _Argv. Leurs<br />
valeurs nous indiquent que le programme EiC prend le fichier « var.c » en argument et c est donc<br />
cet unique fichier qui sera à traiter, ce qu on peut effectivement voir aux lignes 4 à 9 (option p).<br />
39
Chapitre 4<br />
Exploration <strong>de</strong> l interprète EiC<br />
L interprète lit les lignes du fichier « var.c » ligne par ligne à partir <strong>de</strong> la définition <strong>de</strong> la fonction<br />
main(), puis exécute celle-ci comme une seule instruction. Les lignes 12 à 14 correspon<strong>de</strong>nt à<br />
l exécution <strong>de</strong> la trace du programme var.c. On peut remarquer que l option <strong>de</strong> trace en mo<strong>de</strong><br />
batch <strong>de</strong> EiC donne le même type d affichage qu en mo<strong>de</strong> interactif (cf. page 32). La mesure du<br />
temps d exécution <strong>de</strong> chaque instruction est affichée aux lignes 3, 10 et 15, le temps étant mesuré<br />
en secon<strong>de</strong>s (option c).<br />
L interprète EiC présente donc <strong>de</strong>s particularités et <strong>de</strong>s possibilités assez intéressantes pour notre<br />
projet, essentiellement l option <strong>de</strong> trace et d affichage d instructions interprétées pendant leur<br />
exécution. EiC nous permet non seulement d exécuter un fichier <strong>de</strong> co<strong>de</strong> C en mo<strong>de</strong> batch, mais<br />
offre aussi la possibilité d être intégré dans un fichier <strong>de</strong> script. Ce fichier <strong>de</strong> script <strong>de</strong>vra<br />
commencer par la ligne #!/chemin/vers/eic pour un fichier contenant un programme C et<br />
par #!/chemin/vers/eic f pour un fichier <strong>de</strong> script EiC 8 [BRE 03]. Les fichiers <strong>de</strong><br />
scripts EiC auront pour extension .eic, peuvent contenir <strong>de</strong>s fonctions EiC et peuvent être<br />
exécutés simplement au prompt Shell par l appel suivant : $./fichier.eic. Nous ne<br />
détaillerons pas plus ce mo<strong>de</strong> d exécution car il présente globalement les mêmes spécificités que<br />
le mo<strong>de</strong> batch.<br />
4.1.3. Les différences entre EiC et C<br />
Du fait <strong>de</strong> son interactivité EiC diffère du C <strong>de</strong> plusieurs manières. Ces différences mettent en<br />
avant surtout les quelques lacunes <strong>de</strong> EiC à interpréter tout programme écrit en langage C suivant<br />
la norme ISO, mais cela ne met pas en doute les qualités <strong>de</strong> EiC en tant qu interprète C complet<br />
et fiable pour interpréter et exécuter la plupart <strong>de</strong>s programmes C (cf. section 3.4).<br />
EiC détecte plusieurs classes mémoire en violation <strong>de</strong> lecture ou d écriture [BRE 03].<br />
Les structures et unions ne peuvent pas être passées en argument dans une fonction à<br />
arguments variables. Ex :<br />
EiC 2> struct stag {int x; double y[5];} ss;<br />
(void)<br />
EiC 3> void foo(const char *fmt, ...);<br />
(void)<br />
EiC 4> foo("",ss);<br />
Error in ::EiC:: near line 4: passing a struct/union to variadic function `foo'<br />
Le concept d édition <strong>de</strong> liens en C n est pas supporté par EiC, ceci du fait que EiC<br />
fonctionne suivant le concept d une seule unité <strong>de</strong> traduction : tous les fichiers appelés par<br />
un programme doivent y être incluses au fichier « main.c ».<br />
EiC ne supporte pas les séquences trigraphes 9 , ni les caractères étendus (<strong>de</strong> type<br />
wchar_t définit dans < std<strong>de</strong>f.h> pour définir <strong>de</strong>s caractères asiatiques par exemple), ni<br />
les chaînes <strong>de</strong> caractères étendues.<br />
Le fichier hea<strong>de</strong>r standard n est pas géré.<br />
8 EiC possè<strong>de</strong> <strong>de</strong>s fonctions internes non existantes dans les librairies standard du C, qui permettent notamment<br />
<strong>de</strong> connaître le type <strong>de</strong>s variables manipulées par exemple.<br />
9<br />
EiC dispose d un jeu <strong>de</strong> caractères restreint, correspondant à la norme ISO646. La norme ANSI permet que<br />
certains <strong>de</strong>s 9 <strong>de</strong>rniers caractères (# [ \ ] ^ { | } ~) soient remplacés par <strong>de</strong>s séquences trigraphes. Une séquence<br />
trigraphe est une suite <strong>de</strong> 3 caractères commençant par ?? [DEL 03].<br />
40
Chapitre 4<br />
Exploration <strong>de</strong> l interprète EiC<br />
Toute fonction dans EiC doit être explicitement définie avec son type <strong>de</strong> retour, quelque<br />
soit le type :<br />
EiC 3> foo(){ int x; x=2; return x; };<br />
Error in ::EiC:: near line 3: Un<strong>de</strong>clared i<strong>de</strong>ntifier foo<br />
Error in ::EiC:: near line 3: Expected ;<br />
Error in ::EiC:: near line 3: Misplaced return statement<br />
Error in ::EiC:: near line 3: Expected ;<br />
EiC 5> int foo(){ int x; x=2; return x; };<br />
(void)<br />
L ancienne syntaxe <strong>de</strong> déclarations et <strong>de</strong> définitions <strong>de</strong> fonctions C n est pas supportée<br />
par EiC, telle que :<br />
int f(value) int value { } /* illégal -> vieux style <strong>de</strong> syntaxe C */<br />
Le préprocesseur <strong>de</strong> EiC ne gère pas la directive #line.<br />
EiC a donné à la directive #inclu<strong>de</strong> plus <strong>de</strong> possibilités comme l inclusion d un fichier<br />
source sans " " ou < >.<br />
Les différences entre EiC et l ISO C sont essentiellement dues au fait que EiC est un interprète<br />
du langage C. Ainsi, EiC est capable <strong>de</strong> supporter l ensemble <strong>de</strong>s spécificités du langage C, mis à<br />
part <strong>de</strong>ux ou trois fonctionnalités et syntaxes non encore supportées [BRE 03]. Ces lacunes ne<br />
sont cependant pas un handicap, elles vont seulement nous contraindre à mettre en forme le co<strong>de</strong><br />
C avant <strong>de</strong> l interpréter avec EiC.<br />
4.2. Structure <strong>de</strong> fichiers<br />
Nous présentons dans cette section l arborescence <strong>de</strong>s principaux fichiers sources constituant<br />
EiC, <strong>de</strong> manière à montrer le rôle que jouent certains fichiers dans la procédure d interprétation<br />
et d exécution du co<strong>de</strong> C. Dans la figure 17 ci-<strong>de</strong>ssous, on peut voir l arborescence <strong>de</strong>s dossiers<br />
avec le détail du contenu <strong>de</strong>s principaux répertoires. Seuls les principaux dossiers et fichiers<br />
impliqués dans le processus d interprétation <strong>de</strong> co<strong>de</strong> sont décrit dans ce qui suit.<br />
Le dossier bin/ contient le fichier binaire « eic » (surligné en jaune sur la figure 17) généré quand<br />
on compile le co<strong>de</strong> source <strong>de</strong> EiC ($make install dans le dossier eic_test/ ).<br />
Les sources <strong>de</strong> l interprète sont situées sous le dossier racine eic_test/ , nous avons<br />
volontairement omis <strong>de</strong> mettre le contenu <strong>de</strong> quelques répertoires ( config/ , doc/ , lib/ ,<br />
module/ et test/ ) qui ne jouent pas <strong>de</strong> rôle dans la procédure d interprétation <strong>de</strong> co<strong>de</strong>.<br />
Les principaux dossiers détaillés dans cette section sont les dossiers inclu<strong>de</strong>/ , main/ et src/ .<br />
Le dossier config/ contient les informations <strong>de</strong> configuration relatives à chaque environnement<br />
sur lequel fonctionne EiC. Le dossier doc/ , comme son nom l indique, contient un ensemble <strong>de</strong><br />
documentations techniques sur EiC. Les dossiers lib/ , module/ et tests/ contiennent<br />
respectivement <strong>de</strong>s fichiers binaires spécifiques à EiC, <strong>de</strong>s modules tels que gnuplot et le<br />
traitement <strong>de</strong>s cgi par EiC et <strong>de</strong>s exemples <strong>de</strong> programmes test pour l interprète.<br />
41
Chapitre 4<br />
Exploration <strong>de</strong> l interprète EiC<br />
Figure 17. Arborescence <strong>de</strong>s fichiers sources <strong>de</strong> EiC<br />
Comme il a été dit dans le chapitre 3, EiC est capable <strong>de</strong> traiter la librairie standard C dans sa<br />
totalité, mis à part le fichier < locale.h>. Dans le dossier inclu<strong>de</strong>/ , on trouve tous les fichiers<br />
hea<strong>de</strong>rs traités par EiC. On remarque alors qu il existe en plus <strong>de</strong>s hea<strong>de</strong>rs standard (surlignés en<br />
vert), <strong>de</strong>s hea<strong>de</strong>rs correspondants à la librairie POSIX.1 tels que , < fcntl.h>, <br />
(surlignés en bleu). Les fichiers restants (non surlignés) correspon<strong>de</strong>nt aux fichiers d entête<br />
spécifiques à EiC et qu on retrouve également dans le dossier src/ . Ce dossier src/ contient les<br />
fichiers sources <strong>de</strong> l interprète, et représente ainsi le noyau <strong>de</strong> EiC. Remarquons que le fichier<br />
« starteic.c » contient les principales fonctions lançant le mécanisme d interprétation, il effectue les<br />
traitements du préprocesseur «à la volée » et vérifie la syntaxe <strong>de</strong>s instructions avant <strong>de</strong> les<br />
représenter dans un format interne (byte co<strong>de</strong>) détaillé dans le chapitre 5.<br />
L analyse va aussi créer une table <strong>de</strong> symboles (symbol table) qui contiendra <strong>de</strong>s informations sur<br />
les chaînes <strong>de</strong> caractères (variables, nom <strong>de</strong> fonctions, nom <strong>de</strong> structures, par exemple)<br />
concernant leur position dans l instruction, leur type, ou encore leur niveau d appel dans le co<strong>de</strong>.<br />
La définition <strong>de</strong>s structures <strong>de</strong> table <strong>de</strong> symboles se trouve dans les fichiers « datastruct.h » et<br />
« eicval.h ». Les fonctions manipulant les éléments <strong>de</strong> la table <strong>de</strong>s symboles se trouvent dans le<br />
fichier « symbol.c ».<br />
42
Chapitre 4<br />
Exploration <strong>de</strong> l interprète EiC<br />
Le fichier « preproc.c » contient les fonctions nécessaires pour le prétraitement du co<strong>de</strong>. EiC utilise<br />
une grammaire LL(1) 10 , avec un mécanisme d analyse <strong>de</strong>scendante [GRU 00], qui a une assez<br />
bonne capacité <strong>de</strong> récupération d erreur. Le travail <strong>de</strong> l interprète est définit dans le fichier<br />
« interpre.c », qui contient une unique fonction appelée EiC_interpret(environ_t * env). Nous<br />
verrons dans le chapitre suivant l importance du rôle joué par ce fichier pour la réalisation <strong>de</strong><br />
notre travail d analyse <strong>dynamique</strong> <strong>de</strong> co<strong>de</strong>, notamment pour modifier l option <strong>de</strong> trace <strong>de</strong> EiC.<br />
Lors <strong>de</strong> l exécution<strong>de</strong> EiC, le premier fichier appelé est « main.c » 11 , qui comme son nom l indique<br />
contient la fonction main() du programme et permet essentiellement à charger les librairies «<br />
libstdClib.a » qui contient la librairie standard C et « libeic.a » qui contient les fonctions propres à<br />
EiC, crée un lien entre elles, puis fait appel aux fonctions <strong>de</strong> « starteic.c ». Ce <strong>de</strong>rnier fichier lance<br />
l anlyse <strong>de</strong>s instructions C ainsi que leur interprétation. C est dans le fichier «interpre.c » que se<br />
trouve la bourcle d exéctution <strong>de</strong>s instructions (en byte co<strong>de</strong>) et c est également dans ce fichier que<br />
l option <strong>de</strong> trace est définie, c est donc ce fichier que nous avons modifié essentiellement pour<br />
réaliser notre travail d analyse <strong>dynamique</strong>.<br />
L étu<strong>de</strong> <strong>de</strong>s différents aspects <strong>de</strong> EiC et l organisation <strong>de</strong> sa structure <strong>de</strong> fichier nous ont permit<br />
<strong>de</strong> prendre en considération toutes les possibilités <strong>de</strong> EiC qui peuvent nous servir dans la<br />
réalisation <strong>de</strong> notre travail d analyse <strong>dynamique</strong>, les possibilités qu offre le mo<strong>de</strong> batch <strong>de</strong> EiC<br />
tout particulièrement et l option <strong>de</strong> trace <strong>de</strong> l interprète. Cette présentation nous a également<br />
permis <strong>de</strong> connaître les points à améliorer dans EiC dans les travaux futurs, comme la prise en<br />
compte <strong>de</strong> fonctions sans types <strong>de</strong> retour, la prise en compte <strong>de</strong> la librairie standard .<br />
10<br />
La <strong>de</strong>scription <strong>de</strong> cette grammaire peut être trouvée dans la documentation technique <strong>de</strong> EiC se trouvant dans<br />
son source (cf. eic_test\doc\tech_doc\LL1).<br />
11<br />
Le fichier « main.c » se trouve dans le dossier nommé /main (cf. figure 17)<br />
43
Chapitre 5 - Description technique du travail réalisé<br />
Chapitre 5 - Description technique du<br />
travail réalisé<br />
Avant d abor<strong>de</strong>r ce chapitre rappelons par un petit exemple ce que l on entend par<br />
dépendances <strong>dynamique</strong>s <strong>de</strong> données, prenons pour cela le fichier <strong>de</strong> co<strong>de</strong> C nommé « exemple.c ».<br />
Le travail décrit dans ce chapitre permet <strong>de</strong> générer un graphe <strong>de</strong> dépendance entre les données<br />
tel qu on peut le voir ci-<strong>de</strong>ssous.<br />
1 /*<br />
2 exemple.c<br />
3 */<br />
4 int main()<br />
5 {<br />
6 int x,y,a;<br />
7 x = 12;<br />
8 y = 8;<br />
9 a = x + y;<br />
10 return 0;<br />
11 }<br />
7<br />
x=12<br />
9<br />
a=20<br />
8<br />
y=8<br />
Ce chapitre présente les techniques utilisées pour l extraction <strong>de</strong>s informations <strong>de</strong> co<strong>de</strong>s sources<br />
C pendant leur exécution dans EiC. Nous y expliquons dans un premier temps <strong>de</strong> quelle manière<br />
l extraction <strong>de</strong>s données est réalisée à l ai<strong>de</strong> <strong>de</strong> l interprète EiC, ce qu il a fallu y modifier et le<br />
format <strong>de</strong>s données extraites. Puis dans un second temps, nous expliquons comment est exploité<br />
le fichier <strong>de</strong> base <strong>de</strong> données extrait pour générer la représentation graphique <strong>de</strong>s dépendances<br />
entre les données et comment interpréter le graphique généré.<br />
5.1. Extraction <strong>dynamique</strong> <strong>de</strong>s données<br />
L interprète EiC, comme nous avons pu le voir dans le chapitre précé<strong>de</strong>nt, possè<strong>de</strong> <strong>de</strong>ux mo<strong>de</strong>s<br />
d exécutions. Nous avons également vu que le mo<strong>de</strong> batch nous permet d intégrer l appel à EiC<br />
dans un fichier <strong>de</strong> scripts Shell. C est pour ces raisons que nous avons choisi <strong>de</strong> travailler sous le<br />
mo<strong>de</strong> batch, d autant plus qu il offre la possibilité <strong>de</strong> tracer un programme. Cette <strong>de</strong>rnière<br />
possibilité <strong>de</strong> l interprète nous a semblé intéressante à exploiter et à étendre sa fonctionnalité afin<br />
qu elle génère <strong>de</strong>s informations sur les données manipulées par le programme C. Mais avant<br />
d abor<strong>de</strong>r l aspect technique du travail réalisé, nous précisons que tout notre travail s est<br />
concentré à traiter les cas <strong>de</strong> manipulation <strong>de</strong> données <strong>de</strong> types entières. Le traitement <strong>de</strong>s autres<br />
types sera effectué par la suite <strong>de</strong> la même manière en y appliquant <strong>de</strong> simples réajustements<br />
suivant le type traité (cf. chapitre 8).<br />
La section 5.1.2 détaille comment l option <strong>de</strong> trace est modifiée dans EiC, et les <strong>de</strong>ux soussections<br />
suivantes, 5.1.3 et 5.1.4, expliquent le format d extraction <strong>de</strong>s données. Mais avant <strong>de</strong><br />
voir cela, commençons par voir les étapes suivies pour extraire <strong>de</strong>s informations à partir d un<br />
fichier <strong>de</strong> co<strong>de</strong> source simple.<br />
44
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
5.1.1. Description <strong>de</strong> la procédure d extraction<br />
La figure 18 présente le schéma général <strong>de</strong> la procédure d extraction pour un programme C, ici<br />
« test.c » comme exemple. Pour analyser ce <strong>de</strong>rnier, on l interprète d abord par EiC avec l option<br />
<strong>de</strong> trace modifiée : $./eic t chemin/vers/test.c.<br />
L exécution <strong>de</strong> cette comman<strong>de</strong> génère l affichage <strong>de</strong>s données extraites en sortie standard. Afin<br />
<strong>de</strong> pouvoir exploiter ces informations, le résultat <strong>de</strong> la comman<strong>de</strong> est donc redirigé vers un<br />
fichier qui se nomme « test.data », ce <strong>de</strong>rnier forme alors la base <strong>de</strong> donnée.<br />
Cette base <strong>de</strong> données est utilisée ensuite par un script awk qui va mettre les données sous un<br />
format pouvant être exploité par l outil d affichage <strong>de</strong> graphes Dot [GAN 02]. Les données ainsi<br />
mises en forme seront enregistrées dans un nouveau fichier d extension .dot. Ce fichier contient<br />
donc l ensemble <strong>de</strong>s informations extraites du co<strong>de</strong> source avec les liens les reliant les unes aux<br />
autres pendant l exécution du programme source.<br />
Le fichier « test.dot » est ensuite transformé par le programme Dot en fichier d extension .ps<br />
(« test.ps »), ce qui nous permet <strong>de</strong> le visualiser avec l application GhostView ou encore le<br />
transformer en format PDF, plus facilement exploitable.<br />
Co<strong>de</strong><br />
Source C<br />
« test.c »<br />
Interprétation<br />
par EiC<br />
modifié<br />
$eic t test.c<br />
Base <strong>de</strong><br />
données<br />
« test.data »<br />
Exploitation<br />
par un script<br />
awk<br />
« graph.awk »<br />
Fichier mis en<br />
forme pour<br />
Dot<br />
« test.dot »<br />
GhostView<br />
Fichier<br />
PostScript<br />
« test.ps »<br />
Dot<br />
Figure 18. Schéma d'extraction <strong>dynamique</strong> <strong>de</strong> données<br />
L ensemble <strong>de</strong> ces étapes pour la génération du graphique <strong>de</strong> dépendances <strong>de</strong>s données, est<br />
effectué par un script Shell nommé « eic_adpc.sh » (<strong>Analyse</strong> Dynamique <strong>de</strong> Programmes C basée<br />
sur EiC). L appel à ce script nécessite <strong>de</strong> passer en argument le nom du fichier <strong>de</strong> co<strong>de</strong> source à<br />
analyser. Si un fichier <strong>de</strong> co<strong>de</strong> est passé en argument, il est alors analysé afin <strong>de</strong> vérifier son<br />
extension (.c) et dans le cas où celle-ci est correcte, une <strong>de</strong>rnière vérification est effectuée pour<br />
voir si le fichier existe bien et s il est en droit <strong>de</strong> lecture. Si une <strong>de</strong> ces conditions n est pas vérifiée,<br />
un message d erreur est affiché pour en avertir l utilisateur. Ce script est donné en annexe V.<br />
45
Chapitre 5 - Description technique du travail réalisé<br />
Pour que le script Shell fonctionne correctement, le fichier <strong>de</strong> co<strong>de</strong> source doit être placé dans un<br />
dossier qu on a crée spécialement pour les co<strong>de</strong>s sources à analyser. On verra dans le paragraphe<br />
qui suit les autres dossiers ajoutés à EiC, ainsi que les fichiers modifiés.<br />
5.1.2. Modifications apportées à EiC<br />
Comme nous avons vu au chapitre précé<strong>de</strong>nt, le programme binaire qui permet d exécuter EiC se<br />
trouve dans le dossier dossier_install_eic/bin et a pour nom eic. C est également dans ce<br />
dossier que se trouvent les scripts Shell et awk, ainsi que les dossiers que manipule « eic_adpc.sh »,<br />
listés ci-<strong>de</strong>ssous :<br />
- co<strong>de</strong>s_test/ : contient les programmes C utilisés pour les tests et ceux à analyser.<br />
- data/ : contient les fichiers <strong>de</strong> base <strong>de</strong> données générés par EiC.<br />
- dot/ : contient les fichiers d extension .dot généré par le script awk.<br />
- graphs/ : contient les fichiers PostScript pour la visualisation du graphe <strong>de</strong> dépendance.<br />
Grâce au script Shell, chaque fichier généré au cours <strong>de</strong> son exécution est placé dans le dossier<br />
correspondant.<br />
Mis à part ces ajouts dans le dossier bin/ <strong>de</strong> EiC, d autres modifications ont été effectuées à<br />
certains fichiers du dossier eic_test/src/ , qui contient les fichiers sources <strong>de</strong> l interprète.<br />
Comme nous l avons précisé précé<strong>de</strong>mment, l option la plus proche <strong>de</strong> ce que l on veut faire est<br />
l option <strong>de</strong> trace d un programme, qui permet <strong>de</strong> retourner le numéro <strong>de</strong> ligne <strong>de</strong>s instructions<br />
exécutées avec éventuellement leur résultat d exécution. L exemple qui suit, montre le résultat<br />
retourné par cette option <strong>de</strong> trace avant sa modification :<br />
lysop@yak> cat -b co<strong>de</strong>s_test/var.c<br />
1 /*<br />
2 var.c<br />
3 fichier simple qui affecte une variable<br />
4 */<br />
5 #inclu<strong>de</strong> <br />
6 int main()<br />
7 {<br />
8 int x;<br />
9 x = 12;<br />
10 printf("x = %d\ n", x);<br />
11 return 0;<br />
12 }<br />
lysop@yak> ./eic -t co<strong>de</strong>s_test/var.c<br />
18,24,26,28,<br />
5,<br />
[main] 9,10,x = 12<br />
11,<br />
[::EiC::]<br />
lysop@yak><br />
Figure 19. Exemple d'exécution <strong>de</strong> l'option trace avant modification<br />
Comme on peut voir, la première série <strong>de</strong> numéros correspond aux instructions appelées par le<br />
fichier « stdio.h » inclus. Le 5 correspond au début du fichier source « var.c » c'est-à-dire à l appel<br />
<strong>de</strong> l inclu<strong>de</strong>, puis on entre dans l appel <strong>de</strong> la fonction main(), puis les instructions <strong>de</strong>s lignes 9<br />
46
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
et 10 sont exécutées. L instruction 10 étant la fonction printf() qui affiche la valeur <strong>de</strong> la<br />
variable x, son résultat est affiché après son numéro <strong>de</strong> ligne. L instruction <strong>de</strong> la 11 ème ligne du<br />
co<strong>de</strong> source est exécutée, elle correspond à la fonction return 0, puis on retourne dans<br />
l environnement EiC ([::EiC::]) qui n a plus d instructions à exécuter d où la fin <strong>de</strong> son<br />
exécution.<br />
L option <strong>de</strong> trace originale à l interprète EiC ne nous fournit pas assez d informations quant à<br />
l exécution du programme, mis à part le numéro <strong>de</strong>s instructions exécutées. Nous allons alors<br />
explorer le co<strong>de</strong> source <strong>de</strong> EiC afin <strong>de</strong> savoir à quel endroit il y gère la fonction <strong>de</strong> trace, puis <strong>de</strong><br />
trouver comment la modifier afin qu elle nous renvoie les informations sur les dépendances entre<br />
données.<br />
Comme nous l avons vu dans le chapitre précé<strong>de</strong>nt, le co<strong>de</strong> source <strong>de</strong> EiC est contenu dans le<br />
dossier chemin_vers_EiC/src/ , le premier fichier appelé par le programme quand il est<br />
exécuté etant « main.c ». Ce fichier fait appel à la fonction EiC_startEiC() définie dans le<br />
fichier « starteic.c », qui fait appel à une autre fonction runEiC() pour initialiser l interprète EiC.<br />
Elle effectue ensuite les analyses lexicale et syntaxique avant d exécuter la fonction<br />
d interprétation EiC_interpret() qui, comme son nom l indique, effectue l interprétation <strong>de</strong>s<br />
instructions. Cette <strong>de</strong>rnière fonction est définie dans le fichier « interpre.c », qui contient également<br />
l option <strong>de</strong> trace d un programme vue en figure 19.<br />
En effet, en suivant l enchaînement <strong>de</strong>s appels entre fichiers sources EiC, nous trouvons que<br />
l option <strong>de</strong> trace consiste en une exécution d instructions dans EiC_interpret() si la variable<br />
EiC_traceON a pour valeur 1. Ainsi, lorsqu on fait appel à la comman<strong>de</strong> eic t fichier.c,<br />
la variable EiC_traceON est initialisée à 1 et la suite d instructions définies ci-<strong>de</strong>ssous est<br />
exécutée :<br />
if(EiC_traceON) {<br />
if(InSt[p].opco<strong>de</strong> == eiccall) {<br />
EiC_eicpush(&names,v);<br />
v.p.p = ((symentry_t *) STK[ToP - 1].v.p.p)->id;<br />
EiC_formatMessage("\n[%s] ",(char*)v.p.p);<br />
}<br />
if(!EiC_traceFunc && lastln != InSt[p].line && InSt[p].line) {<br />
lastln = InSt[p].line;<br />
EiC_formatMessage("%d,",lastln);<br />
}<br />
}<br />
Dans cet extrait <strong>de</strong> co<strong>de</strong> source, les résultats <strong>de</strong> trace obtenus sous EiC sont effectués avec les<br />
<strong>de</strong>ux instructions : EiC_formatMessage("\n[%s] ",(char*)v.p.p), pour le nom <strong>de</strong> la<br />
fonction exécutée et EiC_formatMessage("%d,",lastln) pour le numéro <strong>de</strong> la ligne<br />
d instruction exécutée (variable lastln). Nous nous sommes donc servis <strong>de</strong> ces fonctions pour<br />
y insérer nos propres informations, et nous avons aussi modifié leur format affichage en un<br />
format spécifique à notre base <strong>de</strong> données (cf. section 5.14). Les informations que nous avons<br />
ajoutées sont générées par la boucle d évaluation <strong>de</strong>s instructions, qui est également effectuée à<br />
l intérieur <strong>de</strong> la fonction EiC_interpret(). Cette boucle a pour rôle essentiel d exécuter le<br />
co<strong>de</strong>, qui à ce sta<strong>de</strong> se présente sous la forme <strong>de</strong> co<strong>de</strong> intermédiaire : opco<strong>de</strong> [operan<strong>de</strong>], où<br />
l opcope est un symbole désignant un type d instructions et operan<strong>de</strong> désigne l éventuel<br />
argument <strong>de</strong> l instruction. C est donc ce co<strong>de</strong> intermédiaire que nous exploitons pour obtenir <strong>de</strong>s<br />
informations telles que l affectation d une variable ou son utilisation par une instruction.<br />
Pour comprendre ce qu effectue la boucle d évaluation d instructions <strong>de</strong> la fonction<br />
EiC_interpret(), il faut savoir au préalable que EiC décompose une ligne d instruction C en<br />
plusieurs instructions <strong>de</strong> co<strong>de</strong> intermédiaire. Nous pouvons voir dans l exemple qui suit,<br />
47
Chapitre 5 - Description technique du travail réalisé<br />
l utilisation <strong>de</strong> l option listco<strong>de</strong> <strong>de</strong> EiC qui permet <strong>de</strong> visualiser en mo<strong>de</strong> interactif le co<strong>de</strong><br />
intermédiaire généré pour toute instruction exécutée, nous avons également schématisé le rôle <strong>de</strong><br />
certains opco<strong>de</strong>s (pushint, stoint et rval) et <strong>de</strong> leurs opéran<strong>de</strong>s :<br />
EiC 4> x=5;<br />
0:pushint 5<br />
1:stoint 0 0<br />
2:halt<br />
5<br />
Operan<strong>de</strong>s<br />
EiC 5> y=2;<br />
0:pushint 2<br />
1:stoint 1 0<br />
2:halt<br />
2<br />
EiC 6> x;<br />
0:rvalint 0 0<br />
1: halt<br />
5<br />
Opco<strong>de</strong><br />
pushint<br />
pushint<br />
Pile<br />
globale<br />
5<br />
stoint<br />
stoint<br />
2<br />
5<br />
Pile<br />
globale<br />
rvalint<br />
5<br />
0 1 2 3<br />
0 5 2<br />
1<br />
3<br />
Tableau AR<br />
Les instructions EiC 4 et 5 effectuent <strong>de</strong>s affectations <strong>de</strong> variables. Nous pouvons voir que<br />
l affectation <strong>de</strong> variables entières est traduite par une suite <strong>de</strong> trois instructions <strong>de</strong> co<strong>de</strong><br />
intermédiaire : pushint, stoint et halt. De la même manière l appel d une variable dans la<br />
ligne d instruction 6 est traduit par <strong>de</strong>ux instructions <strong>de</strong> co<strong>de</strong> intermédiaire : rvalint et halt.<br />
Chaque instruction <strong>de</strong> co<strong>de</strong> intermédiaire est représentée dans EiC par la structure <strong>de</strong> données<br />
suivante :<br />
Type<strong>de</strong>f struct {<br />
Unsigned opco<strong>de</strong>;<br />
val_t val ;<br />
int ext ;<br />
unsigned short line ;<br />
} InsT_t;<br />
Cette structure permet donc d enregistrer pour chaque instruction le numéro <strong>de</strong> ligne (line), le<br />
numéro d enregistrement <strong>de</strong> l objet 12 qu elle manipule le cas échéant (val), le niveau d appel <strong>de</strong><br />
l objet 13 (ext) et le co<strong>de</strong> opérateur (opco<strong>de</strong>) qui la compose. Ainsi, <strong>de</strong>ux co<strong>de</strong>s opérateurs (ou<br />
opco<strong>de</strong>s) peuvent appartenir à une même ligne d instruction C. EiC utilise également un<br />
compteur interne d instructions (p) pour pouvoir les distinguer entre elles.<br />
Nous pouvons voir ci-<strong>de</strong>ssous un échantillon <strong>de</strong> co<strong>de</strong> source, extrait <strong>de</strong> la fonction<br />
EiC_interpret(), constituant la boucle d évaluation <strong>de</strong>s instructions en pseudo co<strong>de</strong> :<br />
switch (InSt[p].opco<strong>de</strong>) {<br />
case stoint: stoTYPE(ival); break;<br />
case rvalint: rvalTYPE(ival); break;<br />
}<br />
12 Variable entière, chaîne <strong>de</strong> caractères, pointeurs, etc, stockés dans la table <strong>de</strong>s symboles.<br />
13 Global = niveau 0, local à main = 1, et ainsi <strong>de</strong> suite suivant la profon<strong>de</strong>ur <strong>de</strong>s appels.<br />
48
Chapitre 5 - Description technique du travail réalisé<br />
L instruction switch évalue l expression InSt[p].opco<strong>de</strong>, qui correspond au co<strong>de</strong> opérateur<br />
<strong>de</strong> l instruction <strong>de</strong> numéro d enregistrement p. Si le co<strong>de</strong> opérateur est stoint alors la fonction<br />
stoTYPE(ival) est exécutée, et ainsi <strong>de</strong> suite pour tous les co<strong>de</strong>s opérateurs définis. Ces co<strong>de</strong>s<br />
opérateurs, ci-<strong>de</strong>ssus, nous permettent <strong>de</strong> détecter lorsqu une variable entière est définie<br />
(stoint), et pour détecter lorsqu une variable entière est utilisée (rvalint). L objectif <strong>de</strong> notre<br />
outil étant d extraire les informations sur la définition et l utilisation <strong>de</strong>s variables 14 , nous <strong>de</strong>vons<br />
principalement modifier la trace dans pour qu elle intègre ces informations. Par exemple pour le<br />
programme <strong>de</strong> la figure 19, nous voulons obtenir une trace <strong>de</strong> la forme :<br />
5,<br />
[main]<br />
9-<br />
Def x 12 9<br />
10-<br />
Use x 9 10<br />
x = 12<br />
11-<br />
return 0<br />
[::EiC::]<br />
Ce format nous permet ainsi <strong>de</strong> capturer l usage <strong>de</strong>s variables effectué par chaque instruction <strong>de</strong><br />
notre exemple :<br />
- en ligne 9 on définit la variable x avec la valeur 12 (Def x 12 9)<br />
- en ligne 10 on utilise la variable x définie en ligne 9 (Use x 9 10), le résultat <strong>de</strong><br />
l instruction est affiché ensuite<br />
- en ligne 11 on utilise la fonction return avec pour valeur <strong>de</strong> retour 0<br />
Pour obtenir le format <strong>de</strong> base <strong>de</strong> données avec les lignes Use et Def, nous avons modifié le co<strong>de</strong><br />
exécutépour le co<strong>de</strong> opérateur stoint pour afficher une ligne <strong>de</strong> type Def. Par contre si c est<br />
rvalint, alors nous affichons dans une ligne <strong>de</strong> type Use. Nous pouvons voir dans l extrait <strong>de</strong><br />
co<strong>de</strong> source suivant comment cela a été introduit dans la boucle d évaluation d instructions :<br />
switch (InSt[p].opco<strong>de</strong>) {<br />
case stoint:<br />
stoTYPE(ival);<br />
printf("\tDef %d-%d %d %d \n",<br />
InSt[p].ext,<br />
InSt[p].val.ival,<br />
AR[InSt[p].ext][InSt[p].val.ival].v.ival,<br />
InSt[p].line);<br />
break;<br />
case rvalint:<br />
rvalTYPE(ival);<br />
printf("\tUse %d-%d %d %d \n",<br />
InSt[p].ext,<br />
InSt[p].val.ival,<br />
lastcalline,<br />
InSt[p].line);<br />
break;<br />
}<br />
Une ligne <strong>de</strong> format Def contient trois informations : l i<strong>de</strong>ntifiant <strong>de</strong> la variable, la valeur <strong>de</strong> la<br />
variable et le numéro <strong>de</strong> ligne <strong>de</strong> l instruction C effectuant cette affectation. Une ligne <strong>de</strong> format<br />
Use contient également trois informations : l i<strong>de</strong>ntifiant <strong>de</strong> la variable, le numéro <strong>de</strong> ligne <strong>de</strong><br />
l instruction C et enfin la <strong>de</strong>rnière ligne où la variable à été modifiée. La <strong>de</strong>rnière ligne où la<br />
14<br />
Pour simplifier l exposé, nous nous concentrons ici sur l usage <strong>de</strong>s variables, le cas <strong>de</strong>s appels <strong>de</strong> fonctions est<br />
détaillé en section 5.14.<br />
49
Chapitre 5 - Description technique du travail réalisé<br />
variable a été modifiée est obtenue grâce à la variable lastcalline, (surlignée en rose ci-<strong>de</strong>ssus)<br />
obtenue grâce à <strong>de</strong>s modifications <strong>de</strong> la structure <strong>de</strong> la pile d exécution et à une nouvelle structure<br />
d instructions que nous avons ajouté à EiC. Le détail <strong>de</strong> ces modifications est présenté en<br />
sections 5.1.2.2 et 5.1.3.<br />
L i<strong>de</strong>ntifiant <strong>de</strong> la variable, comme on peut voir sur le co<strong>de</strong> source ci-<strong>de</strong>ssus, est une combinaison<br />
<strong>de</strong> <strong>de</strong>ux entiers : InSt[p].ext et InSt[p].val.ival (surlignés en bleu ci-<strong>de</strong>ssus). Nous<br />
donnons en section 5.1.2.1 un exemple permettant <strong>de</strong> mieux voir comment EiC i<strong>de</strong>ntifie les<br />
variables d un programme grâce à ces <strong>de</strong>ux valeurs.<br />
La valeur <strong>de</strong> la variable est accessible via la pile d exécution AR (runtime stack) définie dans<br />
« eicval.h » (cf. annexe VII) grâce aux i<strong>de</strong>ntifiants <strong>de</strong> la variable présentés en haut (cf surlignée en<br />
jaune ci-<strong>de</strong>ssus).<br />
5.1.2.1. I<strong>de</strong>ntification <strong>de</strong>s variables dans EiC<br />
Pour comprendre le mécanisme d enregistrement <strong>de</strong>s variables d un programme C par EiC, nous<br />
nous regardons la base <strong>de</strong> donnée générée pour le programme « ext_affvar.c » donné en section<br />
1.3 et redonné ci-<strong>de</strong>ssous en plus version plus courte :<br />
7 int m;<br />
8<br />
9 int main()<br />
10 {<br />
11 int x,y;<br />
12<br />
13 x = 12;<br />
14 y = 8;<br />
15 m = 15;<br />
...<br />
20 }<br />
::EiC:: : 5 -> [main]<br />
13.- <br />
Def 1-0 12 13<br />
14.- <br />
Def 1-1 8 14<br />
15.- <br />
Def 0-2 15 15<br />
Dans le co<strong>de</strong> source m est définie en global, alors que x et y sont en local. Dans la base <strong>de</strong><br />
données générée par EiC, on peut voir qu en ligne 13 la variable x, qui prend la valeur 12, est<br />
i<strong>de</strong>ntifiée par 1-0. De même, aux lignes 14 et 15, y et m sont représentés par les i<strong>de</strong>ntifiants 1-1<br />
et 0-2. En effet, EiC i<strong>de</strong>ntifie les variables par un couple « portée-numéro d ordre »: la portée <strong>de</strong><br />
niveau 0 correspond au niveau global, la portée 1 aux variables locales à une fonction <strong>de</strong><br />
contrôles et ainsi <strong>de</strong> suite pour les variables déclarées dans <strong>de</strong>s blocs imbriqués, le numéro<br />
d ordre est le numéro d enregistrement <strong>de</strong> la variable et commence par 0 pour la première<br />
variable enregistrée. Ainsi, x est i<strong>de</strong>ntifié par 1-0, puisqu il s agit <strong>de</strong> la 1 ère variable déclarée en<br />
local à la fonction main(), y est i<strong>de</strong>ntifié par 1-1, étant donné qu elle est la 2 ème variable<br />
déclarée en local à main(), tandis que 0-2 i<strong>de</strong>ntifie m qui est la 3 ème variable définie en global<br />
(les <strong>de</strong>ux premières positions sont réservées à <strong>de</strong>s variables internes à EiC).<br />
5.1.2.2. Enregistrement <strong>de</strong> la <strong>de</strong>rnière ligne utilisant une<br />
variable<br />
Nous avons vu précé<strong>de</strong>mment qu en cas <strong>de</strong> lecture <strong>de</strong> variable par une instruction nous<br />
enregistrons une ligne <strong>de</strong> format Use dans la base <strong>de</strong> données, et que ce format doit contenir le<br />
numéro <strong>de</strong> la <strong>de</strong>rnière ligne d instruction C où cette variable a été modifiée. Pour cela nous avons<br />
représenté ce numéro <strong>de</strong> ligne par la variable lastcalline. Nous voyons dans cette section<br />
comment nous obtenons cette information ; pour cela nous reprenons le co<strong>de</strong> <strong>de</strong> la section<br />
50
Chapitre 5 - Description technique du travail réalisé<br />
précé<strong>de</strong>nte et modifions la variable m pour qu elle reçoive la somme <strong>de</strong>s valeurs <strong>de</strong>s variables x et<br />
y :<br />
7 int m;<br />
8<br />
9 int main()<br />
10 {<br />
11 int x,y;<br />
12<br />
13 x = 12;<br />
14 y = 8;<br />
15 m = x+y;<br />
...<br />
20 }<br />
::EiC:: : 5 -> [main]<br />
13.- <br />
Def 1-0 12 13<br />
14.- <br />
Def 1-1 8 14<br />
15.- <br />
Use 1-0 13 15<br />
Use 1-1 14 15<br />
Def 0-2 15 15<br />
Pour représenter la lecture <strong>de</strong>s variables x et y dans la base <strong>de</strong> données nous <strong>de</strong>vons faire<br />
référence au numéro <strong>de</strong> ligne où elles ont été affectées c'est-à-dire respectivement les lignes 13 et<br />
14. Pour enregistrer ces <strong>de</strong>ux valeurs, nous modifions la structure <strong>de</strong> la pile d exécution AR par<br />
laquelle nous accédons aux valeurs <strong>de</strong>s variables, en lui ajoutant un champ supplémentaire line.,<br />
ci-<strong>de</strong>ssous la structure <strong>de</strong> la pile d exécution ainsi modifiée :<br />
type<strong>de</strong>f struct AR_t {<br />
val_t v;<br />
type_expr * type;<br />
unsigned short line;<br />
}AR_t;<br />
Ce champ line nous permet ainsi à chaque modification <strong>de</strong> la valeur d une variable d enregistrer<br />
le numéro <strong>de</strong> ligne où cela est effectué. Dans stoint et rvalint, nous avons ajouté une<br />
ligne <strong>de</strong> co<strong>de</strong> après chaque Def afin d affecter à la variable son nouveau numéro <strong>de</strong> ligne comme<br />
on peut le voir ci-<strong>de</strong>ssous :<br />
case stoint:<br />
stoTYPE(ival);<br />
printf("\tDef %d-%d %d %d \n",<br />
InSt[p].ext,<br />
InSt[p].val.ival,<br />
AR[InSt[p].ext][InSt[p].val.ival].v.ival,<br />
InSt[p].line);<br />
AR[InSt[p].ext][InSt[p].val.ival].line = InSt[p].line;<br />
break;<br />
5.1.3. Numérotation et compteur d appel <strong>de</strong>s instructions<br />
Nous abordons dans cette section la numérotation <strong>de</strong>s instructions. En effet, ce point bien<br />
qu abstrait à ce niveau et pouvant paraître sans gran<strong>de</strong> importance à première vue est la clé dans<br />
notre représentation <strong>de</strong>s dépendances entre données.<br />
Nous avons vu, dans l exemple donné en section 5.1.2, que lorsqu une variable est utilisée nous<br />
avons besoin <strong>de</strong> savoir le numéro <strong>de</strong> la ligne d instruction où elle a été définie auparavant. Notre<br />
numérotation <strong>de</strong>s lignes doit non seulement permettre <strong>de</strong> faire <strong>de</strong>s liens entre les données du<br />
programme, mais aussi permettre d i<strong>de</strong>ntifier <strong>de</strong> manière unique chaque passage sur une même<br />
instruction(cf. l exemple donné ci-<strong>de</strong>ssous). Ainsi, lorsqu on passe plusieurs fois sur une même<br />
instruction (cas <strong>de</strong> fonctions récursives et boucles), nous <strong>de</strong>vons générer autant d i<strong>de</strong>ntifiants<br />
d instructions que <strong>de</strong> passages.<br />
51
Chapitre 5 - Description technique du travail réalisé<br />
Pour en comprendre l importance, nous présentons dans ce qui suit un exemple <strong>de</strong> cas dans<br />
lequel le simple enregistrement <strong>de</strong> la <strong>de</strong>rnière ligne où une variable est modifiée (vu en section<br />
5.1.2.2) est problématique :<br />
1 int main()<br />
2 {<br />
3 int x;<br />
4 x = 0;<br />
5 while(x
Chapitre 5 - Description technique du travail réalisé<br />
Nous avons par la suite créé un tableau <strong>de</strong> cette structure, l in<strong>de</strong>x du tableau étant le numéro <strong>de</strong><br />
ligne d instruction C appelée pendant l exécution du programme. Ce tableau est initialisé avant<br />
l analyse du co<strong>de</strong> intermédiaire <strong>de</strong> cette manière :<br />
for (i=0; i
Chapitre 5 - Description technique du travail réalisé<br />
Et ainsi <strong>de</strong> suite pour les <strong>de</strong>ux <strong>de</strong>rniers appels <strong>de</strong> boucle. En regardant les colorations <strong>de</strong>s cases<br />
du tableau 1, on remarque que les instruction <strong>de</strong> type Use font appel aux valeurs du tableau T<br />
pour les valeurs <strong>de</strong>rnier_appel et <strong>de</strong>rnier_pass pour le numéro d instruction où la<br />
variable 1-0 à été modifiée qu on peut alors obtenir via la variable AR[1][0].line.<br />
Nous modifions la boucle d évaluation d instructions comme suit pour les co<strong>de</strong>s opérateurs<br />
stoint et rvalint :<br />
case stoint: stoTYPE(ival);<br />
AR[InSt[p].ext][InSt[p].val.ival].line = InSt[p].line;<br />
printf("\tDef %d-%d %d %d %d\n",<br />
InSt[p].ext,<br />
InSt[p].val.ival,<br />
AR[InSt[p].ext][InSt[p].val.ival].v.ival,<br />
InSt[p].line,<br />
T[InSt[p].line].cptr_a);<br />
T[InSt[p].line].<strong>de</strong>rnier_appel= InSt[p].line;<br />
T[InSt[p].line].<strong>de</strong>rnier_pass= T[lastln].cptr_a;<br />
break;<br />
case rvalint: rvalTYPE(ival);<br />
printf("\tUse %d-%d %d %d %d %d \n",<br />
InSt[p].ext,<br />
InSt[p].val.ival,<br />
T[AR[InSt[p].ext][InSt[p].val.ival].line].<strong>de</strong>rnier_appel,<br />
T[AR[InSt[p].ext][InSt[p].val.ival].line].<strong>de</strong>rnier_pass,<br />
InSt[p].line,<br />
T[InSt[p].line].cptr_a);<br />
break;<br />
5.1.4. Extensions pour les boucles et l appel <strong>de</strong> fonctions<br />
Dans cette section nous présentons les autres formats <strong>de</strong> la base <strong>de</strong> données pour les types non<br />
encore cités tels que les évaluations <strong>de</strong> conditions, les appels <strong>de</strong> fonctions (telles que printf())<br />
ou encore les fonctions main() et return() traitées différemment par EiC.<br />
Pour capturer les appels <strong>de</strong> boucles et les structures <strong>de</strong> contrôles if, nous avons intégré à la<br />
boucle d évaluation d instructions au niveau du co<strong>de</strong> opérateur ltint l affichage d une<br />
instruction Cond pour mettre en évi<strong>de</strong>nce dans notre base <strong>de</strong> données l évaluation d une<br />
condition 15 dans le cas d un if ou <strong>de</strong> boucles while et for. Ainsi une ligne <strong>de</strong> format Cond 16<br />
dans la base <strong>de</strong> données contient trois types d informations : la condition évaluée, la valeur <strong>de</strong> son<br />
évaluation (0 ou 1) et les i<strong>de</strong>ntifiants <strong>de</strong> la ligne d instruction.<br />
Pour afficher l appel d une fonction, nous avons modifié le co<strong>de</strong> opérateur call pour qu il<br />
génère une ligne <strong>de</strong> format Call 17 dans la base <strong>de</strong> donnée, ce format contient alors <strong>de</strong>ux types<br />
d informations au plus : les i<strong>de</strong>ntifiants <strong>de</strong> l instruction et la valeur <strong>de</strong> retour <strong>de</strong> la fonction le cas<br />
échéant.<br />
Pour afficher la fonction main(), nous lui avons réservé une ligne <strong>de</strong> format main 18 dans la<br />
base <strong>de</strong> donnée, ainsi ce format <strong>de</strong> ligne renseigne les i<strong>de</strong>ntifiants <strong>de</strong> lignes ou la fonction main()<br />
est appelée dans le fichier source C.<br />
15<br />
Seul l opérateur « < » est traité par EiC à ce sta<strong>de</strong> du projet.<br />
16 Exemple : Cond (1
Chapitre 5 - Description technique du travail réalisé<br />
Pour afficher la fonction return() nous avons modifié le co<strong>de</strong> opérateur return pour qu il<br />
génère une ligne <strong>de</strong> format Return 19 contenant <strong>de</strong>ux informations : les i<strong>de</strong>ntifiants <strong>de</strong><br />
l instruction qui l appelle et sa valeur <strong>de</strong> retour.<br />
5.2. Affichage du graphique <strong>de</strong> dépendances entre<br />
données<br />
Nous voyons maintenant <strong>de</strong> quelle manière on exploite les informations <strong>de</strong> la base <strong>de</strong> donnée<br />
générée pour obtenir une représentation graphique. Pour cela, nous commençons par présenter<br />
l outil Dot <strong>de</strong> génération <strong>de</strong> graphes utilisé dans notre projet, puis nous décrivons le script<br />
awk utilisé pour formater les informations <strong>de</strong> la base <strong>de</strong> données en un format utilisable par<br />
Dot.<br />
5.2.1. L outil dot<br />
Cet outil [GAN 02] permet <strong>de</strong> générer <strong>de</strong>s graphes contenant un grand nombre <strong>de</strong> n uds et<br />
d arcs qui néanmoins reste clairs et aérés. Il offre <strong>de</strong> plus <strong>de</strong> larges possibilités pour la<br />
représentation graphique : différentes figures pour les noeuds, différents types d extrémités d arcs,<br />
couleur, styles <strong>de</strong> polices pour les labels <strong>de</strong> n uds et d arcs, par exemple. Il permet également <strong>de</strong><br />
générer les graphes dans <strong>de</strong>s formats réutilisables comme entre autre le format PostScript. Nous<br />
pouvons voir dans les figures ci <strong>de</strong>ssous <strong>de</strong>s exemples <strong>de</strong> graphes pouvant être générés avec cet<br />
outil [BEL 05 ; GAN 02].<br />
Figure 20. Exemples <strong>de</strong> graphes obtenus avec l outil Dot, avec un exemple <strong>de</strong> graphe en bas avec son co<strong>de</strong><br />
source<br />
19 Exemple : Return 0 10 1.<br />
55
Chapitre 5 - Description technique du travail réalisé<br />
Ainsi comme on peut le voir à la figure 20, créer un graphe <strong>de</strong> dépendance avec l outil Dot<br />
nécessite d écrire au préalable les relations entre les n uds que l ont veut afficher dans un format<br />
propre à l outil (n ud 1 -> noeud2). On qu on doit ainsi créer un fichier (en format .dot)<br />
contenant toutes les définitions <strong>de</strong>s n uds et <strong>de</strong>s liens entre ces n uds, puis l exécuter avec la<br />
comman<strong>de</strong> dot suivante : dot -Tps -o fichier.ps fichier.dot<br />
C est donc dans ce format Dot que nous allons formater notre base <strong>de</strong> données.<br />
5.2.2. Formatage <strong>de</strong> la base <strong>de</strong> données au format dot<br />
Dans cette section, nous présentons comment la base <strong>de</strong> donnée générée grâce à la version<br />
modifiée <strong>de</strong> EiC est exploitée pour avoir une représentation graphique claire <strong>de</strong> nos dépendances<br />
entre les données. Pour cela, nous avons utilisé les possibilités <strong>de</strong> l outil Dot pour représenter<br />
chaque type d information <strong>de</strong> la base <strong>de</strong> données sous forme d un n ud ou d un lien dans le<br />
graphe. Ainsi, chaque fonction (Call, main, Return) est représentée par un rectangle, rouge<br />
pour la fontion main() et noir pour les autres, les définitions <strong>de</strong> variables (Def) sont<br />
représentées par un n ud vert en forme d ellipse, l utilisation d une variable est représentée par<br />
un line allant <strong>de</strong> la l igne d origine <strong>de</strong> sa valeur vers la ligne où elle est appellée. Les lignes<br />
d instructions sont alors représentées par leur i<strong>de</strong>ntifiant <strong>de</strong> ligne unique (numéro <strong>de</strong><br />
ligne:numero d appel) et alignées verticalement à gauche du graphe <strong>de</strong> dépendance, tel un<br />
axe <strong>de</strong> mesure, par ordre d appel dans le programme. Nous pouvons visualiser cette<br />
représentation graphique sur la figure 21, qui définit une variable x (i<strong>de</strong>ntifiée par 1-0) puis<br />
retourne sa valeur avec la fonction return.<br />
var2.c<br />
1 int main()<br />
2 {<br />
3 int x;<br />
4 x = 12;<br />
5 return x;<br />
6 }<br />
Figure 21. Graphe <strong>de</strong> dépendances <strong>dynamique</strong>s <strong>de</strong> données pour "var2.c"<br />
Nous pouvons voir sur cette représentation graphique, que les n uds du graphe son positionnés<br />
au même niveau que les i<strong>de</strong>ntifiants <strong>de</strong> leurs ligne d appel sur l échelle d appel <strong>de</strong>s instructions (à<br />
gauche du graphe), sauf pour la fonction main qui est i<strong>de</strong>ntifiée par son nom et son compteur<br />
d appel. Ainsi, l échelle <strong>de</strong> gauche indique que le fichier analysé commence par la fonction main<br />
et que la <strong>de</strong>rnière ligne <strong>de</strong> co<strong>de</strong> exécutée est la ligne 5:1 (end). Le graphe <strong>de</strong> dépendances à droite<br />
<strong>de</strong> cette échelle nous indique que la fonction main (rectangle rouge) définit une variable en ligne<br />
4:1 (ellipse verte), dont la valeur est renvoyée (fonction return) par l instruction <strong>de</strong> la ligne 5:1.<br />
Les conditions <strong>de</strong>s structures <strong>de</strong> controle telles que if et while, sont représentées par un noed<br />
dans le graphe <strong>de</strong> dépendances en forme <strong>de</strong> losange, définit <strong>de</strong> sorte que si la condition est vraie,<br />
56
Chapitre 5 - Description technique du travail réalisé<br />
un lien vers l instruction suivante ira du sommet gauche du losange, et si la condition est fausse le<br />
lien vers l instruction suivante ira du sommet droit. On peut voir ci-<strong>de</strong>ssous un exemple <strong>de</strong> son<br />
utilisation :<br />
if (condition)<br />
instruction_1<br />
else<br />
instruction_2<br />
Condition<br />
vraie<br />
Condition<br />
fausse<br />
Instruction_1<br />
Instruction_2<br />
Figure 22. Propriétés du noeud représentant une condition.<br />
Les scripts <strong>de</strong> nos graphes <strong>de</strong> dépendances sont générés <strong>de</strong> manière automatique à partir <strong>de</strong> la<br />
base <strong>de</strong> données, grâce à trois scripts awk (cf. annexe VI) placés dans le dossier bin/ . Le<br />
premier fichier se nomme « formaterdata.awk » et permet <strong>de</strong> supprimer <strong>de</strong>s informations<br />
superfluesextraites concernant l exéction interne à EiC. Le <strong>de</strong>uxième fichier se nomme<br />
« graph1.awk » et permet <strong>de</strong> générer les premières lignes du script dot c'est-à-dire l entet du fichier<br />
(en rouge sur la figure 23) et le co<strong>de</strong> générant l echelle d enchainement <strong>de</strong>s lignes d instructions<br />
placée à gauche du graphe <strong>de</strong> dépendance (en bleu sur la figure 23). Le troisième script est<br />
nommé « graph2.awk » qui génère le co<strong>de</strong> dot adéquant suivant le type <strong>de</strong> ligne dans la base<br />
donnée 20 , à savoir le type du n ud 21 , sa couleur, son comportement (dans le cas d une condition<br />
par exemple) ou encore un lien reliant <strong>de</strong>ux n uds (cas d un Use) . On peut voir à la figure 23 ci<strong>de</strong>ssous<br />
un exemple <strong>de</strong> co<strong>de</strong>s dot générés en fonction <strong>de</strong> la base <strong>de</strong> données obtenue pour le<br />
programme « var2.c » donné en figure 21.<br />
digraph G { ranksep=.75; size="7.5,7.5";<br />
{ no<strong>de</strong> [shape=plaintext, fontsize=16];<br />
"main:1" -> "4:1" -> "5:1" -> "end"; }<br />
{ rank = same;<br />
"main:1"; "#main:1"; }<br />
"#main:1" [label="main-1", shape=box, color=red]<br />
var2.c :<br />
# main:1<br />
main 1<br />
# 4:1 <br />
Def 1-0 12 4 1<br />
# 5:1 <br />
Use 1-0 4 1 5 1<br />
Return 12 5 1<br />
"#main:1" -> "#4:1"<br />
{ rank = same;<br />
"4:1"; "#4:1"; }<br />
"#4:1" [label="1-0=12", color=green]<br />
"#4:1" -> "#5:1"<br />
{ rank = same;<br />
"5:1"; "#5:1"; }<br />
"#5:1" [label="Return-1\n12", shape=box]<br />
}<br />
Figure 23. Co<strong>de</strong> dot généré à partir <strong>de</strong> la base <strong>de</strong> données.<br />
20<br />
Use, Def, main, Return, Cond, Call.<br />
21 Rectangle, ellipse, losange<br />
57
Chapitre 5 - Description technique du travail réalisé<br />
Sur la figure 23, on peut voir le détail du script dot ; chaque n ud est i<strong>de</strong>ntifié par une chaine <strong>de</strong><br />
caractère entre guillemets, ainsi le n ud "4 :1" et différent du n ud "#4 :1". Nous nous sommes<br />
servi <strong>de</strong> cette particularité du co<strong>de</strong> Dot pour i<strong>de</strong>ntifier les n uds <strong>de</strong> l échelle d instructions par<br />
"x :y" et les n uds du graphe <strong>de</strong> dépendances par "#x :y", ce qui nous a permis <strong>de</strong> mettre chaque<br />
n ud du graphe au même niveau que son correspondant dans l echelle (cf. co<strong>de</strong>s dot encadrés en<br />
bleu : rank=same; "5 :1"; "#5 :1";). Chaque n ud du graphe <strong>de</strong> dépendance est définit<br />
par plusieurs critères tels qu une forme (rectangle, ellipse, etc.), un label (ce qui sera inscrit à<br />
l intérieur <strong>de</strong> la forme) ou encore une couleur.<br />
On peut également voir sur la figure 23, en première ligne (surligné en rouge) l entête du fichier<br />
<strong>de</strong> script dot, suivi par le co<strong>de</strong> générant l echelle <strong>de</strong> suite d instructions (cf. surligné en bleu). Les<br />
lignes <strong>de</strong> scripts encadrées en bleu sont générées à chaque nouvelle ligne <strong>de</strong> base <strong>de</strong> donnée<br />
commençant par le symbole «# ». Nous voyons ensuite que chaque ligne <strong>de</strong> base <strong>de</strong> donnée<br />
génère la définition d un n ud avec le label correspondant à son type et/ou un lien entre <strong>de</strong>ux<br />
n uds (cf liens en violet). Ainsi, la ligne <strong>de</strong> base <strong>de</strong> donnée <strong>de</strong> type main gènère la définition du<br />
n ud main comme un rectangle <strong>de</strong> couleur rouge <strong>de</strong> label « main-1 », puis relie ce n ud au<br />
n ud suivant "# 4:1", <strong>de</strong> la même façon la ligne Use 1-0 4 1 5 1 génère un lien allant du<br />
n ud "# 4 :1" ou la variable 1-0 à été définie, vers le n ud "# 5:1".<br />
Comme nous venons <strong>de</strong> le voir, chaque ligne <strong>de</strong> la base <strong>de</strong> donnée est exploitée pour générer<br />
suivant son type une série <strong>de</strong> co<strong>de</strong>s dot pour définir l échelle <strong>de</strong> suite d instructions, le type <strong>de</strong><br />
n uds, et les liens entre ces <strong>de</strong>rniers. Le graphe que nous générons ensuite par dot est en format<br />
postscript, ils peuvent ainsi être visualisés sur bon nombre <strong>de</strong> plateformes.<br />
58
Chapitre 5 - Description technique du travail réalisé<br />
59
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Chapitre 6 - Exemples <strong>de</strong> résultats<br />
N ous avons vu au long <strong>de</strong>s chapitres précé<strong>de</strong>nts <strong>de</strong>s extraits <strong>de</strong> graphes <strong>de</strong> dépendances<br />
<strong>dynamique</strong>s <strong>de</strong> données générés suivant le modèle <strong>de</strong> graphes <strong>de</strong> dépendances <strong>de</strong> l outil<br />
DDFgraph pour le le langage Lisp (cf. chapitre 1). Ce chapitre, présente les résultats que nous<br />
obtenons grâce à la technique <strong>de</strong> génération <strong>de</strong> graphe décrite dans le chapitre précé<strong>de</strong>nt, qui<br />
présente les données <strong>de</strong> manière différente que pour le modèle suivi. Nous voyons dans ce<br />
chapitre les résultats <strong>de</strong> graphes <strong>dynamique</strong>s <strong>de</strong> dépendances entre données obtenus pour<br />
quelques exemples <strong>de</strong> programmes manipulant <strong>de</strong>s variables entières. Nous présentons ces<br />
résulats par ordre croissant <strong>de</strong> complexité.<br />
6.1. Opérations sur <strong>de</strong>s variables entières<br />
Nous prenons pour premier exemple le fichier « ext_affvar1.c », qui effectue <strong>de</strong> simples opérations<br />
sur <strong>de</strong>s valeurs entières, retournant la valeur d une <strong>de</strong>s variables manipulées en fin <strong>de</strong> programme.<br />
1 /* ext_affvar1.c */<br />
2 int g;<br />
3 int main()<br />
4 {<br />
5 int x,y,a,b;<br />
6 x = 12;<br />
7 y = 8;<br />
8 g = 15;<br />
9 a = x + y;<br />
10 x = a - g;<br />
11 a ++;<br />
12 return a;<br />
13 }<br />
Nous pouvons voir sur la figure 24 le graphe <strong>de</strong> dépendances<br />
<strong>dynamique</strong> <strong>de</strong>s variables entières manipulées par le programme<br />
source. Nous avons ajouté, pour une meilleure lecture du graphe,<br />
près <strong>de</strong> chaque n ud définissant une variable, le symbole<br />
correspondant à l i<strong>de</strong>ntifiant <strong>de</strong> celle-ci 22 .<br />
En observant le graphe <strong>de</strong> plus près, nous pouvosn remarquer que<br />
la variable b n est pas affichée sur le graphe, ceci est expliqué par le<br />
fait que cette <strong>de</strong>rnière n est pas manipulée pendant l exécution du<br />
programme. Nous pouvons ainsi voir sur ce graphe les<br />
dépendances entre les variables, comme par exemple la variable x<br />
est définie en ligne 6 puis sa valeur est utilisée en ligne 9 pour<br />
définir la valeur <strong>de</strong> la variable a, puis elle est encore modifiée en<br />
ligne 10 en prenant une nouvelle valeur issue d une opération sur<br />
les variables a et g.<br />
Par contre il n existe pas <strong>de</strong> lien représenté entre les variables x, y et<br />
g avec la fonction main dans laquelle ils sont définis, ce problème<br />
d affichage est traité dans le chapitre 8.<br />
x<br />
y<br />
a<br />
a<br />
g<br />
x<br />
22<br />
Automatiserle rempalcement <strong>de</strong> l i<strong>de</strong>ntifiant interne <strong>de</strong>s variables par leur<br />
symbole est l une <strong>de</strong> nos perspectives (cf. chapitre 8).<br />
Figure 24. Graphe <strong>de</strong><br />
dépendances <strong>dynamique</strong><br />
60
Chapitre 6 - Exemples <strong>de</strong> résultats<br />
Nous voyons dans ce <strong>de</strong>uxième exemple comment<br />
l affichage graphique <strong>de</strong>s dépendances <strong>dynamique</strong>s réalisé<br />
peut mettre en évi<strong>de</strong>nce les variables non utilisées au cours<br />
<strong>de</strong> l exécution <strong>de</strong> programmes.<br />
1 /* isole.c */<br />
2 int main() {<br />
3 int x,y,z;<br />
4 x = 1;<br />
5 y = 5;<br />
6 z = 3;<br />
7 z += x;<br />
8 return x;<br />
9 }<br />
Nous utilisons le co<strong>de</strong> source ci-<strong>de</strong>ssus définissant une<br />
variable y sans l utiliser dans le reste <strong>de</strong>s instructions, nous<br />
pouvons alors visualiser le comportement <strong>de</strong>s instructions<br />
<strong>de</strong> ce programme sur la figure 25, la variable y i<strong>de</strong>ntifiée par<br />
1-1 (cf. ligne 5 du co<strong>de</strong> source) est isolée <strong>de</strong>s autres<br />
instructions. Ceci peut nous permettre dans le cas <strong>de</strong> longs<br />
programmes complexes d isoler les instructions qui n ont pas<br />
<strong>de</strong> rôle dans l exécution du programme et <strong>de</strong> les éliminer afin<br />
d améliorer le temps d exécution <strong>de</strong> ce <strong>de</strong>rnier, d autant plus<br />
si l instruction se trouve dans une boucle appellée un grand<br />
nombre <strong>de</strong> fois.<br />
6.2. Conditionnelles<br />
Figure 25. Mise en évi<strong>de</strong>nce d'une<br />
variable isolée<br />
z<br />
z<br />
x<br />
y<br />
Nous voyons les résultats obtenus par notre programme pour la gestion d instructions à<br />
conditions, en commençant par donner <strong>de</strong>s exemples <strong>de</strong> graphes obtenus pour l instruction if,<br />
puis nous montrons <strong>de</strong>s graphes obtenus pour les boucles while, do..while() et for. Mais<br />
avant d abor<strong>de</strong>r ces exemples, il faut noter que seule la comparaison < est gérée par notre<br />
programme.<br />
6.2.1. L instruction if<br />
6.2.1.1. Cas simples<br />
Pour voir le comportement <strong>de</strong> programmes faisant appel à l instruction <strong>de</strong> contrôle if, nous<br />
utilisons les <strong>de</strong>ux programmes ci-<strong>de</strong>ssous, le premier vérifie une condition vraie et le <strong>de</strong>uxième<br />
vérife une condtion fausse et fait appel également à l instruction else, les représentations<br />
graphiques <strong>de</strong> ces <strong>de</strong>ux programm²es sont présentées à la figure 25.<br />
if2.c<br />
if1.c<br />
1 int main (void){<br />
2 int x;<br />
3 x=6;<br />
4 if (x
Chapitre 6 - Exemples <strong>de</strong> résultats<br />
x<br />
x<br />
x<br />
x<br />
Figure 26. Graphes générés pour les fichiers "if1.c" cas où la condition est vraie à gauche et "if2.c" pour<br />
un cas <strong>de</strong> condition fausse à droite.<br />
Nous pouvons observer sur le graphique <strong>de</strong> gauche <strong>de</strong> la figure 26, que la condition du if (x
Chapitre 6 - Exemples <strong>de</strong> résultats<br />
ifimbriques.c<br />
Figure 27. Graphe <strong>de</strong><br />
dépendance pour l'appel <strong>de</strong> if<br />
imbriqués « ifimbriques.c »<br />
1 #inclu<strong>de</strong> <br />
2 int main (void){<br />
3 int a,b,c;<br />
4 a=6;<br />
5 b=3;<br />
6 c=5;<br />
7 if (b
Chapitre 6 - Exemples <strong>de</strong> résultats<br />
while.c<br />
1 #inclu<strong>de</strong> <br />
2<br />
3 int x;<br />
4 int main (void){<br />
5 x=0;<br />
6 while (x
Chapitre 6 - Exemples <strong>de</strong> résultats<br />
Figure 29. Graphe <strong>de</strong><br />
dépendances pour le co<strong>de</strong><br />
x<br />
x<br />
do.c<br />
1<br />
2 int main (void){<br />
3 int x;<br />
4 x = 0;<br />
5 do {<br />
6 x++;<br />
7 }while(x < 2);<br />
8 return 0;<br />
9 }<br />
x<br />
Au <strong>de</strong>uxième tour <strong>de</strong> boucle, les instructions qui y sont appelées<br />
ont leur numéro <strong>de</strong> ligne avec un compteur d appel égal à 2, c està-dire<br />
les lignes 6 :2 pour l incrémenattion <strong>de</strong> la valeur <strong>de</strong> x et la<br />
ligne 7 :2 pour la condition du while. La <strong>de</strong>uxième évaluation <strong>de</strong><br />
la condition n étant pas vérifiée la ligne d instruction 8 :1 est<br />
exécutée pour retourner la valeur 0.<br />
6.2.4. Boucle for<br />
for.c<br />
b<br />
i=0; i=1;<br />
Pour l exemple <strong>de</strong> boucle for,<br />
nous avons utilisé le programme<br />
« for.c », qui fait <strong>de</strong>ux tours <strong>de</strong><br />
boucles for et qui modifie la<br />
valeur <strong>de</strong> la variable b (initialisée<br />
à 5) à chaque tour <strong>de</strong> boucle en<br />
fonction <strong>de</strong> la variable i. La<br />
variable i étant l in<strong>de</strong>x <strong>de</strong> boucle.<br />
1 int main (void){<br />
2 int i,b;<br />
3 b = 5;<br />
4 for (i=0; i < 2; i++){<br />
5 b += i;<br />
6 }<br />
7 return b;<br />
8 }<br />
b<br />
b<br />
i=2;<br />
Nous voyons alors sur le graphe généré que les conditions dans<br />
l appel <strong>de</strong> la boucle for sont correctement évaluées, les <strong>de</strong>ux<br />
tours <strong>de</strong> boucles sont bien effectuées et la valeur <strong>de</strong> b est<br />
également bien modifiée. Cependant, bien que nous ayons les<br />
bons résultats et les bonnes évaluations <strong>de</strong> conditions pour<br />
chaque boucle, nous voyons que notre graphique se comporte <strong>de</strong><br />
manière innatendue. Il effectue en effet un retour sur chaque<br />
appel <strong>de</strong> condition, ce qui n est pas le cas dans notre programme.<br />
De plus, notre outil considère l initialisation et l incrémentation<br />
<strong>de</strong> l in<strong>de</strong>x i ainsi que l évaluation <strong>de</strong> la condition, comme étant<br />
effectués par une même instruction i<strong>de</strong>ntifiée par la ligne du for<br />
(4 :1, 4 :2, 4 :3 dans notre exemple). Or notre programme ne<br />
i=3;<br />
Figure 30. Graphe <strong>de</strong><br />
dépendances pour le co<strong>de</strong><br />
65
Chapitre 6 - Exemples <strong>de</strong> résultats<br />
prend pas encore en compte l exécution <strong>de</strong> <strong>de</strong>ux instructions sur une même ligne. Il nous faudrait<br />
alors trouver un moyen <strong>de</strong> gérer, au niveau <strong>de</strong> la numérotation <strong>de</strong> nos instruction les cas<br />
d instructions sur une même ligne (cf. chapitre 8).<br />
6.2.5. Boucles a imbriquées<br />
imbriques.c<br />
1 #inclu<strong>de</strong> <br />
2 int main(void){<br />
3 int a,b,c;<br />
4 b = 2;<br />
5 a = 3;<br />
6 c = 0;<br />
7 do {<br />
8 while (c < b){<br />
9 c++;<br />
10 }<br />
11 b++;<br />
12 } while (c
Chapitre 6 - Exemples <strong>de</strong> résultats<br />
6.3. Appels <strong>de</strong> fonctions avec et sans arguments<br />
Nous voyons dans cette section la manière dont sont représentés graphiquement les appels <strong>de</strong><br />
fonctions, définies dans un programme C. Nous commençons par présenter l exemple d un appel<br />
d une fonction sans arguments, avec <strong>de</strong>s variables qui lui sont locales, puis nous présentons un<br />
<strong>de</strong>uxième exemple d appel d une fonction avec arguments.<br />
6.3.1. Fonction sans arguments<br />
Nous utilisons le programme « foncssarg.c » pour présenter le cas d un appel d une fonction sans<br />
argument. Ce programme commence par définir la fonction add23() qui aditionne <strong>de</strong>ux<br />
variables entières, définies en local, <strong>de</strong> valeur 2 et 3, puis retourne leur somme. La fonction<br />
main() est définie ensuite et ne fait que retourner le résultat <strong>de</strong> l appel à la fonction add23().<br />
foncssarg.c<br />
x<br />
y<br />
1<br />
2 int add23 (void) {<br />
3 int x,y;<br />
4 x = 2;<br />
5 y = 3;<br />
6 return x+y;<br />
7 }<br />
8<br />
9 int main(void) {<br />
10 return add23();<br />
11 }<br />
On peut voir sur la figure 32 le graphe <strong>de</strong><br />
dépendances généré pour ce programme.<br />
La fonction add23() est ainsi appelée en<br />
premier en ligne 10 :1, ses variables locales<br />
sont définies aux lignes 4 :1 et 5 :1 et sont<br />
i<strong>de</strong>ntifiées par 1-0 pour x et 1-1 pour y.<br />
Nous voyons également sur cette figure, que la fonction add23-1<br />
n est pas reliée à la fonction Return-2. Ceci est en effet dû au fait<br />
que nous ne générons pas encore d informations dans notre base <strong>de</strong><br />
données pour relier la fonction appelée à l instruction l appelant, ici<br />
Return-1 <strong>de</strong> la fonction add23-1 <strong>de</strong>vrait être reliée à Return-2<br />
(cf. lien en pointillés rouges). Nous verrons au chapitre 8 comment<br />
nous pouvons remédier à cela.<br />
Figure 32. Graphe <strong>de</strong><br />
dépendances <strong>de</strong> données<br />
pour "foncssarg.c".<br />
De plus, contrairement au cas du for, l appel d une fonction dans<br />
une instruction est considéré comme la succession <strong>de</strong> <strong>de</strong>ux<br />
instructions : d abord l appel <strong>de</strong> la fonction puis l instruction ellemême.<br />
Ici la fonction add23() est exécutée en ligne 10 :1 et lorsque la<br />
fonction fait appel a sa valeur <strong>de</strong> retour, le compteur d appel <strong>de</strong><br />
l instruction 10 est incrémenté au lieu <strong>de</strong> rester à 1.<br />
67
Chapitre 6 - Exemples <strong>de</strong> résultats<br />
6.3.2. Fonction avec arguments<br />
Nous voyons maintenant comment l appel <strong>de</strong> fonctions avec arguments est représenté<br />
graphiquement, puis ce que l on obtient dans la base <strong>de</strong> données grâce à la version modifiée <strong>de</strong><br />
EiC. L exemple qui suit utilise le programme « foncavcarg.c » qui définit <strong>de</strong>ux variables entières dans<br />
la fonction main(), ces valeurs sont alors passées en argument à la fonction add23().<br />
a<br />
b<br />
x,y<br />
Figure 33. Graphe <strong>de</strong> dépendances<br />
<strong>de</strong> données généré pour le<br />
programme "foncavarg.c".<br />
foncavcarg.c :<br />
# main:1<br />
main 1<br />
# 7:1 <br />
Def 1-0 2 7 1<br />
# 8:1 <br />
Def 1-1 3 8 1<br />
foncavcarg.c<br />
# 9:1 <br />
stoval -3- stoval -2- eiccall<br />
1 int add23 (int x,int y) {<br />
2 return x+y;<br />
3 }<br />
4<br />
5 int main(void) {<br />
6 int a,b;<br />
7 a = 2;<br />
8 b = 3;<br />
9 return add23(2,3);<br />
10 }<br />
Nous pouvons voir sur cet exemple les définitions <strong>de</strong>s<br />
variables a et b <strong>de</strong> la fonction main() aux lignes 7 :1 et 8 :1,<br />
qui sont suivies du premier appel à la fonction add23 en ligne<br />
9:1. Nous pouvons remarquer qu à cette même ligne un n ud<br />
est relié à la fonction Return-1 <strong>de</strong> la ligne 2 du co<strong>de</strong> source et<br />
qui retourne bien la somme <strong>de</strong>s valeurs <strong>de</strong>s arguments à la<br />
fonction add23(). Ainsi, les arguments x et y sont<br />
représentés par un n ud unique : le noeud « #1:629592 »,<br />
dont le 1 signifie que ces variables sont définies en ligne 1 du<br />
co<strong>de</strong> source et le chiffre 629592 correspond au nombre<br />
d appels <strong>de</strong> cette ligne, cette valeur est à priori fausse puisqu il<br />
s agit du premier appel à la fonction add23 définie en ligne 1.<br />
Ceci étant, les liens partant <strong>de</strong> ces variables x et y vers la<br />
fonction Return-1 sont correctement affichés.<br />
En regardant <strong>de</strong> plus près la base <strong>de</strong> données (donnée ci<strong>de</strong>ssous)<br />
générée avec EiC nous pouvons voir que ces <strong>de</strong>ux<br />
variables sont i<strong>de</strong>ntifiées au niveau 1 et numérotées négativement 23 c est-à-dire que la variable x<br />
est i<strong>de</strong>ntifiée par 1- -1 et y par 1- -2 (cf. surlignés en rouge dans la base <strong>de</strong> données) et leurs<br />
valeurs sont transmises à la fonction grâce au co<strong>de</strong> opérateur stoval (cf. surlignés en jaune ci<strong>de</strong>ssous),<br />
comme nous pouvons le voir ici :<br />
foncavcarg.c :<br />
Fonc add23 9 1<br />
# 2:1 <br />
Use 1--1 1 629592 2 1<br />
Use 1--2 1 629592 2 1<br />
Return 5 2 1<br />
[main]<br />
# 9:2 <br />
Return 5 9 2<br />
[::EiC::]<br />
23 Les variables passées en argument à une fonction sont numérotées négativement par EiC.La numérotation<br />
commence par -1 pour le premier argument, -2 pour le suivant et ainsi <strong>de</strong> suite.<br />
68
Chapitre 6 - Exemples <strong>de</strong> résultats<br />
Les valeurs surlignées en jaune et en rouge ne sont pas représentées dans notre graphique, il<br />
faudrait donc trouver un moyen <strong>de</strong> les afficher.<br />
Nous avons également réfléchi sur les cas d affichage <strong>de</strong> tableau, mais nous n avosn aps encore<br />
<strong>de</strong> représentation graphique <strong>de</strong> ce type <strong>de</strong> donnée, nous sommes cependant arrivés à reconnaître<br />
la série <strong>de</strong> co<strong>de</strong>s opérateurs intervenants pour la définition d un élèment du tableau. Nous voyons<br />
au chapitre 8 comment exploiter ces informations pour représenter les tableaux dans notre<br />
graphe <strong>de</strong> dépendances ?<br />
Nous avons donc vu ce que l on peut déjà représenter avec notre outil d analyse <strong>dynamique</strong> basé<br />
sur l interprète EiC, à savoir l affichage pour :<br />
- Les séquences d instructions, grâce à l échelle d enchainement <strong>de</strong>s lignes d instructions.<br />
- Les dépendances entre données manipulées par les instructions.<br />
- Les boucles grâce à notre numérotation unique <strong>de</strong>s lignes d instructions.<br />
- Les conditionnelles représentées par un n ud dont le comportement change suivant que<br />
la valeur <strong>de</strong> la condition.<br />
Tout cela donne un aperçu <strong>de</strong> ce que l on pourrait faire en étendant les fonctionnalités <strong>de</strong> notre<br />
outil, nous verrons dans le chapitre <strong>de</strong>s perspectives (chapitre 8) l ensemble <strong>de</strong>s améliorations<br />
pouvant encore être apportées à notre outil dans ce sens.<br />
69
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Chapitre 7 - Comparaison avec l existant<br />
Il existe à l heure actuelle <strong>de</strong> nombreuses recherches portant sur le domaine <strong>de</strong> l analyse<br />
<strong>dynamique</strong> <strong>de</strong> programme. Certains travaux <strong>de</strong> recherche ont même permis <strong>de</strong> développer <strong>de</strong>s<br />
outils dont les résultats sont encourageants quant aux objectifs <strong>de</strong> ces recherches. Je vais<br />
présenter dans ce chapitre, quelques projets traitant <strong>de</strong> l analyse <strong>dynamique</strong> <strong>de</strong> programmes et<br />
apportant une solution pour visualiser les dépendances entre données extraites.<br />
Dans le domaine <strong>de</strong> la recherche, nous pouvons citer les travaux <strong>de</strong> Systä sur l analyse <strong>dynamique</strong><br />
<strong>de</strong> programmes objets (Java) [SYS 01]. Le concept <strong>de</strong> dépendances <strong>dynamique</strong>s fû introduit par<br />
Korel et Laski [KOR 88] dans le contexte du slicing <strong>dynamique</strong>, qui consiste à connaitre les<br />
valeurs <strong>de</strong>s variables dont la valeur dépend directement d une variable donnée. Le concept <strong>de</strong><br />
graphes <strong>de</strong> dépendances <strong>dynamique</strong>s a été introduit par Agrawal et Horgan [AGR 90] qui se base<br />
sur <strong>de</strong>s algorithmes pour calculer les slices <strong>dynamique</strong>s. Ces algorithmes utilisent un historique <strong>de</strong><br />
l exécution pour extraire les informations sur les slices concernés. Ces techniques sont<br />
essentiellement intégrées dans <strong>de</strong>s programmes tels que les débuggeurs, qui permettent d obtenir<br />
les valeurs <strong>de</strong>s variables pendant l exécution du programme ; ces valeurs sont visualisables <strong>de</strong><br />
façon textuelle et non graphique. Du fait <strong>de</strong> l importante masse <strong>de</strong> données générée par ces<br />
techniques, <strong>de</strong>s étu<strong>de</strong>s se sont orientées pour trouvers <strong>de</strong>s solutions <strong>de</strong> compactages <strong>de</strong>s données.<br />
Notre projet, intègre le calcul <strong>dynamique</strong> et la représentation graphique <strong>de</strong>s dépendances <strong>de</strong><br />
données. Il permet <strong>de</strong> tracer non seulement les dépendances d une variable mais l ensemble <strong>de</strong>s<br />
interactions <strong>de</strong>s données manipulées par le programme.<br />
Dans le reste du chapitre, nous présentons en section 7.1 l outil Call graph d ai<strong>de</strong> à la<br />
maintenance <strong>de</strong> programmes C. Le <strong>de</strong>uxième outil, Zeugma, que nous présentons en section 7.2,<br />
propose une approche originale <strong>de</strong> représentation <strong>de</strong>s données. Et le <strong>de</strong>rnier outil, Care, que nous<br />
présentons dans la section 7.3, représente la solution la plus proche <strong>de</strong> notre outil.<br />
7.1. Call graph Drawing interface<br />
L outil Call Graph Drawing Interface [ENG 03] est une solution permettant d afficher le graphe<br />
<strong>de</strong> dépendances <strong>de</strong>s appels <strong>de</strong> fonctions pour <strong>de</strong>s co<strong>de</strong>s sources C et C++ sous Unix. Le<br />
graphique <strong>de</strong>s dépendances <strong>de</strong>s appels est généré pendant l exécution du co<strong>de</strong> source par le<br />
compilateur avec les options p et g <strong>de</strong> GCC. Il utilise ainsi l outil <strong>de</strong> profiling <strong>de</strong> programmes<br />
Gprof [FEN 97], pour extraire les données <strong>dynamique</strong>s du co<strong>de</strong> source et l outil VCG [SAN 95]<br />
pour afficher ces dépendances graphiquement.<br />
Nous pouvons voir ci-<strong>de</strong>ssous un exemple d affichage <strong>de</strong>s dépendances <strong>dynamique</strong>s <strong>de</strong>s<br />
interactions entre les fonctions d un programme C++ donné également dans cette figure.<br />
70
Chapitre 7 - Comparaison avec l existant<br />
#inclu<strong>de</strong> <br />
class A {<br />
public:<br />
void a();<br />
void b();<br />
void c();<br />
};<br />
void A::a(){b();}<br />
void A::b(){}<br />
void A::c(){}<br />
int main()<br />
{A t;<br />
t.a();<br />
t.c();<br />
exit(0);}<br />
Figure 34. Graphe <strong>de</strong> dépendance <strong>de</strong>s fonctions du fichier "test.cpp" à gauche <strong>de</strong> la figure<br />
Nous pouvons voir dans cet exemple, que la fonction main fait appel à trois fonctions. La<br />
première fonction a() est définie dans la classe A et fait appel à la fonction b() qui est est<br />
définie dans cette classe. La <strong>de</strong>uxième fonction c() est également définie dans A et la troisième<br />
est la fonction exit(0). Sur le graphe généré <strong>dynamique</strong>ment, on peut voir <strong>de</strong>s liens <strong>de</strong> la<br />
fonction main vers les <strong>de</strong>ux fonctions <strong>de</strong> classe A, avec le lien représentant l appel <strong>de</strong> la fonction<br />
a() à la fonction b() et enfin un lien <strong>de</strong> la fonction main vers la fonction exit. Nous n avons<br />
donc aucune représentation sur la valeur passée en argument à la fonction exit, contrairement à<br />
notre outil qui permet <strong>de</strong> retourner ces valeurs graphiquement.<br />
L appel à Gprof permet <strong>de</strong> consulter le contenu du fichier <strong>de</strong> données généré, <strong>de</strong>s options<br />
d appel à cet outil permettent <strong>de</strong> filtrer les données qu on veut consulter (par exemple choisir <strong>de</strong><br />
ne pas représenter certaines fonctions). Le fichier <strong>de</strong> données doit ensuite être manipulé par<br />
d autres outils pour le mettre sous un format spécifique lisible par VCG. Il n y a, <strong>de</strong> plus, aucune<br />
automatisation <strong>de</strong> cette génération <strong>de</strong> graphes.<br />
Donc cet outil, tout comme le nôtre, permet d obtenir une visualisation <strong>de</strong> données extraites <strong>de</strong><br />
manière <strong>dynamique</strong> d un co<strong>de</strong> source. L avantage que présente Call Graph est que toutes les<br />
spécificités du C sont prises en compte étant donné que le compilateur gcc est utilisé. Cependant,<br />
les informations extraites ne concernent que les dépendances entre fonctions, ce qui ne donne au<br />
développeur qu une partie <strong>de</strong> l information manipulée par un programme. Notre programme<br />
permet non seulement <strong>de</strong> générer un plus grand nombre d informations d un co<strong>de</strong> source exécuté<br />
mais se base sur un interprète, portable sur un grand nombre <strong>de</strong> systèmes. Il offre également une<br />
génération automatique <strong>de</strong>s graphes <strong>de</strong> dépendances.<br />
7.2. Zeugma : représentation métaphorique <strong>de</strong><br />
programmes<br />
L outil Zeugma [PLO 02], développé par D. Ploix en Intelligence Artificielle, porte sur la<br />
représentation analogique <strong>de</strong> programmes en Vlisp. Il est basé sur <strong>de</strong>s liens métaphoriques entre<br />
les objets manipulés <strong>dynamique</strong>ment par un programme et <strong>de</strong>s domaines <strong>de</strong> représentations dans<br />
<strong>de</strong>s villes ou encore <strong>de</strong>s comportements d animaux lors <strong>de</strong> l exécution du programme, ces liens<br />
sont activés pour ainsi construire une représentation métaphorique du programme.<br />
71
Chapitre 7 - Comparaison avec l existant<br />
Nous pouvons voir sur les exemples <strong>de</strong>s figures 35 et 36 chacune <strong>de</strong> ces représentations :<br />
Figure 35. Représentation en ville à gauche, détail d une maison à plusieurs étages en haut à droite et<br />
d une maison contenant d autres maisons en bas à droite<br />
Figure 36. Représentation en toile d'araignée à gauche et détail d une araignée à droite<br />
La figure 35, présente l exemple d une visualisation d un programme sous forme d une ville.<br />
Chaque quartier <strong>de</strong> la ville correspond à un type <strong>de</strong> données i<strong>de</strong>ntifié par sa couleur : les boules<br />
(en rouge), les conditions (en orange), les additions <strong>de</strong> nombres (en bleu) pour notre exemple.<br />
Chaque quartier est composé <strong>de</strong> rues reliant plusieurs maisons pour traduire les interactions entre<br />
données. Chaque maison est composée d étages (cf. figure), plus elle a d étages plus la fonction<br />
72
Chapitre 7 - Comparaison avec l existant<br />
qu elle représente est complexe, elle peut également contenir d autre maisons pour les appels<br />
récursifs.<br />
La figure 39, représente les interactions entre fonctions et variables comme <strong>de</strong>s interactions entre<br />
araignées sur une toile, chaque araignée représentant une fonction du programme. A la fin <strong>de</strong><br />
l exécution, plus les araignées sont proches plus les interactions entre les données qu elles<br />
représentent sont importantes.<br />
Cet outil, permet <strong>de</strong> se construire une idée assez précise du comportement d un programme, mais<br />
il ne permet pas <strong>de</strong> connaître les valeurs manipulées par le programme ni <strong>de</strong> suivre le contrôle <strong>de</strong><br />
son exécution.<br />
7.3. CARE<br />
Le projet CARE (Computer-A i<strong>de</strong>d Re-Engineering) [LIN1 93, LIN2 93] est issu <strong>de</strong>s recherches<br />
effectuées au sein du Laboratoire du Département Informatique <strong>de</strong> l Université Technologique<br />
du Tennessee (Etats-Unis) et ceci <strong>de</strong>puis 1990. Ce projet vise à développer <strong>de</strong>s prototypes<br />
d outils d ai<strong>de</strong> à la compréhension, à la maintenance et à la création <strong>de</strong> programmes.<br />
Ces travaux se sont basés sur <strong>de</strong>ux outils appelés VIFOR (Visual Interactive Fortran) et VIC<br />
(Visual Interactive C), développés dans les années 80 par <strong>de</strong>s membres <strong>de</strong> l équipe <strong>de</strong> recherche<br />
<strong>de</strong> l Université Wayne State à Détroit (Michigan). Les outils actuellement développés par l équipe<br />
du projet sont au nombre <strong>de</strong> trois :<br />
- CARE est un outil pour la compréhension et le développement <strong>de</strong> gros programmes en<br />
ANSI C<br />
- OO!CARE est la version orientée objet <strong>de</strong> CARE, qui facilite la compréhension et la<br />
maintenance <strong>de</strong> programmes écrits en C++<br />
- PolyCARE est le fruit <strong>de</strong>s <strong>de</strong>rniers travaux <strong>de</strong> recherche <strong>de</strong> l équipe CARE. Cet outil se<br />
concentre sur l ai<strong>de</strong> à la compréhension <strong>de</strong> programmes complexes écrits en différents<br />
langages.<br />
L outil CARE est donc assez proche <strong>de</strong> par sa <strong>de</strong>scription aux objectifs <strong>de</strong> notre travail, mais<br />
voyons <strong>de</strong> plus près l étendue <strong>de</strong>s possibilités qu offre ce logiciel aux développeurs.<br />
Cet outil permet d obtenir la représentation graphique <strong>de</strong> quatre types <strong>de</strong> données :<br />
- une représentation textuelle (cf. figure 37)<br />
- une représentation sous forme <strong>de</strong> colonnes <strong>de</strong> types <strong>de</strong> données (cf figure 38)<br />
- une représentation <strong>de</strong> graphe hiérarchique <strong>de</strong>s dépendances entre données (cf. figure 39)<br />
- <strong>de</strong>s représentations <strong>de</strong> slicings (cf. figure 40)<br />
Ces différentes représentations <strong>de</strong> données sont générées après analyse du programme source,<br />
qui extrait dans une base <strong>de</strong> données les informations sur les interactions entre les données du<br />
programme. L ensemble <strong>de</strong> ces représentations est généré via une interface graphique, comme<br />
nous pouvons le voir sur les figures qui suivent.<br />
73
Chapitre 7 - Comparaison avec l existant<br />
Figure 37. Représentation textuelle d'un programme C<br />
Figure 38. Représentation en collonnes<br />
74
Chapitre 7 - Comparaison avec l existant<br />
Figure 39. Représentation hiérarchique <strong>de</strong>s appels <strong>de</strong> fontions du programme <strong>de</strong> la figure 37<br />
Figure 40. Représentation graphique d'un slice <strong>de</strong> la fonction Get Number<br />
Comme nous pouvons voir sur ces figures, les données <strong>de</strong>s variables manipulées ne sont pas<br />
représentées, contrairement à notre outil. CARE se présente donc comme un outil complet pour<br />
l analyse statique <strong>de</strong> programmes C, et permet grâce à son interface <strong>de</strong> visualiser un ensemble <strong>de</strong><br />
représentations permettant ainsi au <strong>de</strong>veloppeur d avoir une meilleure connaissance du<br />
programme. Notre outil permet <strong>de</strong> représenter le graphe <strong>de</strong> hiérarchie, <strong>de</strong> la même manière que<br />
CARE, mais en se basant sur une analyse <strong>dynamique</strong> ce qui le rend plus précis.<br />
De plus, CARE fonctionne sur <strong>de</strong>s machines DEC et <strong>de</strong>s stations <strong>de</strong> travail HP avec un système<br />
Unix avec un X-based Motif GUI. Contrairement à notre outil qui peut être utilisé sur<br />
différentes plateformes (cf. section 3.4).<br />
Ainsi, notre outil d analyse <strong>dynamique</strong> <strong>de</strong> programmes C, apporte grâce à sa base d analyse<br />
<strong>dynamique</strong> <strong>de</strong> programme la possibilité d avoir une trace précise <strong>de</strong>s dépendances entre données,<br />
ce que n offre aucun <strong>de</strong>s outils présentés dans ce chapitre, bien qu ils permettent d avoir une idée<br />
du fonctionnement d un programme à partir <strong>de</strong> son co<strong>de</strong> source.<br />
75
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Chapitre 8 - Conclusion et perspectives<br />
Pour conclure, nous résumons dans un premier temps ce qui a été vu tout au long <strong>de</strong> ce<br />
mémoire, puis nous présentons les perspectives pour notre projet d analyse <strong>dynamique</strong> <strong>de</strong><br />
données, avec toutes les améliorations pouvant à terme faire que cet outil soit une réelle ai<strong>de</strong> pour<br />
les développeurs du langage C.<br />
Nous avons présenté dans les premiers chapitres l intérêt <strong>de</strong> ce projet, à savoir permettre aux<br />
programmeurs <strong>de</strong> connaître la trace <strong>de</strong>s programmes C qu ils développent ou qui ont été<br />
développés par un tiers et dont la taille en lignes <strong>de</strong> co<strong>de</strong>s est trop importante pour en<br />
comprendre aisément le fonctionnement. Ainsi, exploiter le programme source pendant son<br />
exécution pour en générer une représentation graphique <strong>de</strong>s dépendances <strong>de</strong>s données qui y sont<br />
manipulées, permet d apporter <strong>de</strong>s informations précises sur le comportement du programme.<br />
Ceci peut également ai<strong>de</strong>r le programmeur à détecter <strong>de</strong>s disfonctionnements dans le<br />
déroulement <strong>de</strong> son exécution, notamment lorsque le programme se comporte <strong>de</strong> manière<br />
différente <strong>de</strong> celle recherchée par son concepteur tout en donnant un résultat correct. La<br />
représentation graphique <strong>de</strong>s dépendances entre les données d un programme peut également<br />
ai<strong>de</strong>r les développeurs dans leur travail d optimisation <strong>de</strong> co<strong>de</strong>.<br />
Pour réaliser notre programme d analyse <strong>dynamique</strong> <strong>de</strong> programmes C, nous nous sommes basés<br />
sur le prototype DDFgraph qui génère <strong>de</strong>s graphes <strong>dynamique</strong>s <strong>de</strong> dépendances pour <strong>de</strong>s<br />
programmes Lisp et qui a été réalisé en modifiant un interprète Lisp. Modifie un compilateur C<br />
représentant un travail considérable, difficile à envisager dans le cadre <strong>de</strong> ce projet. Nous avons<br />
alors cherché un interprète du langage C dont la modification était plus abordable. Puis nous<br />
avons testé les différents interprètes C existant dans le domaine public, EiC qui s est alors avéré le<br />
plus conforme à nos attentes.<br />
Nous avons alors entrepris d en comprendre le fonctionnement, pour ensuite modifier son<br />
option <strong>de</strong> trace afin qu elle génère plus d informations que dans sa version initiale. Nous avons<br />
alors pu obtenir grâce à cette technique <strong>de</strong>s informations telles que les dépendances entre<br />
variables entières, les appels <strong>de</strong> fonctions, les conditions et les boucles. Nous avons enregistré ces<br />
informations dans une base <strong>de</strong> données que nous avons ensuite exploitée à l ai<strong>de</strong> d un script awk.<br />
Puis nous avons utilisé certaines fonctionnalités <strong>de</strong> l outil Dot pour obtenir un affichage<br />
graphique <strong>de</strong>s dépendances entres les données, avec une échelle d enchaînement <strong>de</strong>s instruction<br />
et quelques règles d affichage. Nous avons également automatisé la génération <strong>de</strong> base <strong>de</strong> donnée<br />
ainsi que du graphe grâce à un script Shell.<br />
Notre technique d extraction <strong>dynamique</strong> <strong>de</strong> données basée sur l interprète EiC, présente <strong>de</strong>s<br />
avantages tels qu une possibilité <strong>de</strong> gestion <strong>de</strong> l ensemble du langage C, et la possibilité <strong>de</strong><br />
portabilité <strong>de</strong> notre outil sur un bon nombre <strong>de</strong> systèmes. De plus, l automatisation <strong>de</strong> la<br />
génération <strong>de</strong>s graphes, avec le script Shell, rend notre outil simple d utilisation. La représentation<br />
graphique suivant une échelle d exécution <strong>de</strong>s instructions, permet au développeur <strong>de</strong> tracer<br />
visuellement son co<strong>de</strong> source <strong>de</strong> manière très précise.<br />
Bien que notre outil soit fonctionnel pour <strong>de</strong>s cas simples <strong>de</strong> programmes C, il présente <strong>de</strong>s<br />
limites que nous voyons en section 8.1. Nous voyons également à la section 8.2 quelques<br />
améliorations possibles à notre outil, puis nous concluons en présentant les perspectives pour ce<br />
projet.<br />
76
Chapitre 8 - Conclusion et perspectives<br />
8.1. Limites <strong>de</strong> notre outil d analyse <strong>dynamique</strong> <strong>de</strong><br />
programmes C<br />
Notre outil, comme nous l avons vu tout au long <strong>de</strong> ce mémoire, présente <strong>de</strong>s limites <strong>de</strong><br />
différents ordres. En effet, notre outil, puisque basé sur les informations extraites par l interprète<br />
EiC nous limite pour les capacités <strong>de</strong> ce <strong>de</strong>rnier. Comme nous l avons montré au chapitre 3, EiC<br />
est le seul interprète du domaine public qui soit actuellement capable <strong>de</strong> prendre en charge<br />
l ensemble <strong>de</strong>s spécificités du langage C, mis-à-part la librairie standard du C . De plus,<br />
l outil EiC n étant plus développé <strong>de</strong>puis 2000, sa documentation n étant <strong>de</strong> plus pas finie, nous<br />
<strong>de</strong>vons en comprendre le fonctionnement par nos propres tests et analyses.<br />
Mis à part ces légères limites dues à l interprète utilisé, nous avons relevé d autres limites. Nous<br />
en énumérons les plus importantes ci-<strong>de</strong>ssous :<br />
Notre outil ne prend pas en charge toutes les sépcificités du langage C, il n est donc pas<br />
encore capable d analyser <strong>de</strong>s instructions switch, les structures, les unions, les pointeurs,<br />
ou encore les fonctions récursives.<br />
Notre numérotation <strong>de</strong>s lignes d instructions n est pas encore au point pour gérer les cas<br />
complexes d instructions.<br />
Notre base <strong>de</strong> données ne contient pas encore toutes les informations pour pouvoir<br />
établir <strong>de</strong>s liens spécifiques entre les données, tels que les liens entre les variables locales<br />
et la fonction dans lesquels elles sont définies. Seule la première variable est reliée à la<br />
fonction actuellement.<br />
La représentation graphique <strong>de</strong>s dépendances entre données ne représente pas toutes les<br />
règles <strong>de</strong> dépendances entres les données d un programme C. L affichage <strong>de</strong>s appels <strong>de</strong><br />
fonctions et <strong>de</strong>s tableaux n est pas encore bien géré.<br />
Nous présentons dans la section 8.3.1 les améliorations possibles pour le premier point, les<br />
améliorations concernant les second et troisième points sont abordées à la section 8.2.2 et enfin,<br />
le troisième point est traité dans la section 8.2.3.<br />
8.2. Améliorations possibles<br />
Dans cette section nous voyons quelles améliorations peuvent être apportées à notre outil, dans<br />
les prochains travaux ainsi que les améliorations pouvant rendre notre outil à terme plus complet.<br />
8.2.1. Prise en charge <strong>de</strong>s spécificités du langage C<br />
Pour que notre outil puisse analyser tout programme C, nous <strong>de</strong>vons étendre ses capacités <strong>de</strong><br />
gestion <strong>de</strong>s autres caractéristiques du langage C. Les extensions les plus simples à faire dans un<br />
premier temps consistent à reproduire le modèle <strong>de</strong> génération <strong>de</strong> lignes <strong>de</strong> base <strong>de</strong> données au<br />
format Def et Use pour les variables entières, pour les autres types. Pour cela, il suffit d ajouter<br />
77
Chapitre 8 - Conclusion et perspectives<br />
dans les co<strong>de</strong>s opérateurs nommés rval 24 une ligne <strong>de</strong><br />
printf(« Use... ), et une ligne <strong>de</strong> printf(« Def ) pour ceux dont le nom est <strong>de</strong> la<br />
forme sto 25 . Il suffirait alors d adapter le format <strong>de</strong>s valeurs<br />
retournées par le printf à celles manipulée par le co<strong>de</strong> opérateur chaine <strong>de</strong> caractère (par<br />
exemple printf(« ..%s..,..,variable <strong>de</strong> type char );).<br />
Un autre point d extension nécessitant <strong>de</strong> reproduire ce que nous avons déjà fait concerne les<br />
opérateurs <strong>de</strong> comparaisons. En effet, notre outil n affiche les n uds <strong>de</strong> conditions que pour<br />
celles effectuant une comparaison entre <strong>de</strong>ux entiers avec l opérateur «< ». Pour étendre cela aux<br />
autres opérateurs du C, il suffit d insérer un printf générant une ligne <strong>de</strong> type Cond, pour la<br />
base <strong>de</strong> données, dans tous les co<strong>de</strong>s opérateurs gérant <strong>de</strong>s entiers dans un premier temps<br />
nommés tels que leint pour
Chapitre 8 - Conclusion et perspectives<br />
rvalint (cf. section 5.1.2.2) mais cette fois-ci pour l appel d une fonction, effectué par le co<strong>de</strong><br />
opérateur eiccall. Notre graphe doit également être amélioré pour afficher ce type <strong>de</strong> lien qui<br />
pourrait d ailleur avoir une couleur spécifique.<br />
Il faudrait également tester le comportement <strong>de</strong> notre système <strong>de</strong> numérotation pour les cas<br />
d appels <strong>de</strong> fonctions récursives, et adapter ce <strong>de</strong>rnier aux cas d appels complexes.<br />
Il serait également intéressant d intégrer la structure d instruction que nous avons introduit dans<br />
le co<strong>de</strong> source <strong>de</strong> EiC (cf. section 5.1.3), aux structures <strong>de</strong> données existantes donc gérées par<br />
EiC, ceci nous éviterait <strong>de</strong> <strong>de</strong>voir pré-initialiser les compteurs d appels pour un nombre défini<br />
d instructions, alors que EiC n impose aucune limite quant au nombre d instructions exécutables.<br />
8.2.3. La représentation graphique<br />
Notre représentation graphique affiche, dans le cas <strong>de</strong> <strong>de</strong>ux variables définies dans une fonction,<br />
un lien du nom <strong>de</strong> cetet fonction vers la première variable définie (cf.exemple <strong>de</strong> la figure 24).<br />
Pour remédier à ce problème d affichage, nous <strong>de</strong>vons améliorer notre script awk pour qu il<br />
génère un lien entre la fonction et chacune <strong>de</strong>s variables qui y sont définies localement.<br />
Un autre point à améliorer dans la représentation graphique est l affichage <strong>de</strong>s informations sur<br />
les variables passées en argument, car nous avons dans la base <strong>de</strong> données les bons i<strong>de</strong>ntifiants <strong>de</strong><br />
ces variables mais ceux-ci sont considérés sur le graphe généré comme une seule variable (cf.<br />
section 6.3.2). Nous récupérons également leurs valeurs dans la base <strong>de</strong> données mais ces<br />
<strong>de</strong>rnières ne sont pas encore représentées dans le graphe <strong>de</strong> dépendances <strong>de</strong> données.<br />
Comme nous l avons vu dans le chapitre 6, le graphe que nous générons suit une échelle<br />
d enchaînement <strong>de</strong>s instructions suivant leur exécution. Ceci peut générer <strong>de</strong>s graphes en hauteur<br />
et nous amener à parcourir le graphe tel un co<strong>de</strong> source, ce qui pourrait être également fastidieux<br />
pour <strong>de</strong>s co<strong>de</strong>s avec un grand nombre <strong>de</strong> lignes d instructions. Il faudrait alors s inspirer du<br />
travail réalisé pour l outil DDFgraph pour compacter l affichage [BAL 03], ou encore permettre<br />
au développeur <strong>de</strong> générer <strong>de</strong>s graphes pour <strong>de</strong>s sections <strong>de</strong> co<strong>de</strong> source avec les autres<br />
instructions représentées en un seul n ud, par exemple.<br />
8.2.4. Vers un outil complet d analyse <strong>dynamique</strong><br />
Notre outil <strong>de</strong>vra à terme être capable d afficher le graphe <strong>de</strong> tout programme C, avec la gestion<br />
<strong>de</strong>s cas d instructions complexes (comme par exemple le cas d une condition contenant l appel à<br />
une fonction pouvant <strong>de</strong> plus être récursive).<br />
Pour cela, nous <strong>de</strong>vons d une part étendre ses capacités en se basant sur la base <strong>de</strong> données<br />
générée actuellement, pour en extraire <strong>de</strong>s graphes <strong>de</strong> dépendances plus spécifiques pour<br />
représenter les dépendances entre les variables manipulées ou entre fonctions appelées. Nous<br />
<strong>de</strong>vons d autre part, créer <strong>de</strong> nouvelles bases <strong>de</strong> données sépcifiques à <strong>de</strong>s structures, <strong>de</strong>s<br />
pointeurs ou encore <strong>de</strong>s tableaux avec les valeurs qui leur sont affectées pendant l exécution du<br />
programme.<br />
Nous envisageons également <strong>de</strong> réaliser une interface graphique à notre outil, permettant ainsi à<br />
l utilisateur <strong>de</strong> charger son co<strong>de</strong> source, et <strong>de</strong> choisir suivant ses besoins le type d affichage voulu,<br />
79
Chapitre 8 - Conclusion et perspectives<br />
ainsi que la suite d intructions qu il veut tracer. Il pourra alors visualiser un graphe con<strong>de</strong>nsé pour<br />
les instructions non séléctionnées avant l exécution du co<strong>de</strong> source mais par contre le détail <strong>de</strong><br />
celles choisies. Cette représentation graphique serait affichée dans une fenêtre adjacente à celle du<br />
co<strong>de</strong> source, comme c est le cas pour l outil JFL C (cf. section 3.3).<br />
A terme, nous envisageons d intégrer à cette interface la possibilité <strong>de</strong> visualiser le graphe <strong>de</strong><br />
dépendance en temps réel pendant l exécution du co<strong>de</strong> source C, offrant ainsi au <strong>de</strong>veloppeur la<br />
possibilité d arrêter cette exécution à tout instant et d éxaminer en détail les valeurs en cours <strong>de</strong><br />
manipulation. Nous y intégrerons également une option <strong>de</strong> recherche suivant le numéro <strong>de</strong> ligne,<br />
<strong>de</strong> mots clés, ou encore <strong>de</strong> type <strong>de</strong> n uds, qui permettera <strong>de</strong> mettre en évi<strong>de</strong>nce sur le graphe <strong>de</strong><br />
dépendances les résultats <strong>de</strong> la recherche sous un format visuellement repérable, en coloriant les<br />
n uds trouvés avec leurs liens avec une couleur spécifique par exemple.<br />
Gageons qu un tel outil sera alors aussi indispensable qu un débuggeur à l heure actuelle.<br />
80
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Bibliographie<br />
[AGR 90]<br />
[BAL 05]<br />
[BAL 01]<br />
[BAL 00]<br />
[BAL 03]<br />
H. Agrawal and J. Horgan, Dynamic program slicing<br />
Proceedings of the ACM SIG PLAN 90, Conference on Programming Languages<br />
Design and Implementation, White Plains (New York), 1990.<br />
Françoise Balmas, Harald Wertz and <strong>Rim</strong> <strong>Chaabane</strong>, Visualizing dynamic data<br />
<strong>de</strong>pen<strong>de</strong>nces as a help to maintain programs<br />
International Conference on Software Maintenance, poster session, Budapest<br />
(Hungary), 2005.<br />
Françoise Balmas and Harald Wertz, I<strong>de</strong>ntifying information needs for program<br />
un<strong>de</strong>rstanding: an iterative approach<br />
7 th Int. Conf. on Reverse Engineering for Information Systems, Lyon<br />
(France), 2005.<br />
Françoise Balmas and Harald Wertz, I<strong>de</strong>ntifying information nee<strong>de</strong>d to un<strong>de</strong>rstand<br />
programs: preliminary observations<br />
Research Report, University <strong>Paris</strong> 8, St Denis (France), July 2000.<br />
Françoise Balmas, Displaying <strong>de</strong>pen<strong>de</strong>nce graphs: a hierarchical approach<br />
Journal of Software Maintenance: Research and Practice, 00:1-37, 2003.<br />
[BEL 05] Fares Belhadj, Outils pour développeurs : Graphviz Dot<br />
Support <strong>de</strong> cours, Université <strong>Paris</strong> 8, St. Denis (France), 2005.<br />
[BRE 98]<br />
[BRE 00]<br />
[BRE 03]<br />
[DEL 03]<br />
[DON 03]<br />
[ENG 03]<br />
[FEN 97]<br />
Neil V. Brewster, Creation of a Software Bookshelf for the Linux operating system<br />
Thesis for the <strong>de</strong>gree Bachelor of Applied Science, University of Toronto,<br />
Toronto (Canada), 1998.<br />
Edmon J. Breen, The embeddable/ extensible interactive, pointer-safe, byteco<strong>de</strong> C<br />
interpreter/compiler<br />
http://eic.sourceforge.net/in<strong>de</strong>x.html, 2000.<br />
Edmond J. Breen, Extensible Interactive C<br />
http://eic.sourceforge.net/documentation/, January 2003.<br />
Clau<strong>de</strong> Delannoy, Langage C<br />
2 ème edition, Eyrolles, <strong>Paris</strong>, 2003.<br />
Steve Donovan, The Un<strong>de</strong>rC Development Project<br />
http://home.mweb.co.za/sd/sdonovan/un<strong>de</strong>rc.html, 2001-2003.<br />
Vadim Engelson, Call Graph Drawing Interface<br />
http://www.ida.liu.se/~va<strong>de</strong>n/cgdi/, 2003<br />
Jay Fenlason and Richard Stallman, Gprof: The GNU profiler<br />
http://www.gnu.org/software/binutils/manual/gprof-<br />
2.9.1/html_mono/gprof.html, 1997.<br />
82
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
[GAN 02]<br />
[GOT 05]<br />
[GRE 97]<br />
[GRU 00]<br />
Em<strong>de</strong>n Gansner, Eleftherios Koutsofios et Stephen North, Drawing graphs with Dot<br />
http://www.graphviz.org/pub/scm/graphviz2/doc/info/lang.html, 2002.<br />
Masaharu Goto, Rene Brun et Fons Ra<strong>de</strong>makers, The Cint C/C++ Interpreter<br />
http://root.cern.ch/root/Cint.html, 2005.<br />
Patrick Greussay, Cours d Intelligence A rtificielle<br />
DEA IAOC, Université <strong>Paris</strong>8, St. Denis (France), 1997<br />
Dick Grune, Henri E. Bal, Ceriel J.H. Jacobs, Koen G. Langendoen, Compilateurs<br />
Édition Dunod, <strong>Paris</strong>, 2000.<br />
[HAT 97] L. Hatton, Does OO sync with the way we think ?<br />
IEEE Software, Vol. 15, No. 3, p. 46-54, May/June 1998.<br />
[JAH 00]<br />
[KOR 88]<br />
[LUC 05]<br />
[LAN 05]<br />
[LIN1 93]<br />
[LIN2 93]<br />
[PLO 02]<br />
[RIF 02]<br />
[SAN 95]<br />
[SOF 05]<br />
Erwan Jahier, A nalyse <strong>dynamique</strong> <strong>de</strong> programmes: mise en uvre automatisée d analyseurs<br />
performants et spécifications <strong>de</strong> modèles d exécution<br />
Thèse <strong>de</strong> doctorat, INSA <strong>de</strong> Rennes, Rennes (France), 2000.<br />
B. Korel and J. Lasky, Dynamic program slicing<br />
Information Processing Letters, 29(3), p. 155-163, October 1988.<br />
Jean François Lucas, JFL C interprète<br />
http://jflucas.club.fr/Philotechnique/PresentationGeneDeLInterprete2.htm,<br />
2005.<br />
Présentation <strong>de</strong> l analyse <strong>dynamique</strong> du projet LANDE.<br />
http://www.irisa.fr/lan<strong>de</strong>/jensen/ap.html, 2005.<br />
P. Linos, P. Aubet, Laurent Dumas, Y. Helleboid, P. Lejeune & P. Tulula,<br />
Facilitating the Comprehension of C Programs: An Experimental Study<br />
Proceeding of the Second IEEE Workshop on Program Comprehension, Capri<br />
(Italy), p. 55-63, July 1993.<br />
P. Linos, P. Aubet, Laurent Dumas, Y. Helleboid, P. Lejeune & P. Tulula, CARE:<br />
An environment for Un<strong>de</strong>rstanding and Re-engineering C Programs<br />
Proceeding on Program Comprehension, Montreal (Canada), p. 130-139,<br />
September 1993.<br />
Damien Ploix, Analogical Representations of Programs<br />
First IEEE International Workshop on Visualizing Software for Un<strong>de</strong>rstanding<br />
and Analysis, p 61-69, June 2002.<br />
Jean-Marie Rifflet, La programmation sous UNIX<br />
3 ème édition, Ediscience, <strong>Paris</strong>, 2002.<br />
G. San<strong>de</strong>r, VCG: Visualization of Compiler Graphs<br />
Universitaet <strong>de</strong>s Saarlan<strong>de</strong>s, Saarbruecken (Germany), February 1995.<br />
SoftIntegration Corporation, CH Standard Edition<br />
http://www.softintegration.com/products/chstandard/, Copyright 2001-2005.<br />
83
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
[SYS 01]<br />
[WIN 72]<br />
T. Systä, An environment for reverse engineering of java software systems<br />
Softare Practice and Experience, 31(4), p 371-394, 2001.<br />
Terry Winograd, Un<strong>de</strong>rstanding Natural Language<br />
Aca<strong>de</strong>mic Press, New York (New York), 1972.<br />
84
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
85
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Annexes<br />
ANNEXE - I - PROGRAMMES DE TESTS DES INTERPRETES C ET TRACES DE TESTS .....................88<br />
ANNEXE - II - COMMANDES INTERNES A EIC EN MODE INTERACTIF ..........................................91<br />
ANNEXE - III - DIRECTIVES D APPEL A EIC EN MODE BATCH......................................................93<br />
ANNEXE - IV - SCRIPT SHELL "EIC_ADPC.SH ..............................................................................95<br />
ANNEXE - V - SCRIPTS AWK............................................................................................................98<br />
ANNEXE - VI - EXTRAITS DU CODE SOURCE MODIFIE DE EIC......................................................99<br />
86
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
87
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Annexe - I -<br />
Programmes <strong>de</strong> tests <strong>de</strong>s interprètes C et traces <strong>de</strong> tests<br />
TRACE D EXÉCUTION DE CINT AVEC L OPTION DE TRACE<br />
POUR LE PROGRAMME DE CALCUL D UNE FACTORIELLE<br />
--------------------------------------------<br />
Programme <strong>de</strong> calcul d une factorielle : fact.c<br />
1 /* fonction <strong>de</strong> calcul du factoriel d'un nombre => recurrence */<br />
2 #inclu<strong>de</strong> <br />
3<br />
4 unsigned int f, x;<br />
5 unsigned int factoriel(unsigned int a);<br />
6 int main(int argc, char *argv[])<br />
7 {<br />
8 puts("Entrez une valeur entière entre 1 et 8 :");<br />
9 scanf("%d", &x);<br />
10 if (x>8 || x
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
89
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
FICHIER MAIN DE LLISP<br />
--------------------------------------------<br />
1 /*<br />
2 * main.c<br />
3 */<br />
4<br />
5 #inclu<strong>de</strong> "llisp/main.h"<br />
6 #inclu<strong>de</strong> "llisp/mem.c"<br />
7 #inclu<strong>de</strong> "llisp/print.c"<br />
8 #inclu<strong>de</strong> "llisp/std.c"<br />
9 #inclu<strong>de</strong> "llisp/read.c"<br />
10 #inclu<strong>de</strong> "llisp/eval.c"<br />
11<br />
12 extern int sp;<br />
13 extern jmp_buf jmp_top;<br />
14 extern jmp_buf jmp_file;<br />
15 extern FILE *Stdin;<br />
16 extern FILE *File;<br />
17 extern void unbind();<br />
18 extern void lisp_print();<br />
19 extern void lisp_read();<br />
20 extern void eval();<br />
21 extern int int_read(char ch);<br />
22 extern void obj_print(int obj);<br />
23 extern void init_listes();<br />
24<br />
25 void toplevel()<br />
26 {<br />
27 for ( ;; )<br />
28 {<br />
29 printf ("? ");<br />
30 fflush (stdout);<br />
31 lisp_read();<br />
32 eval();<br />
33 printf ("= ");<br />
34 lisp_print();<br />
35 putchar ('\n');<br />
36 fflush (stdout);<br />
37 }<br />
38 }<br />
39<br />
40 /* routine d'erreur : obj est un entier, adresse (in<strong>de</strong>x dans mem) d'un elt */<br />
41 void err(char *fmt,int obj)<br />
42 {<br />
43 int i;<br />
44 printf (fmt, obj);<br />
45 while (sp > B_STACK)<br />
46 if (pop(i) == -2)<br />
47 unbind();<br />
48 longjmp (jmp_top, 0);<br />
49 }<br />
50<br />
51 void err2(char *fmt)<br />
52 {<br />
53 int i;<br />
54 printf (fmt);<br />
55 while (sp > B_STACK)<br />
56 if (pop(i) == -2)<br />
57 unbind();<br />
58 longjmp (jmp_top, 0);<br />
59 }<br />
60<br />
61 /* routine d'erreur : obj est une chaine (p_name) d'un elt */<br />
62 void err_s(char *fmt,char *obj)<br />
63 {<br />
64 int i;<br />
65 printf (fmt, obj);<br />
66 while (sp > B_STACK)<br />
90
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
67 if (pop(i) == -2)<br />
68 unbind();<br />
69 longjmp (jmp_top, 0);<br />
70 }<br />
71<br />
72 void load (char *name)<br />
73 {<br />
74 if ((File = fopen (name, "r")) == NULL)<br />
75 {<br />
76 printf ("Le fichier %s n'existe pas\n", name);<br />
77 }<br />
78 else<br />
79 {<br />
80 printf ("Chargement <strong>de</strong> %s\n", name);<br />
81 Stdin = File;<br />
82 if (setjmp(jmp_file))<br />
83 goto fini;<br />
84 while (!feof(Stdin))<br />
85 {<br />
86 lisp_read();<br />
87 eval();<br />
88 lisp_print();<br />
89 putchar ('\n');<br />
90 }<br />
91 fini:<br />
92 fclose (File);<br />
93 Stdin = stdin;<br />
94 init_read();<br />
95 }<br />
96 }<br />
97<br />
98 void <strong>de</strong>bug(char *s,int x)<br />
99 {<br />
100 printf("%s", s);<br />
101 obj_print (x);<br />
102 putchar ('\n');<br />
103 }<br />
104<br />
105<br />
106 int main()<br />
107 {<br />
108 static int nbtop = 0;<br />
109 init_listes();<br />
110 init_atomes();<br />
111 setjmp (jmp_top);<br />
112 init_read();<br />
113 init_stack();<br />
114 Stdin = stdin;<br />
115 if (++nbtop == 1)<br />
116 load ("llisp/llisp.ini");<br />
117 toplevel();<br />
118 return 0;<br />
119 }<br />
120<br />
121 /* FIN <strong>de</strong> fichier */<br />
122<br />
91
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Annexe - II -<br />
Comman<strong>de</strong>s internes à EiC en mo<strong>de</strong> interactif<br />
---------------------------------------------------------------------------<br />
EiC-COMMAND<br />
SUMMARY DESCRIPTION<br />
---------------------------------------------------------------------------<br />
:-I path<br />
Append path to the inclu<strong>de</strong>-file search list.<br />
:-L<br />
List search paths.<br />
:-R path<br />
Remove path from the inclu<strong>de</strong>-file search list.<br />
:clear fname<br />
Removes the contents of file fname from EiC.<br />
:exit<br />
Terminates an EiC session.<br />
:files<br />
Display the names of all inclu<strong>de</strong>d files.<br />
:files fname<br />
Summarize the contents of the inclu<strong>de</strong>d file `fname'.<br />
:gen fname<br />
Generates EiC interface of the inclu<strong>de</strong>d file `fname'.<br />
:gen fname [] Places the interface in outfile<br />
:gen fname 4<br />
Generates EiC interface with 4 levels of multiplexing.<br />
:help<br />
Display summary of EiC commands.<br />
:history<br />
List the history of all input commands.<br />
:inclu<strong>de</strong>s<br />
Display path of inclu<strong>de</strong> files when loa<strong>de</strong>d.<br />
:interpreter<br />
Execute input commands. By <strong>de</strong>fault it is on.<br />
:listco<strong>de</strong><br />
List stack co<strong>de</strong>.<br />
:listco<strong>de</strong> linenums<br />
List stack co<strong>de</strong> with associated line numbers.<br />
:memdump<br />
Show potential memory leaks.<br />
:reset<br />
Reset EiC back to its start state.<br />
:reset here<br />
Set the `reset' state to EiC's current state.<br />
:rm dddd<br />
Remove memory item dddd, which is a constant integer<br />
value.<br />
:rm f Removes f's <strong>de</strong>finition from the symbol tables.<br />
:show f<br />
Shows type or macro <strong>de</strong>finition of `f'.<br />
:showline<br />
Show input line after macro expansion.<br />
:status<br />
Display the status of the toggle switches.<br />
:timer<br />
Time in seconds of execution.<br />
:trace<br />
Trace function calls and line numbers during co<strong>de</strong><br />
execution.<br />
:trace funcs<br />
Trace function calls only during co<strong>de</strong> execution.<br />
:variables<br />
Display <strong>de</strong>clared variables and interpreter-ed function<br />
names.<br />
:variables tags<br />
Display the tag i<strong>de</strong>ntifiers.<br />
:variables type-name Display variables of type `type-name'.<br />
:verbose<br />
Suppresses EiC's copyright and warning messages on start<br />
up.<br />
-----------------------------------------------------------------------------------<br />
92
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
93
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Annexe - III -<br />
Directiv es d appel à EiC en mo<strong>de</strong> batch<br />
To start eic, type eic.<br />
To exit eic, type :exit.<br />
Usage:<br />
eic [-Ipath] [-Dname[=var]] -[hHvVcCrR] [[file] [fileargs]]<br />
Options:<br />
C preprocessor directives:<br />
-Ipath<br />
search for inclu<strong>de</strong> files in path<br />
-Dname <strong>de</strong>fine a symbolic name to the value 1<br />
-Dname=var <strong>de</strong>fine a symbolic name to the value var<br />
Note, there is no spaces allowed<br />
EiC directives:<br />
-h -H causes this usage to be displayed<br />
-v V print EiC's Log information<br />
-p showline<br />
-P show path of inclu<strong>de</strong> files<br />
-t -T turns trace on<br />
-c -C turns timer on<br />
-e echo HTML mo<strong>de</strong><br />
-r restart EiC. Causes EiC to be re initiated<br />
from the contents of EiChist.lst file<br />
-R same as `r', but prompts the user to accept<br />
or reject each input line first<br />
-s -S run silently<br />
-f run in script mo<strong>de</strong><br />
-n no history file<br />
-N don't use any startup.h files<br />
-A Non-interactive-mo<strong>de</strong><br />
file<br />
EiC will execute `file' and then stop; for example:<br />
% eic foo.c<br />
fileargs command line arguments, which get passed onto file<br />
94
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
95
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Annexe - IV -<br />
Script shell "eic_adpc.sh<br />
# eic_adpc.sh<br />
# --------------------------------------------------------<br />
# Fichier Shell qui lance l'execution <strong>de</strong> EiC en mo<strong>de</strong> batch<br />
# avec l'option <strong>de</strong> trace d'un programme.<br />
#! /usr/bin/sh<br />
RACINE="$HOME/bin"<br />
PROGSC="$HOME/bin/co<strong>de</strong>s_test"<br />
DATA="$HOME/bin/datas"<br />
DOT="$HOME/bin/dot"<br />
GRAPH="$HOME/bin/graphs"<br />
if [ -z "$1" ]<br />
then<br />
echo "Veuilez saisir un nom <strong>de</strong> fichier en argument."<br />
exit 1<br />
else<br />
extension=`echo $1 | cut -f2 -d"."`<br />
if [ "$extension" != c ]<br />
then<br />
echo "Le fichier n'est pas d'extension .c ! saisissez un nom vali<strong>de</strong> <strong>de</strong><br />
fichier C."<br />
else<br />
if [ -r "$PROGSC/$1" ]<br />
then<br />
fichier=`echo $1 | cut -f1 -d "."`<br />
./eic -t $PROGSC/$1 > $DATA/tmp.data<br />
awk -f $RACINE/formaterdata.awk $DATA/tmp.data ><br />
$DATA/$fichier.data<br />
awk -f $RACINE/graph1.awk $DATA/$fichier.data ><br />
$DOT/$fichier.dot<br />
awk -f $RACINE/graph2.awk $DATA/$fichier.data >><br />
$DOT/$fichier.dot<br />
dot -Tps -o $GRAPH/$fichier.ps $DOT/$fichier.dot<br />
gv $GRAPH/$fichier.ps<br />
else<br />
echo "Le fichier n'existe pas ou n'est pas en droit <strong>de</strong> lecture."<br />
fi<br />
fi<br />
fi<br />
96
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
97
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Annexe - V - Scripts awk<br />
# formaterdata.awk<br />
# --------------------------------------------------------<br />
# Supprime la base <strong>de</strong> donnee pour ne gar<strong>de</strong>r que les données<br />
# du programme a analyser<br />
/co<strong>de</strong>s_test\//,/EiC/ { print $0 }<br />
# graph1.awk<br />
# --------------------------------------------------------<br />
# Genere les premieres lignes du fichier .dot<br />
BEGIN { printf "digraph G { ranksep=.75; size=\"7.5,7.5\";\n{\nno<strong>de</strong><br />
[shape=plaintext, fontsize=16];\n" }<br />
# { print }<br />
$1 == "#" { printf "\"%s\" -> ", $2 }<br />
END { printf "\"end\";\n}\n" }<br />
# graph2.awk<br />
# --------------------------------------------------------<br />
# Genere l essentiel du fichier .dot<br />
BEGIN { lastline = " " }<br />
$1 == "main" { printf "{rank = same;\n\"%s:%s\"; \"#%s:%s\";\n}\n\n", $2, $3, $2,<br />
$3<br />
printf "\"#%s:%s\" [label=\"main-%s\", shape=box, color=red]\n", $2,<br />
$3, $3<br />
#printf "\"#%s:%s\" -> ", $2, $3<br />
lastline = "\"#"$2":"$3"\""}<br />
$1 == "Def" { if (lastline != " ") { printf "%s -> \"#%s:%s\"\n\n", lastline, $4,<br />
$5<br />
lastline = " " }<br />
$3 }<br />
printf "{rank = same;\n\"%s:%s\"; \"#%s:%s\";\n}\n", $4, $5, $4, $5<br />
printf "\"#%s:%s\" [label=\"%s=%s\", color=green]\n\n", $4, $5, $2,<br />
$1 == "Use" { printf "\"#%s:%s\" -> \"#%s:%s\"\n", $3, $4, $5, $6 }<br />
$1 == "Call" { i = 4<br />
if (lastline != " ") { printf "%s -> \"#%s:%s\"\n\n", lastline, $2, $3<br />
lastline = "\"#"$2":"$3"\"" }<br />
#printf "\"#%s:%s\"\n", $2, $3<br />
printf "{rank = same;\n\"%s:%s\"; \"#%s:%s\";\n}\n", $2, $3, $2, $3<br />
printf "\"#%s:%s\" [label=\"Call-%s\\n", $2, $3, $3<br />
while (i \"#%s:%s\"\n\n", lastline, $4,<br />
$5<br />
lastline = "\"#"$4":"$5"\"" }<br />
#printf "\"#%s:%s\"\n", $4, $5<br />
98
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
printf "{rank = same;\n\"%s:%s\"; \"#%s:%s\";\n}\n", $4, $5, $4, $5<br />
printf "\"#%s:%s\" [label=\"Cond-%s\\n%s\", shape=diamond, headport=w,<br />
tailport=e]\n", $4, $5, $5, $2<br />
if ($3 == "0") lastline="\"#"$4":"$5"\":e"<br />
else lastline="\"#"$4":"$5"\":w" }<br />
$1 == "Return" { if (lastline != " ") { printf "%s -> \"#%s:%s\"\n\n", lastline, $3,<br />
$4<br />
lastline = "\"#"$3":"$4"\"" }<br />
#printf "\"#%s:%s\"\n", $3, $4<br />
printf "{rank = same;\n\"%s:%s\"; \"#%s:%s\";\n}\n", $3, $4, $3, $4<br />
printf "\"#%s:%s\" [label=\"Return-%s\\n%s\", shape=box]\n", $3, $4,<br />
$4, $2 }<br />
END { printf "\n}\n" }<br />
99
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
Annexe - VI - Extraits du co<strong>de</strong> source modifié <strong>de</strong> EiC<br />
1 /* interpre.c<br />
2 *<br />
3 * (C) Copyright Apr 15 1995, Edmond J. Breen.<br />
4 * ALL RIGHTS RESERVED.<br />
5 * This co<strong>de</strong> may be copied for personal, non-profit use only.<br />
6 *<br />
7 */<br />
8<br />
9 #inclu<strong>de</strong> <br />
10 #inclu<strong>de</strong> <br />
11 #inclu<strong>de</strong> <br />
12 #inclu<strong>de</strong> <br />
13 #inclu<strong>de</strong> <br />
14 #inclu<strong>de</strong> <br />
15 #inclu<strong>de</strong> <br />
16<br />
17 #inclu<strong>de</strong> "MachSet.h"<br />
18 #inclu<strong>de</strong> "global.h"<br />
19 #inclu<strong>de</strong> "xalloc.h"<br />
20 #inclu<strong>de</strong> "lexer.h"<br />
21 #inclu<strong>de</strong> "typemod.h"<br />
22 #inclu<strong>de</strong> "symbol.h"<br />
23 #inclu<strong>de</strong> "func.h"<br />
24 #inclu<strong>de</strong> "typesets.h"<br />
25 #inclu<strong>de</strong> "preproc.h"<br />
26 #inclu<strong>de</strong> "c<strong>de</strong>cl.h"<br />
27 #inclu<strong>de</strong> "emitter.h"<br />
28<br />
29 #inclu<strong>de</strong> "error.h"<br />
30<br />
31 /* make a safe memory block */<br />
32 #<strong>de</strong>fine MASSIGN \<br />
33<br />
34 #<strong>de</strong>fine checkPtr(P,s,i) \<br />
35 if(( (char *)P.p + i ) > (char *) P.ep || P.p < P.sp) {\<br />
36 if(( (char *)P.p + i ) > (char *) P.ep) {\<br />
37 EiC_messageDisplay(s ": attempted beyond allowed access area\n"); }\<br />
38 else\<br />
39 EiC_messageDisplay(s ": attempted before allowed access area\n");\<br />
40 raise(SIGSEGV);\<br />
41 }<br />
42<br />
43<br />
44 #<strong>de</strong>fine FMEM xfree(AR[InSt[p].ext][InSt[p].val.ival].v.p.sp)<br />
45<br />
46 #<strong>de</strong>fine LDA<br />
47<br />
48 #<strong>de</strong>fine LVAL<br />
49<br />
50 #<strong>de</strong>fine stoTYPE(x) AR[InSt[p].ext][InSt[p].val.ival].v.x = STK[ToP].v.x;<br />
51 /*printf("STK[ToP].v.sym->id = %s\n",STK[ToP].v.sym->id);*/<br />
52<br />
53 #<strong>de</strong>fine stoVAL env->LAR[env->lsp].v = STK[ToP].v;\<br />
54 /*printf(" -%d- ",env->LAR[env->lsp].v.ival);*/ \<br />
55 env->lsp++;<br />
56<br />
57 #<strong>de</strong>fine pushVAL _ STK[ToP].v = InSt[p].val;<br />
58 #<strong>de</strong>fine assignTYPE_ env->LAR[env->lsp-1].type = InSt[p].val.p.p<br />
59<br />
60 #<strong>de</strong>fine rvalTYPE(x) STK[ToP].v.x = AR[InSt[p].ext][InSt[p].val.ival].v.x<br />
61<br />
62 #<strong>de</strong>fine drefTYPE(x,y) checkPtr(STK[ToP].v.p,"READ", sizeof(x) );\<br />
100
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
63 STK[ToP].v.y = *(x*)STK[ToP].v.p.p<br />
64<br />
65 #<strong>de</strong>fine refTYPE(x,y) ToP--;\<br />
66 checkPtr(STK[ToP].v.p,"WRITE", sizeof(x) );\<br />
67 *(x*)STK[ToP].v.p.p = STK[ToP+1].v.y;\<br />
68 STK[ToP].v.y = STK[ToP+1].v.y<br />
69<br />
70 #<strong>de</strong>fine refMEM ToP--;\<br />
71 memcpy(STK[ToP].v.p.p,STK[ToP+1].v.p.p,InSt[p].val.ival);\<br />
72 STK[ToP].v.p.sp = STK[ToP].v.p.p;\<br />
73 STK[ToP].v.p.ep = (char*)STK[ToP].v.p.p + InSt[p].val.ival;<br />
74<br />
75 #<strong>de</strong>fine pushTYPE(x) STK[ToP].v.x = InSt[p].val.x;\<br />
76 /*printf("STK[%d].v.ival = %d\n",ToP,STK[ToP].v.ival);*/<br />
77<br />
78 #<strong>de</strong>fine castTYPES(x,y,T) STK[ToP].v.y = (T)STK[ToP].v.x<br />
79<br />
80 #<strong>de</strong>fine negTYPE(x) STK[ToP].v.x = -STK[ToP].v.x<br />
81 #<strong>de</strong>fine addTYPE(x) ToP--; STK[ToP].v.x += STK[ToP+1].v.x<br />
82 #<strong>de</strong>fine subTYPE(x) ToP--; STK[ToP].v.x -= STK[ToP+1].v.x<br />
83 #<strong>de</strong>fine divTYPE(x) ToP--; STK[ToP].v.x /= STK[ToP+1].v.x<br />
84 #<strong>de</strong>fine multTYPE(x) ToP--; STK[ToP].v.x *= STK[ToP+1].v.x<br />
85 #<strong>de</strong>fine modTYPE(x) ToP--; STK[ToP].v.x %= STK[ToP+1].v.x<br />
86 #<strong>de</strong>fine lshtTYPE(x) ToP--; STK[ToP].v.x = STK[ToP+1].v.x<br />
88 #<strong>de</strong>fine ltTYPE(x) ToP--; STK[ToP].v.ival = STK[ToP].v.x < STK[ToP+1].v.x;\<br />
89 if(EiC_traceON) {\<br />
90 cond = STK[ToP].v.ival; \<br />
91 printf("\tCond (%d
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
131 extern int EiC_traceON;<br />
132 extern int EiC_traceFunc;<br />
133 extern int EiC_interActive;<br />
134<br />
135<br />
136 #<strong>de</strong>fine stacksize 200<br />
137 type<strong>de</strong>f AR_t STK_t;<br />
138<br />
139 STK_t *AR[3];<br />
140 size_t ARGC;<br />
141<br />
142 val_t EiC_STaCK_VaLuE;<br />
143<br />
144 void EiC_interpret(environ_t * env)<br />
145 {<br />
146 int p,Jmpu,cond,i;<br />
147 /* Jmpu --> indicateur <strong>de</strong> boucle 1 si dans boucle et 0 sinon */<br />
148 /*int k;<br />
149 symentry_t *sym;<br />
150 */<br />
151 static int cpti;<br />
152 size_t argc;<br />
153 unsigned int ToP;<br />
154 InsT_t *InSt;<br />
155 STK_t *STK, *hold_AR, *hold_AR1;<br />
156<br />
157 /* EXPLANATION OF REGISTERS<br />
158 * ToP stack top;<br />
159 * p program counter;<br />
160 * InSt pointer to instruction set<br />
161 */<br />
162<br />
163 type<strong>de</strong>f struct {<br />
164 int p;<br />
165 unsigned int top;<br />
166 int lsp;<br />
167 long offset;<br />
168 void *file;<br />
169 void *inst;<br />
170 void *ar;<br />
171 } _EiC_jmp_buf;<br />
172<br />
173<br />
174 /* Ajout par <strong>Rim</strong> <strong>Chaabane</strong> rchaabane@free.fr (02/2005 -> 09/2005)<br />
175 Structure qui pour chaque instruction i<strong>de</strong>ntifiée par num_i,<br />
176 permet <strong>de</strong> compter so nombre d'appels cptr_a, cette structure<br />
177 permet également d'enregistrer le numéro <strong>de</strong> la <strong>de</strong>rnière<br />
178 instruction ou la variable est appelée & le nombre d'appels<br />
179 a cette <strong>de</strong>rniere<br />
180<br />
181 */<br />
182 type<strong>de</strong>f struct {<br />
183 int num_i; /* numero d'instruction */<br />
184 unsigned int cptr_a; /* compteur d'appels d'instructions */<br />
185 int <strong>de</strong>rnier_appel; /* enregistre l'id <strong>de</strong> la <strong>de</strong>rnière ligne<br />
d'instruction ou est appelée la var */<br />
186 int <strong>de</strong>rnier_pass; /* enregistre le num <strong>de</strong> passage <strong>de</strong> l'instruction ou<br />
est appelée la var */<br />
187 } inf_inst;<br />
188<br />
189 extern int EiC_TIMER;<br />
190 extern void EiC_showvalue(AR_t *);<br />
191 extern symentry_t * EiC_lookup(char nspace, char *id);<br />
192<br />
193 int stksz = stacksize;<br />
194 int lastln = -1;<br />
195 eicstack_t names = {0, NULL};<br />
196 val_t v;<br />
102
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
197 void *vp; /* for temporay use only */<br />
198<br />
199 #<strong>de</strong>fine N 50<br />
200 inf_inst T[N];<br />
201 /* Initialisation a 0 <strong>de</strong> la valeur <strong>de</strong> cptr_a et le numero d instruction */<br />
202 for (i=0; iAR;<br />
215 AR[1] = &env->LAR[env->lsp];<br />
216 InSt = env->CODE.inst;<br />
217 ToP = 0;<br />
218 p = 0;<br />
219<br />
220 STK[ToP].v.dval = 0;<br />
221 ON = 1;<br />
222<br />
223 start = clock();<br />
224 EiC_CurrentFile = co<strong>de</strong>Name(&env->CODE);<br />
225 /*Jmpu = 0;*/<br />
226<br />
227 _while (ON) {<br />
228 _/* renvoi tjs le nom du fichier pr var.c_<br />
229 for(k=0;kstab.n;++k) {<br />
230 _ _printf("stab->strs[%d]=%s\n",k,env->stab.strs[k]);<br />
231 _}<br />
232 _*/<br />
233 _if(EiC_CurrentLine != InSt[p].line) /* for error reporting */<br />
234 EiC_CurrentLine = InSt[p].line; /* purposes only */<br />
235 if(EiC_traceON) {<br />
236<br />
237 if(InSt[p].opco<strong>de</strong> == eiccall) {<br />
238 EiC_eicpush(&names,v);<br />
239 v.p.p = ((symentry_t *) STK[ToP - 1].v.p.p)->id;<br />
240 lastln = InSt[p].line;<br />
241 }<br />
242 if(!EiC_traceFunc && lastln != InSt[p].line && InSt[p].line) {<br />
243 lastln = InSt[p].line;<br />
244 cpti++;<br />
245 T[lastln].cptr_a ++;<br />
246 _printf("\n# %d:%d <br />
\n",lastln,T[lastln].cptr_a,(char*)EiC_CurrentFile);<br />
247 _if (T[lastln].num_i == 0) T[lastln].num_i = cpti; _<br />
248 }<br />
249<br />
250 }<br />
251<br />
252 switch (InSt[p].opco<strong>de</strong>) {<br />
253 case bump:<br />
254 /*if(EiC_traceON) printf("pump\n");*/<br />
255 AdjustTop(InSt[p].val.ival);<br />
256 ToP += InSt[p].val.ival;<br />
257 break;<br />
258 case jmpFint:<br />
259 jmpfTYPE(ival); if(EiC_traceON) printf("jmpftype ival \n");<br />
260 break;<br />
261 case jmpFlng:<br />
262 jmpfTYPE(lval); if(EiC_traceON) printf("jmpftype lval\n");<br />
263 break;<br />
103
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
264 case jmpFdbl:<br />
265 jmpfTYPE(dval); if(EiC_traceON) printf("jmpftype dval\n");<br />
266 break;<br />
267 case jmpFptr:<br />
268 jmpfTYPE(p.p); if(EiC_traceON) {printf("jmpftype p.p\n");}<br />
269 break;<br />
270 case jmpFllng:<br />
271 jmpfTYPE(llval); /*if(EiC_traceON) {printf("jmpftype<br />
llval"); }*/<br />
272 break;<br />
273<br />
274 case jmpTint:<br />
275 jmptTYPE(ival); /*if(EiC_traceON) {printf("jmptTint "); }*/<br />
276 break;<br />
277 case jmpTlng:<br />
278 jmptTYPE(lval); /*if(EiC_traceON) {printf("jmpTlng "); }*/<br />
279 break;<br />
280 case jmpTdbl:<br />
281 jmptTYPE(dval);/* if(EiC_traceON) {printf("jmpTdbl "); }*/<br />
282 break;<br />
283 case jmpTptr:<br />
284 jmptTYPE(p.p);/*if(EiC_traceON) { printf("jmpTptr "); }*/<br />
285 break;<br />
286 case jmpTllng:<br />
287 jmptTYPE(llval); /*if(EiC_traceON) {printf("jmpTllng "); }*/<br />
288 break;<br />
289<br />
290 case jmpu: p += InSt[p].val.ival - 1;<br />
291 /*if(EiC_traceON) { printf("jmpu \n"); }*/<br />
292 break;<br />
293 case dupval:<br />
294 /* should really adjustTop here !!*/<br />
295 STK[ToP + 1].v = STK[ToP].v;<br />
296 ToP += InSt[p].val.ival;<br />
297 /*if(EiC_traceON) {printf("dupval "); }*/<br />
298 break;<br />
299 case jmptab:<br />
300 {<br />
301 /*if(EiC_traceON) {printf("jmptab "); }*/<br />
302 struct {<br />
303 int n;<br />
304 val_t *loc;<br />
305 } *tab;<br />
306 int i;<br />
307 tab = InSt[p].val.p.p;<br />
308 for (i = 1; i < tab->n; i += 2)<br />
309 if (tab->loc[i].ival == STK[ToP].v.ival) {<br />
310 p += tab->loc[i + 1].ival - 1;<br />
311 break;<br />
312 }<br />
313 if (i >= tab->n)<br />
314 p += tab->loc[0].ival - 1;<br />
315 }<br />
316 break;<br />
317<br />
318<br />
319 /* specific float stuff */<br />
320<br />
321 case dreffloat:<br />
322 drefTYPE(float, dval); /*if(EiC_traceON) { printf("dreffloat<br />
");}*/<br />
323 break;<br />
324 case reffloat: refTYPE(float, dval);/* if(EiC_traceON)<br />
{printf("reffloat ");} */<br />
325 break;<br />
326 case rvalfloat:<br />
327 STK[ToP].v.dval=AR[InSt[p].ext][InSt[p].val.ival].v.fval;<br />
/*if(EiC_traceON) { printf("rvalfloat ");}*/<br />
104
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
328 break;<br />
329 case stofloat:<br />
330 AR[InSt[p].ext][InSt[p].val.ival].v.fval =<br />
(float)STK[ToP].v.dval; /*if(EiC_traceON) {printf("stofloat ");}*/<br />
331 break;<br />
332<br />
333<br />
334 /* specific short stuff */<br />
335 case rvalshort:<br />
336 STK[ToP].v.ival=AR[InSt[p].ext][InSt[p].val.ival].v.sval;<br />
/*if(EiC_traceON) {printf("rvalshort ");}*/<br />
337 break;<br />
338 case rvalushort:<br />
339 STK[ToP].v.ival=AR[InSt[p].ext][InSt[p].val.ival].v.usval;/*<br />
if(EiC_traceON) { printf("rvalushort ");}*/<br />
340 break;<br />
341 case drefushort:<br />
342 drefTYPE(unsigned short, ival);/*if(EiC_traceON)<br />
{ printf("drefushort ");}*/<br />
343 break;<br />
344 case drefshort:<br />
345 drefTYPE(short, ival);/* if(EiC_traceON) {printf("drefshort<br />
");}*/<br />
346 break;<br />
347 case refshort: refTYPE(short, ival); /*if(EiC_traceON)<br />
{printf("refshort ");} */<br />
348 break;<br />
349 case stoshort:<br />
350 AR[InSt[p].ext][InSt[p].val.ival].v.sval = STK[ToP].v.ival;<br />
351 /*if(EiC_traceON) {printf("stoshort ");}*/<br />
352 break;<br />
353<br />
354 /* specific char stuff */<br />
355 case rvalchar:<br />
356 STK[ToP].v.ival=AR[InSt[p].ext][InSt[p].val.ival].v.cval;<br />
357 /*if(EiC_traceON) {printf("rvalchar "); }*/<br />
358 break;<br />
359 case rvaluchar:<br />
360 STK[ToP].v.ival=AR[InSt[p].ext][InSt[p].val.ival].v.ucval;<br />
361 /*if(EiC_traceON) {printf("rvaluchar "); }*/<br />
362 break;<br />
363 case stochar:<br />
364 AR[InSt[p].ext][InSt[p].val.ival].v.cval = STK[ToP].v.ival;<br />
365 /*if(EiC_traceON) {printf("stochar ");}*/<br />
366 break;<br />
367 case drefuchar:<br />
368 drefTYPE(unsigned char, ival); /*if(EiC_traceON)<br />
{printf("drefuchar "); }*/<br />
369 break;<br />
370 case drefchar:<br />
371 drefTYPE(char, ival); /*if(EiC_traceON) {printf("drefchar<br />
"); }*/<br />
372 break;<br />
373 case refchar: refTYPE(char, ival); /*if(EiC_traceON)<br />
{printf("refchar "); }*/<br />
374 break;<br />
375 case neguchar: STK[ToP].v.uival = 256 - STK[ToP].v.uival;<br />
/*if(EiC_traceON) {printf("neguchar "); }*/<br />
376 break;<br />
377<br />
378 /* specific int stuff */<br />
379 case incint: STK[ToP].v.ival += InSt[p].val.ival; /*if(EiC_traceON)<br />
{printf("incrint ");}*/<br />
380 break;<br />
381 case <strong>de</strong>cint: STK[ToP].v.ival -= InSt[p].val.ival;/*if(EiC_traceON)<br />
{ printf("<strong>de</strong>crint"); }*/<br />
382 break;<br />
383 case drefint:<br />
105
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
384 drefTYPE(int, ival); /*if(EiC_traceON) {printf("drefint ");} */<br />
385 break;<br />
386 case refint: refTYPE(int, ival);/*if(EiC_traceON) { printf("refint<br />
"); }*/<br />
387 break;<br />
388 case stoint: stoTYPE(ival);<br />
389 if(EiC_traceON) {<br />
390 /*printf("\nstoint \n");*/<br />
391 AR[InSt[p].ext][InSt[p].val.ival].line = InSt[p].line;<br />
392 printf("\tDef %d-%d %d %d %d\n",<br />
393 InSt[p].ext,<br />
394 InSt[p].val.ival,<br />
395 /*((symentry_t *)AR[0][InSt[p].val.ival].v.sym)->id,*/<br />
396 /*((symentry_t *)AR[InSt[p].ext][InSt[p].val.ival].v.p.p)-<br />
>id,*/<br />
397 /*token->Val.sym->id,*/<br />
398 /*(char *) AR[InSt[p].ext][InSt[p].val.ival].v.sym->id,*/<br />
399 /*InSt.val.sym->id,*/<br />
400 /*token->Val.sym->id,*/<br />
401 /*((symentry_t *) STK[ToP - 1].v.p.p)->id,*/<br />
402 AR[InSt[p].ext][InSt[p].val.ival].v.ival,<br />
403 InSt[p].line,<br />
404 T[InSt[p].line].cptr_a<br />
405 ); /* id_symbole, valeur, id_intruction(num_instr-nb_appels)<br />
*/<br />
406<br />
407 /*<br />
408 for (k = 0; k < HSIZE; k++)<br />
409 for (sym = EiC_HTAB[k]; sym!= NULL; sym = sym->next) {<br />
410 printf("- k = %d - ",k);<br />
411 fputs(sym->id, stdout);<br />
412 fputc('\n', stdout);<br />
413 }<br />
414 */<br />
415<br />
416 T[InSt[p].line].<strong>de</strong>rnier_appel=<br />
InSt[p].line;/*[InSt[p].line].num_i;*/<br />
417 T[InSt[p].line].<strong>de</strong>rnier_pass= T[lastln].cptr_a;_<br />
418 }<br />
419<br />
420 break;<br />
421 case rvalint: rvalTYPE(ival);<br />
422 if(EiC_traceON) {<br />
423 /*printf("\n rvalint \n");*/<br />
424 printf("\tUse %d-%d %d %d %d %d \n",<br />
425 InSt[p].ext,<br />
426 InSt[p].val.ival,<br />
427 /*((symentry_t *)AR[InSt[p].ext][InSt[p].val.ival].v.sym)-<br />
>id,*/<br />
428 T[AR[InSt[p].ext][InSt[p].val.ival].line].<strong>de</strong>rnier_appel,<br />
429 T[AR[InSt[p].ext][InSt[p].val.ival].line].<strong>de</strong>rnier_pass,<br />
430 InSt[p].line,<br />
431 T[InSt[p].line].cptr_a<br />
432 );/*id_symbole, appel <strong>de</strong>, id_instruction(num_instrnb_appels)*/<br />
433 }<br />
434 break;<br />
435 case pushint: pushTYPE(ival); /*if(EiC_traceON) {printf("pushint<br />
");}*/<br />
436 break;<br />
437 case negint: negTYPE(ival); /*if(EiC_traceON) {printf("negtype -<br />
\n");} */<br />
438 break;<br />
439 case addint: addTYPE(ival); /*if(EiC_traceON) {printf("\t<br />
\"+\"\n");} */<br />
440 break;<br />
441 case subint: subTYPE(ival); /*if(EiC_traceON) {printf("\t \"-<br />
\"\n");} */<br />
106
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
442 break;<br />
443 case divint: divTYPE(ival); /*if(EiC_traceON) {printf("divint<br />
\n");} */<br />
444 break;<br />
445 case multint: multTYPE(ival); /*if(EiC_traceON) {printf("multint<br />
\n");} */<br />
446 break;<br />
447 case modint: modTYPE(ival); /*if(EiC_traceON) {printf("modint<br />
\n");} */<br />
448 break;<br />
449 case lshtint: lshtTYPE(ival); /*if(EiC_traceON) {printf("lshtint<br />
\n");} */<br />
450 break;<br />
451 case rshtint: rshtTYPE(ival); /*if(EiC_traceON) {printf("rshtint<br />
\n");} */<br />
452 break;<br />
453 case ltint: ltTYPE(ival);<br />
454 if(EiC_traceON) {<br />
455 printf("%d %d\n",InSt[p].line,T[InSt[p].line].cptr_a);<br />
456 /*<br />
457 if (STK[ToP].v.ival==1 && cpt_psgBoucle==0) cpt_psgBoucle++;<br />
458 if (STK[ToP].v.ival==1 && cpt_psgBoucle!=0) cpt_psgBoucle++;<br />
459 if (STK[ToP].v.ival==0) { cpt_psgBoucle=0; Jmpu--; }<br />
460 */<br />
461 }<br />
462 break;<br />
463 case leint: leTYPE(ival); /*if(EiC_traceON) {printf("\t<br />
\"\"\n"); }*/<br />
470 break;<br />
471 case geint: geTYPE(ival); /*if(EiC_traceON) {printf("\t<br />
\">=\"\n"); }*/<br />
472 break;<br />
473 case lorint: lorTYPE(ival);/* if(EiC_traceON) {printf("\t<br />
\"||\"\n");} */<br />
474 break;<br />
475 case landint: landTYPE(ival);/* if(EiC_traceON) {printf("\t<br />
\"!=0\"\n"); }*/<br />
476 break;<br />
477 case notint: notTYPE(ival); /*if(EiC_traceON) {printf("notint<br />
\n"); }*/<br />
478 break;<br />
479 case borint: borTYPE(ival); /*if(EiC_traceON) {printf("borint<br />
\n"); }*/<br />
480 break;<br />
481 case xorint: xorTYPE(ival); /*if(EiC_traceON) {printf("xorint<br />
\n"); }*/<br />
482 break;<br />
483 case andint: andTYPE(ival); /*if(EiC_traceON) {printf("andint<br />
\n"); }*/<br />
484 break;<br />
485 case compint: compTYPE(ival); /*if(EiC_traceON) {printf("compint<br />
\n");} */<br />
486 break;<br />
487 case int2double: castTYPES(ival, dval, double); /*if(EiC_traceON)<br />
{ printf("int2double ");}*/<br />
488 break;<br />
489 case int2ptr: castTYPES(ival, p.p, void *); /*if(EiC_traceON)<br />
{printf("int2ptr ");}*/<br />
490 break;<br />
107
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
491 case int2long: castTYPES(ival, lval, long); /* if(EiC_traceON)<br />
{printf("int2long ");}*/<br />
492 break;<br />
493 case int2llong: castTYPES(ival, llval, eic_llong);<br />
/*if(EiC_traceON) { printf("int2llong ");}*/<br />
494 break;<br />
495 case int2uchar: castTYPES(ival, lval, unsigned char);<br />
/*if(EiC_traceON) { printf("int2uchar ");}*/<br />
496 break;<br />
497 case int2ushort: castTYPES(ival, lval, unsigned short);<br />
/*if(EiC_traceON) {printf("int2ushort ");}*/<br />
498 break;<br />
499<br />
500 /* unsigned int stuff */<br />
501 case incuint: STK[ToP].v.uival += InSt[p].val.uival;<br />
/*if(EiC_traceON) { printf("incuint ");}*/<br />
502 break;<br />
503 case <strong>de</strong>cuint: STK[ToP].v.uival -= InSt[p].val.uival;<br />
/*if(EiC_traceON) { printf("<strong>de</strong>cuint ");}*/<br />
504 break;<br />
505 case drefuint:<br />
506 drefTYPE(unsigned, uival); /*if(EiC_traceON) { printf("drefuint<br />
");}*/<br />
507 break;<br />
508 case refuint: refTYPE(unsigned, uival); /*if(EiC_traceON)<br />
{ printf("refuint ");}*/<br />
509 break;<br />
510 case stouint: stoTYPE(uival); /*if(EiC_traceON) { printf("stouint<br />
");}*/<br />
511 break;<br />
512 case rvaluint: rvalTYPE(uival); /*if(EiC_traceON)<br />
{ printf("rvaluint ");}*/<br />
513 break;<br />
514 case pushuint: pushTYPE(uival); /*if(EiC_traceON)<br />
{ printf("pushuint ");}*/<br />
515 break;<br />
516 case neguint: negTYPE(uival); /*if(EiC_traceON) { printf("neguint<br />
");}*/<br />
517 break;<br />
518 case adduint: addTYPE(uival);/* if(EiC_traceON) { printf("adduint<br />
");}*/<br />
519 break;<br />
520 case subuint: subTYPE(uival); /*if(EiC_traceON) { printf("subuint<br />
");}*/<br />
521 break;<br />
522 case divuint: divTYPE(uival); /*if(EiC_traceON) { printf("divuint<br />
");}*/<br />
523 break;<br />
524 case multuint: multTYPE(uival); /*if(EiC_traceON)<br />
{ printf("multuint ");}*/<br />
525 break;<br />
526 case moduint: modTYPE(uival); /*if(EiC_traceON) { printf("moduint<br />
");}*/<br />
527 break;<br />
528 case lshtuint: lshtTYPE(uival);/* if(EiC_traceON)<br />
{ printf("lshuint ");}*/<br />
529 break;<br />
530 case rshtuint: rshtTYPE(uival); /*if(EiC_traceON)<br />
{ printf("rshtuint ");}*/<br />
531 break;<br />
532 case ltuint: ltTYPE(uival); /*if(EiC_traceON) {printf("ltuint<br />
");}*/<br />
533 break;<br />
534 case leuint: leTYPE(uival); /*if(EiC_traceON) { printf("leuint<br />
");}*/<br />
535 break;<br />
536 case equint: eqTYPE(uival); /*if(EiC_traceON) { printf("equint<br />
");}*/<br />
108
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
537 break;<br />
538 case neuint: neTYPE(uival); /*if(EiC_traceON) { printf("neuint<br />
");}*/<br />
539 break;<br />
540 case gtuint: gtTYPE(uival); /*if(EiC_traceON) { printf("gtuint<br />
");}*/<br />
541 break;<br />
542 case geuint: geTYPE(uival); /*if(EiC_traceON) {printf("geuint<br />
");}*/<br />
543 break;<br />
544 case loruint: lorTYPE(uival);/* if(EiC_traceON) { printf("loruint<br />
");}*/<br />
545 break;<br />
546<br />
547 case notuint: notTYPE(uival); /*if(EiC_traceON)<br />
{ printf("notuint");}*/<br />
548 break;<br />
549 case boruint: borTYPE(uival); /*if(EiC_traceON)<br />
{printf("boruint"); }*/<br />
550 break;<br />
551 case xoruint: xorTYPE(uival); /*if(EiC_traceON) { printf("xoruint<br />
"); }*/<br />
552 break;<br />
553 case anduint: andTYPE(uival); /*if(EiC_traceON) { printf("anduint<br />
"); }*/<br />
554 break;<br />
555 case compuint: compTYPE(uival); /*if(EiC_traceON)<br />
{printf("compuint ");} */<br />
556 break;<br />
557 case uint2double: castTYPES(uival, dval, double); /*if(EiC_traceON)<br />
{printf("uint2double "); }*/<br />
558 break;<br />
559 case uint2ptr: castTYPES(uival, p.p, void *); /*if(EiC_traceON)<br />
{printf("uint2ptr "); }*/<br />
560 break;<br />
561 case uint2long: castTYPES(uival, lval, long); /*if(EiC_traceON)<br />
{printf("uint2long "); }*/<br />
562 break;<br />
563 case uint2llong: castTYPES(uival, llval, eic_llong);/*<br />
if(EiC_traceON) {printf("uint2llong "); }*/<br />
564 break;<br />
565<br />
566 /* specific long stuff */<br />
567 case inclong: STK[ToP].v.lval += InSt[p].val.ival;<br />
568 break;<br />
569 case <strong>de</strong>clong: STK[ToP].v.lval -= InSt[p].val.ival;<br />
570 break;<br />
571 case dreflong:<br />
572 drefTYPE(long, lval);<br />
573 break;<br />
574 case reflong: refTYPE(long, lval);<br />
575 break;<br />
576 case stolong: stoTYPE(lval);<br />
577 break;<br />
578 case rvallong: rvalTYPE(lval);<br />
579 break;<br />
580 case pushlong: pushTYPE(lval);<br />
581 break;<br />
582 case neglong: negTYPE(lval);<br />
583 break;<br />
584 case addlong: addTYPE(lval);<br />
585 break;<br />
586 case sublong: subTYPE(lval);<br />
587 break;<br />
588 case divlong: divTYPE(lval);<br />
589 break;<br />
590 case multlong: multTYPE(lval);<br />
591 break;<br />
109
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
592 case modlong: modTYPE(lval);<br />
593 break;<br />
594 case lshtlong: lshtTYPE(lval);<br />
595 break;<br />
596 case rshtlong: rshtTYPE(lval);<br />
597 break;<br />
598 case ltlong: ltTYPE(lval);<br />
599 break;<br />
600 case lelong: leTYPE(lval);<br />
601 break;<br />
602 case eqlong: eqTYPE(lval);<br />
603 break;<br />
604 case nelong: neTYPE(lval);<br />
605 break;<br />
606 case gtlong: gtTYPE(lval);<br />
607 break;<br />
608 case gelong: geTYPE(lval);<br />
609 break;<br />
610 case lorlong: lorTYPE(lval);<br />
611 break;<br />
612 case landlong: landTYPE(lval);<br />
613 break;<br />
614 case notlong: notTYPE(lval);<br />
615 break;<br />
616 case borlong: borTYPE(lval);<br />
617 break;<br />
618 case xorlong: xorTYPE(lval);<br />
619 break;<br />
620 case andlong: andTYPE(lval);<br />
621 break;<br />
622 case complong: compTYPE(lval);<br />
623 break;<br />
624 case long2double: castTYPES(lval, dval, double);<br />
625 break;<br />
626 case long2ptr: castTYPES(lval, p.p, void *);<br />
627 break;<br />
628 case long2llong: castTYPES(lval, llval, eic_llong);<br />
629 break;<br />
630 case long2int: castTYPES(lval, ival, int);<br />
631 break;<br />
632<br />
633 /* unsigned long stuff */<br />
634 case inculong: STK[ToP].v.ulval += InSt[p].val.ival;<br />
635 break;<br />
636 case <strong>de</strong>culong: STK[ToP].v.ulval -= InSt[p].val.ival;<br />
637 break;<br />
638 case drefulong:<br />
639 drefTYPE(unsigned long, ulval);<br />
640 break;<br />
641 case refulong: refTYPE(unsigned long, ulval);<br />
642 break;<br />
643 case stoulong: stoTYPE(ulval);<br />
644 break;<br />
645 case rvalulong: rvalTYPE(ulval);<br />
646 break;<br />
647 case pushulong: pushTYPE(ulval);<br />
648 break;<br />
649 case negulong: negTYPE(ulval);<br />
650 break;<br />
651 case addulong: addTYPE(ulval);<br />
652 break;<br />
653 case subulong: subTYPE(ulval);<br />
654 break;<br />
655 case divulong: divTYPE(ulval);<br />
656 break;<br />
657 case multulong: multTYPE(ulval);<br />
658 break;<br />
659 case modulong: modTYPE(ulval);<br />
110
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
660 break;<br />
661 case lshtulong: lshtTYPE(ulval);<br />
662 break;<br />
663 case rshtulong: rshtTYPE(ulval);<br />
664 break;<br />
665 case ltulong: ltTYPE(ulval);<br />
666 break;<br />
667 case leulong: leTYPE(ulval);<br />
668 break;<br />
669 case equlong: eqTYPE(ulval);<br />
670 break;<br />
671 case neulong: neTYPE(ulval);<br />
672 break;<br />
673 case gtulong: gtTYPE(ulval);<br />
674 break;<br />
675 case geulong: geTYPE(ulval);<br />
676 break;<br />
677 case lorulong: lorTYPE(ulval);<br />
678 break;<br />
679<br />
680 case notulong: notTYPE(ulval);<br />
681 break;<br />
682 case borulong: borTYPE(ulval);<br />
683 break;<br />
684 case xorulong: xorTYPE(ulval);<br />
685 break;<br />
686 case andulong: andTYPE(ulval);<br />
687 break;<br />
688 case compulong: compTYPE(ulval);<br />
689 break;<br />
690 case ulong2double: castTYPES(ulval, dval, double);<br />
691 break;<br />
692 case ulong2ptr: castTYPES(ulval, p.p, void *);<br />
693 break;<br />
694 case ulong2int: castTYPES(ulval, ival, int);<br />
695 break;<br />
696 case ulong2llong: castTYPES(ulval, llval, eic_llong);<br />
697 break;<br />
698<br />
699<br />
700<br />
701 /* specific long long stuff */<br />
702 case incllong: STK[ToP].v.llval += InSt[p].val.ival;<br />
703 break;<br />
704 case <strong>de</strong>cllong: STK[ToP].v.llval -= InSt[p].val.ival;<br />
705 break;<br />
706 case drefllong:<br />
707 drefTYPE(eic_llong, llval);<br />
708 break;<br />
709 case refllong: refTYPE(eic_llong, llval);<br />
710 break;<br />
711 case stollong: stoTYPE(llval);<br />
712 break;<br />
713 case rvalllong: rvalTYPE(llval);<br />
714 break;<br />
715 case pushllong: pushTYPE(llval);<br />
716 break;<br />
717 case negllong: negTYPE(llval);<br />
718 break;<br />
719 case addllong: addTYPE(llval);<br />
720 break;<br />
721 case subllong: subTYPE(llval);<br />
722 break;<br />
723 case divllong: divTYPE(llval);<br />
724 break;<br />
725 case multllong: multTYPE(llval);<br />
726 break;<br />
727 case modllong: modTYPE(llval);<br />
111
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
728 break;<br />
729 case lshtllong: lshtTYPE(llval);<br />
730 break;<br />
731 case rshtllong: rshtTYPE(llval);<br />
732 break;<br />
733 case ltllong: ltTYPE(llval);<br />
734 break;<br />
735 case lellong: leTYPE(llval);<br />
736 break;<br />
737 case eqllong: eqTYPE(llval);<br />
738 break;<br />
739 case nellong: neTYPE(llval);<br />
740 break;<br />
741 case gtllong: gtTYPE(llval);<br />
742 break;<br />
743 case gellong: geTYPE(llval);<br />
744 break;<br />
745 case lorllong: lorTYPE(llval);<br />
746 break;<br />
747 case landllong: landTYPE(llval);<br />
748 break;<br />
749 case notllong: notTYPE(llval);<br />
750 break;<br />
751 case borllong: borTYPE(llval);<br />
752 break;<br />
753 case xorllong: xorTYPE(llval);<br />
754 break;<br />
755 case andllong: andTYPE(llval);<br />
756 break;<br />
757 case compllong: compTYPE(llval);<br />
758 break;<br />
759 case llong2double: castTYPES(llval, dval, double);<br />
760 break;<br />
761 case llong2ptr: castTYPES(llval, p.p, void *);<br />
762 break;<br />
763 case llong2int: castTYPES(llval, ival, int);<br />
764 break;<br />
765 case llong2long: castTYPES(llval, lval, long);<br />
766 break;<br />
767<br />
768<br />
769 /* specific double stuff */<br />
770 case incdouble:STK[ToP].v.dval += InSt[p].val.ival;<br />
771 break;<br />
772 case <strong>de</strong>cdouble:STK[ToP].v.dval -= InSt[p].val.ival;<br />
773 break;<br />
774 case drefdouble:<br />
775 drefTYPE(double, dval);<br />
776 break;<br />
777 case refdouble: refTYPE(double, dval);<br />
778 break;<br />
779 case stodouble: stoTYPE(dval);<br />
780 break;<br />
781 case rvaldouble: rvalTYPE(dval);<br />
782 break;<br />
783 case pushdouble: pushTYPE(dval);<br />
784 break;<br />
785 case negdouble: negTYPE(dval);<br />
786 break;<br />
787 case adddouble: addTYPE(dval);<br />
788 break;<br />
789 case subdouble: subTYPE(dval);<br />
790 break;<br />
791 case divdouble: divTYPE(dval);<br />
792 break;<br />
793 case multdouble: multTYPE(dval);<br />
794 break;<br />
795 case ltdouble: ltTYPE(dval);<br />
112
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
796 break;<br />
797 case ledouble: leTYPE(dval);<br />
798 break;<br />
799 case eqdouble: eqTYPE(dval);<br />
800 break;<br />
801 case nedouble: neTYPE(dval);<br />
802 break;<br />
803 case gtdouble: gtTYPE(dval);<br />
804 break;<br />
805 case gedouble: geTYPE(dval);<br />
806 break;<br />
807 case lordouble: lorTYPE(dval);<br />
808 break;<br />
809 case landdouble: landTYPE(dval);<br />
810 break;<br />
811 case notdouble: notTYPE(dval);<br />
812 break;<br />
813<br />
814 case double2int: castTYPES(dval, uival, unsigned int);<br />
815 break;<br />
816 case double2long: castTYPES(dval, ulval, unsigned long);<br />
817 break;<br />
818 case double2llong: castTYPES(dval, llval, eic_llong);<br />
819 break;<br />
820 case double2float: castTYPES(dval, fval, float);<br />
821 break;<br />
822<br />
823<br />
824 /*specific pointer stuff */<br />
825 case incptr: STK[ToP].v.p.p = (char *) STK[ToP].v.p.p +<br />
826 InSt[p].val.ival; /*if(EiC_traceON) {printf("incptr "); }*/<br />
827 break;<br />
828 case <strong>de</strong>cptr: STK[ToP].v.p.p = (char *) STK[ToP].v.p.p -<br />
829 InSt[p].val.ival; /*if(EiC_traceON) {printf("<strong>de</strong>cptr "); }*/<br />
830 break;<br />
831 case lda:<br />
832 #if 0<br />
833 STK[ToP].v.p = AR[1][InSt[p].val.ival].v.p;<br />
834 STK[ToP].v.p.p = (char*)STK[ToP].v.p.sp + InSt[p].ext;<br />
835 STK[ToP].v.p.sp = STK[ToP].v.p.p;<br />
836 if(EiC_traceON) {printf("lda if 0\n"); }<br />
837 #else<br />
838<br />
839 {<br />
840 if(EiC_traceON) {printf("lda if non 0\n"); }<br />
841 ptr_t *q = &AR[1][InSt[p].val.ival].v.p;<br />
842 ptr_t *a = &STK[ToP].v.p;<br />
843<br />
844 a->p = a->sp = (char*)q->sp + InSt[p].ext;<br />
845 a->ep = q->ep;<br />
846<br />
847 if(vp) { /* patch previous lda assignment */<br />
848 ((ptr_t*)vp)->ep = (char*)a->p;<br />
849 }<br />
850 /* Take advantage of the fact that the next InSt<br />
851 * has the location of where `a' is to be stored.<br />
852 */<br />
853 vp = &AR[1][InSt[p+1].val.ival].v.p;<br />
854<br />
855 }<br />
856<br />
857 #endif<br />
858<br />
859 break;<br />
860 case ixa:<br />
861 ToP--;<br />
862 STK[ToP].v.p.p = (char *) STK[ToP].v.p.p +<br />
STK[ToP+1].v.ival*InSt[p].val.ival;<br />
113
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
863 if(EiC_traceON) {printf("ixa \n"); }<br />
864 break;<br />
865 case addptr2int: ToP--;<br />
866 STK[ToP].v.p.p = (char *) STK[ToP].v.p.p + STK[ToP + 1].v.ival;<br />
if(EiC_traceON) {printf("add2ptrint "); }<br />
867 break;<br />
868 case addint2ptr: ToP--;<br />
869 STK[ToP].v.p.p = STK[ToP].v.ival<br />
870 + (char *) STK[ToP+1].v.p.p; if(EiC_traceON)<br />
{printf("addint2ptr\n"); }<br />
871 break;<br />
872 case subptrint: ToP--;<br />
873 STK[ToP].v.p.p = (char *) STK[ToP].v.p.p - STK[ToP + 1].v.ival;<br />
if(EiC_traceON) {printf("subptrint\n"); }<br />
874 break;<br />
875 case subptr:<br />
876 ToP--;<br />
877 STK[ToP].v.ival =<br />
878 (int) ((long) STK[ToP].v.p.p - (long) STK[ToP+1].v.p.p);<br />
879 if(EiC_traceON) {printf("subptr\n"); }<br />
880 break;<br />
881<br />
882 case drefptr:<br />
883 drefTYPE(ptr_t, p); if(EiC_traceON) {printf("drefptr\n "); }<br />
884 break;<br />
885<br />
886 case drefuptr:<br />
887 drefTYPE(void**,p.p);<br />
888 STK[ToP].v.p.sp = 0;<br />
889 STK[ToP].v.p.ep = (void *) ULONG_MAX; if(EiC_traceON)<br />
{printf("drefuptr \n");}<br />
890 break;<br />
891<br />
892 case refptr: refTYPE(ptr_t, p); if(EiC_traceON) {printf("refptr<br />
\n"); }<br />
893 break;<br />
894 case refuptr: refTYPE(void *, p.p); if(EiC_traceON)<br />
{printf("refuptr\n ");}<br />
895 break;<br />
896<br />
897 case stoptr: stoTYPE(p);/* if(EiC_traceON) {printf("stoptr<br />
\n");}*/<br />
898 break;<br />
899 case stouptr: stoTYPE(p.p); if(EiC_traceON) {printf("stouptr \n");}<br />
900 break;<br />
901<br />
902 case rvalptr: rvalTYPE(p); if(EiC_traceON) {printf("rvalptr \n");}<br />
903 break;<br />
904 case rvaluptr: rvalTYPE(p);<br />
905 STK[ToP].v.p.sp = 0;<br />
906 STK[ToP].v.p.ep = (void*) ULONG_MAX; /* set to a very high<br />
value */<br />
907 _if(EiC_traceON) {printf("rvaluptr ");}<br />
908 break;<br />
909<br />
910 case pushptr: pushTYPE(p); /*if(EiC_traceON) {printf("pushptr<br />
\n");}*/<br />
911 break;<br />
912 case ltptr: ltTYPE(p.p); if(EiC_traceON) {printf("ltptr\n");}<br />
913 break;<br />
914 case leptr: leTYPE(p.p); if(EiC_traceON) {printf("leptr \n");}<br />
915 break;<br />
916 case eqptr: eqTYPE(p.p); if(EiC_traceON) {printf("eqptr \n");}<br />
917 break;<br />
918 case neptr: neTYPE(p.p); if(EiC_traceON) {printf("neptr \n");}<br />
919 break;<br />
920 case gtptr: gtTYPE(p.p); if(EiC_traceON) {printf("gtptr \n");}<br />
921 break;<br />
114
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
922 case geptr: geTYPE(p.p); if(EiC_traceON) {printf("geptr \n");}<br />
923 break;<br />
924 case lorptr: lorTYPE(p.p); if(EiC_traceON) {printf("lorptr \n");}<br />
925 break;<br />
926 case landptr: landTYPE(p.p); if(EiC_traceON) {printf("landptr<br />
\n");}<br />
927 break;<br />
928 case notptr: notTYPE(p.p); if(EiC_traceON) {printf("notptr \n");}<br />
929 break;<br />
930 case ptr2int: castTYPES(p.p, ival, int); if(EiC_traceON)<br />
{printf("ptr2int \n");}<br />
931 break;<br />
932 case ptr2long: castTYPES(p.p, lval, long); if(EiC_traceON)<br />
{printf("ptr2long \n");}<br />
933 break;<br />
934<br />
935 case lval: /* on the fly safe pointer */<br />
936 STK[ToP].v.p.p = &AR[InSt[p].ext][InSt[p].val.ival].v;<br />
937 STK[ToP].v.p.ep = (char *) STK[ToP].v.p.p + (size_t)<br />
938 InSt[p].val.p.ep;<br />
939 STK[ToP].v.p.sp = STK[ToP].v.p.p;<br />
940 _/*if(EiC_traceON) {printf("lval \n");}*/<br />
941 break;<br />
942 case assigntype: assignTYPE; /*if(EiC_traceON) {printf("assigntype<br />
");}*/<br />
943 break;<br />
944 case stoval:<br />
945 /*if(EiC_traceON) {printf("stoval "); }*/<br />
946 switch(InSt[p].ext) {<br />
947 case t_char:<br />
948 case t_uchar: STK[ToP].v.cval = STK[ToP].v.ival;<br />
if(EiC_traceON) {printf("t_char ou t_uchar\n");}<br />
949 break;<br />
950 case t_short:<br />
951 case t_ushort: STK[ToP].v.sval = STK[ToP].v.ival;<br />
if(EiC_traceON) {printf("t_short ou t_ushort\n");}<br />
952 break;<br />
953 case t_float: STK[ToP].v.fval = STK[ToP].v.dval;<br />
if(EiC_traceON) {printf("t_float\n");}<br />
954 /*_ case t_struct:<br />
955 case t_union:<br />
956 printf("stoVa1l with struct/union\n");<br />
957 */<br />
958 }<br />
959<br />
960 stoVAL;<br />
961 break;<br />
962 case pushval: pushVAL; if(EiC_traceON) {printf("pushval\n"); }<br />
963 break;<br />
964<br />
965 case eiccall:<br />
966 if(EiC_traceON) {printf("eiccall\n");}<br />
967 if(!((symentry_t*)STK[ToP - 1].v.p.p)->tag) {<br />
968 AdjustTop(6);<br />
969 STK[ToP + 1].v.ival = p;<br />
970 STK[ToP + 1].type = (void*)EiC_CurrentFile; /* save file */<br />
971 STK[ToP + 2].v.p.p = InSt;<br />
972 STK[ToP + 3].v.lval = AR[1] - env->LAR;<br />
973 STK[ToP + 4].v.ival = env->lsp - STK[ToP].v.ival;<br />
974 AR[1] = &env->LAR[env->lsp] /* - STK[ToP].v.ival] */ ;<br />
975 co<strong>de</strong> = ! STK[ToP - 1].v.p.p ? NULL :<br />
976 AR[0][((symentry_t *)<br />
977 STK[ToP - 1].v.p.p)->val.ival].v.p.p;<br />
978<br />
979 if (co<strong>de</strong> == NULL) {<br />
980 if(STK[ToP - 1].v.p.p) {<br />
981 EiC_formatMessage("Link error: un<strong>de</strong>fined function :-><br />
%s\n",<br />
115
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
982 ((symentry_t *) STK[ToP - 1].v.p.p)->id);<br />
983 }<br />
984 else<br />
985 EiC_formatMessage("Link error: possible usage of a<br />
function pointer"<br />
986 " before assignment.\n");<br />
987 env->lsp = 0;<br />
988 raise(SIGINT);<br />
989 }<br />
990<br />
991 /*printf("((symentry_t *)STK[%d - 1].v.p.p)->id = %s\n",ToP, ((symentry_t<br />
*)STK[ToP - 1].v.p.p)->id);*/<br />
992 EiC_CurrentFile = co<strong>de</strong>Name(co<strong>de</strong>);<br />
993 _if(EiC_traceON) {printf("\n%s :\n# %d:%d\n\t%s %d<br />
%d\n",(char*)EiC_CurrentFile,InSt[p].line,T[InSt[p].line].cptr_a,(char*)v.p.p,InSt[<br />
p].line,T[InSt[p].line].cptr_a);}<br />
994 InSt = co<strong>de</strong>->inst;<br />
995 p = -1;<br />
996 ToP += 5;<br />
997 if(EiC_traceON){<br />
998 lastln = -1;<br />
999 }<br />
1000<br />
1001 break;<br />
1002 }<br />
1003<br />
1004 case call:<br />
1005 if(EiC_traceON) {printf("\tCall %d %d<br />
",InSt[p].line,T[InSt[p].line].cptr_a); }<br />
1006 argc = ARGC;<br />
1007 hold_AR = AR[2];<br />
1008 hold_AR1 = AR[1];<br />
1009 ARGC = STK[ToP].v.ival;<br />
1010<br />
1011 /*AR[2] = &env->LAR[env->lsp - ARGC];*/<br />
1012 AR[2] = &env->LAR[env->lsp];<br />
1013 if(InSt[p].ext)<br />
1014 STK[ToP - 1].v = STK[ToP - 1].v.vfunc ();<br />
1015 else<br />
1016 STK[ToP - 1].v.vfunc();<br />
1017<br />
1018 env->lsp -= STK[ToP].v.ival;<br />
1019 ARGC = argc;<br />
1020 AR[2] = hold_AR;<br />
1021 AR[1] = hold_AR1;<br />
1022 ToP--;<br />
1023 break;<br />
1024<br />
1025 case eicreturn:<br />
1026 if(EiC_traceON) {printf("\tReturn %d %d<br />
%d\n",STK[ToP].v.ival,InSt[p].line,T[InSt[p].line].cptr_a);}<br />
1027 ToP -= 6; /* over write co<strong>de</strong> pointer */<br />
1028 p = STK[ToP + 2].v.ival;<br />
1029<br />
1030 EiC_CurrentFile = (char*)STK[ToP+2].type;<br />
1031<br />
1032 InSt = STK[ToP + 3].v.p.p;<br />
1033 env->lsp = STK[ToP + 5].v.ival;<br />
1034 STK[ToP].v = STK[ToP + 6].v;<br />
1035<br />
1036 AR[1] = &env->LAR[STK[ToP + 4].v.ival];<br />
1037 if(EiC_traceON) {<br />
1038<br />
1039 EiC_eicpop(&names,&v);<br />
1040 EiC_formatMessage("\n[%s] ", (char*)v.p.p);<br />
1041 lastln = -1;<br />
1042 }<br />
1043 break;<br />
116
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
1044<br />
1045<br />
1046 #if 1<br />
1047 case eiclongjmp:<br />
1048 {<br />
1049<br />
1050 _EiC_jmp_buf * reg;<br />
1051<br />
1052 reg = (_EiC_jmp_buf *) ((char*)STK[ToP].v.p.p -<br />
STK[ToP+1].v.ival);<br />
1053<br />
1054 p = reg->p;<br />
1055 EiC_CurrentFile = reg->file;<br />
1056 InSt = reg->inst;<br />
1057 env->lsp = reg->lsp;<br />
1058 AR[1] = &env->LAR[reg->offset]; /*reg->ar; */<br />
1059<br />
1060 if(STK[ToP+1].v.ival == 0)<br />
1061 STK[reg->top].v.ival = 1;<br />
1062 else<br />
1063 STK[reg->top].v.ival = STK[ToP+1].v.ival;<br />
1064<br />
1065 ToP = reg->top;<br />
1066 if(EiC_traceON) {printf(" eiclongjmp \n");}<br />
1067 }<br />
1068<br />
1069 break;<br />
1070<br />
1071 case eicsetjmp:<br />
1072 {<br />
1073<br />
1074 _EiC_jmp_buf * reg;<br />
1075<br />
1076 reg = (_EiC_jmp_buf *) STK[ToP].v.p.p;<br />
1077<br />
1078 reg->p = p;<br />
1079 reg->file = (void*)EiC_CurrentFile; /* save file */<br />
1080 reg->inst = InSt;<br />
1081 reg->lsp = env->lsp;<br />
1082 reg->offset = AR[1] - env->LAR;<br />
1083 reg->ar = AR[1];<br />
1084 reg->top = ToP;<br />
1085<br />
1086 STK[ToP].v.ival = 0;<br />
1087 _if(EiC_traceON) {printf(" eicsetjmp \n");}<br />
1088 }<br />
1089<br />
1090 break;<br />
1091 #endif<br />
1092<br />
1093 case massign:<br />
1094 {<br />
1095 val_t *v = &AR[InSt[p].ext][InSt[p].val.ival].v;<br />
1096 v->p.sp = (void*)xcalloc(STK[ToP].v.ival,1);<br />
1097 v->p.ep = (char*)v->p.sp + STK[ToP].v.ival;<br />
1098 vp = NULL;<br />
1099 if(EiC_traceON) {printf("massign "); }<br />
1100 }<br />
1101 break;<br />
1102 case fmem: FMEM; if(EiC_traceON) {printf("fmem ");}<br />
1103 break;<br />
1104 case refmem: refMEM; if(EiC_traceON) {printf("refmem "); }<br />
1105 break;<br />
1106 case minit:<br />
1107 memcpy(STK[ToP].v.p.p,InSt[p].val.p.p, InSt[p].ext);<br />
1108 if(EiC_traceON) {printf("minit "); }<br />
1109 break;<br />
1110 case reducear:<br />
117
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
1111 env->lsp -= InSt[p].val.ival;<br />
1112 if(EiC_traceON) {printf("reducear "); }<br />
1113 break;<br />
1114 case checkar:<br />
1115 {<br />
1116 size_t d;<br />
1117 ptrdiff_t d2;<br />
1118 d = env->LARsize - env->lsp;<br />
1119 if (d < InSt[p].val.ival) {<br />
1120 /* printf("expanding AR %d\n",env->LARsize);*/<br />
1121 d2 = (AR[1] - env->LAR);<br />
1122 env->LARsize += InSt[p].val.ival - d;<br />
1123 env->LAR =<br />
1124 (AR_t *) xrealloc(env->LAR,<br />
1125 env->LARsize * sizeof(AR_t));<br />
1126 AR[1] = &env->LAR[(size_t) d2];<br />
1127 }<br />
1128 if (InSt[p].ext == 0) {<br />
1129 env->lsp += InSt[p].val.ival;<br />
1130 /*AR[1][0].v.p.p = NULL;*/<br />
1131 }<br />
1132 }<br />
1133 /*if(EiC_traceON) {printf("checkar \n"); }*/<br />
1134 break;<br />
1135 case halt: STK[ToP].type = InSt[p].val.p.p;<br />
1136 ON = 0; EiC_STaCK_VaLuE = STK[ToP].v; /*if(EiC_traceON)<br />
{printf("\nhalt\n");}*/<br />
1137 break;<br />
1138<br />
1139 case empty: /*if(EiC_traceON) {printf("empty\n");} */<br />
1140 break;<br />
1141 }<br />
1142 p++;<br />
1143 }<br />
1144<br />
1145<br />
1146 end = clock();<br />
1147<br />
1148 /*if(EiC_traceON)<br />
1149 EiC_messageDisplay("Fin d'interpre.c\n");<br />
1150 */<br />
1151 if(EiC_interActive)<br />
1152 EiC_showvalue(&STK[ToP]);<br />
1153<br />
1154 if (EiC_TIMER) {<br />
1155 fprintf(stdout," : %g\n",(endstart)/(float)CLOCKS_PER_SEC);<br />
1156 }<br />
1157<br />
1158 xfree(STK);<br />
1159 }<br />
118
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
1 /* eicval.h<br />
2 *<br />
3 * (C) Copyright Apr 15 1995, Edmond J. Breen.<br />
4 * ALL RIGHTS RESERVED.<br />
5 * This co<strong>de</strong> may be copied for personal, non-profit use only.<br />
6 *<br />
7 */<br />
8<br />
9 #ifn<strong>de</strong>f EICVALH_<br />
10 #<strong>de</strong>fine EICVALH_<br />
11<br />
12 #inclu<strong>de</strong> <br />
13 #inclu<strong>de</strong> <br />
14<br />
15 #if !<strong>de</strong>fined(_eic_ptr)<br />
16 #<strong>de</strong>fine _eic_ptr<br />
17 type<strong>de</strong>f struct {void *p, *sp, *ep;} ptr_t;<br />
18 #endif<br />
19<br />
20<br />
21 #ifn<strong>de</strong>f NO_LONG_LONG<br />
22 type<strong>de</strong>f long long eic_llong;<br />
23 #else<br />
24 type<strong>de</strong>f long eic_llong;<br />
25 #endif<br />
26<br />
27<br />
28 union VaL {<br />
29 char cval; _ /* char value */<br />
30 unsigned char ucval;<br />
31 short sval; /* short integer val */<br />
32 unsigned short usval;<br />
33 int ival; _ /* integer value */<br />
34 unsigned uival;<br />
35 long lval; /* long integer */<br />
36 unsigned long ulval;<br />
37<br />
38 /* long longs are not yet supported by ANSI C*/<br />
39<br />
40 eic_llong llval; /* long long value */<br />
41<br />
42 float fval; _ /* float value */<br />
43 double dval; /* double float value */<br />
44<br />
45 ptr_t p; /* safe pointer */<br />
46 void *up; /* unsafe pointer */<br />
47<br />
48 div_t divval;<br />
49 ldiv_t ldivval;<br />
50<br />
51 int (*func)(); _ /* function pointer */<br />
52 union VaL (*vfunc)();<br />
53<br />
54 struct symentry_t * sym;/* pointer into symbol table */<br />
55<br />
56 pid_t pid; /* process ID value */<br />
57 size_t szval; /* generic size value */<br />
58 ssize_t sszval; /* POSIX.1 byte count value */<br />
59<br />
60 mo<strong>de</strong>_t mval; /* mo<strong>de</strong>_t value */<br />
61 #if<strong>de</strong>f _NETBSD<br />
62 long offval; /* file offset position */<br />
63 #else<br />
64 off_t offval; /* file offset position */<br />
65 #endif<br />
66 };<br />
67<br />
119
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
68 type<strong>de</strong>f union VaL val_t;<br />
69<br />
70<br />
71 type<strong>de</strong>f struct Label_t {<br />
72 char *name; /* label name */<br />
73 int loc; /* label location */<br />
74 struct Label_t *nxt; /* link to next label in list */<br />
75 } Label_t;<br />
76<br />
77 type<strong>de</strong>f struct {<br />
78 unsigned opco<strong>de</strong>;<br />
79 val_t val;<br />
80 int ext;<br />
81 unsigned short line;<br />
82 _ unsigned short pas; /* pour compter le nombre <strong>de</strong> passage*/<br />
83 }InsT_t;<br />
84<br />
85<br />
86 type<strong>de</strong>f struct {<br />
87 unsigned int nextinst; /* next instruction */<br />
88 unsigned int binst; /* physical size */<br />
89 InsT_t * inst; /* instructions */<br />
90 char * Filename; /* file with source co<strong>de</strong> */<br />
91 Label_t * labels;<br />
92 Label_t * gotos;<br />
93 void * parent; /* used for callbacks */<br />
94 void * prev; /* used for chaining during reentry and callbacks*/<br />
95 }co<strong>de</strong>_t;<br />
96<br />
97 /* methods for co<strong>de</strong> */<br />
98 #<strong>de</strong>fine opco<strong>de</strong>(C,i) ((C)->inst[i].opco<strong>de</strong>)<br />
99 #<strong>de</strong>fine setopco<strong>de</strong>(C,i,y) (opco<strong>de</strong>(C,i) = y)<br />
100 #<strong>de</strong>fine ivalco<strong>de</strong>(C,i) ((C)->inst[i].val.ival)<br />
101 #<strong>de</strong>fine pvalco<strong>de</strong>(C,i) ((C)->inst[i].val.p.p)<br />
102 #<strong>de</strong>fine nextinst(C) ((C)->nextinst)<br />
103 #<strong>de</strong>fine instline(C,i) ((C)->inst[i].line)<br />
104 #<strong>de</strong>fine co<strong>de</strong>Name(C) (C)->Filename<br />
105<br />
106<br />
107 #ifn<strong>de</strong>f EICH_<br />
108 type<strong>de</strong>f struct AR_t {<br />
109 val_t v;<br />
110 type_expr * type;<br />
111 _ unsigned short line;<br />
112 }AR_t;<br />
113<br />
114 #else<br />
115 type<strong>de</strong>f struct AR_t {<br />
116 val_t v;<br />
117 void * type;<br />
118 unsigned short line;<br />
119 }AR_t;<br />
120 #endif<br />
121<br />
122 #endif<br />
120
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
1<br />
2 /* datastruct.h<br />
3 *<br />
4 * (C) Copyright May 7 1995, Edmond J. Breen.<br />
5 * ALL RIGHTS RESERVED.<br />
6 * This co<strong>de</strong> may be copied for personal, non-profit use only.<br />
7 *<br />
8 */<br />
9<br />
10 #ifn<strong>de</strong>f DATASTRUCT_H<br />
11 #<strong>de</strong>fine DATASTRUCT_H<br />
12<br />
13 #if !<strong>de</strong>fined(_eic_ptr) && !<strong>de</strong>fined(_EiC)<br />
14 #<strong>de</strong>fine _eic_ptr<br />
15 type<strong>de</strong>f struct {void *p, *sp, *ep;} ptr_t;<br />
16 #endif<br />
17<br />
18<br />
19 #inclu<strong>de</strong> "stab.h"<br />
20<br />
21 #inclu<strong>de</strong> "eicval.h"<br />
22<br />
23<br />
24 type<strong>de</strong>f struct {<br />
25 int n;<br />
26 val_t * val;<br />
27 }eicstack_t;<br />
28<br />
29 type<strong>de</strong>f struct extern_t {<br />
30 char * name;<br />
31 type_expr * type;<br />
32 int n;<br />
33 unsigned *loc;<br />
34 struct extern_t *nxt;<br />
35 } extern_t;<br />
36<br />
37 /* methods for extern_t */<br />
38 #<strong>de</strong>fine crt_extern() xcalloc(sizeof(extern_t),1)<br />
39 #<strong>de</strong>fine getExtName(x) ((x)->name)<br />
40 #<strong>de</strong>fine setExtName(x,y) ((x)->name = y)<br />
41 #<strong>de</strong>fine getExtType(x) ((x)->type)<br />
42 #<strong>de</strong>fine setExtType(x,y) ((x)->type = y)<br />
43 #<strong>de</strong>fine getExtNext(x) ((x)->nxt)<br />
44 #<strong>de</strong>fine setExtNext(x,y) ((x)->nxt = y)<br />
45<br />
46<br />
47 type<strong>de</strong>f struct {<br />
48 char cl; /* closed flag */<br />
49 int n; /* number of members */<br />
50 int tsize; /* total size in bytes of struct */<br />
51 int align; /* alignment of structure */<br />
52 type_expr **type; /* member types */<br />
53 char **id; /* member names */<br />
54 int *offset; /* offsets to members data position*/<br />
55 int ntags; /* number of tags */<br />
56 type_expr **tag; /* tag types */<br />
57 }struct_t;<br />
58<br />
59<br />
60 type<strong>de</strong>f struct {<br />
61 unsigned short Tok;<br />
62 int Tab;__ /* name space table */<br />
63 unsigned char Pflag; /* processed flag */<br />
64 unsigned char Sclass; /* storage class */<br />
65 unsigned char Typequal; /* type qualifier */<br />
66 struct symentry_t * Sym;<br />
67 co<strong>de</strong>_t Co<strong>de</strong>;<br />
68 type_expr * Type;<br />
121
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
69 val_t Val;<br />
70 }token_t;<br />
71<br />
72 /*****<br />
73 #<strong>de</strong>fine getTokenVal(x) ((x).Val)<br />
74 #<strong>de</strong>fine setTokenVal(x,y) ((x).Val = (y))<br />
75 #<strong>de</strong>fine getTokenType(x) ((x).Type)<br />
76 #<strong>de</strong>fine setTokenType(x,y) ((x).Type = (y))<br />
77 #<strong>de</strong>fine getTokenCo<strong>de</strong>(x) ((x).Co<strong>de</strong>)<br />
78 #<strong>de</strong>fine setTokenCo<strong>de</strong>(x,y) ((x).Co<strong>de</strong> = (y))<br />
79 #<strong>de</strong>fine getTokenSym(x) ((x).Sym)<br />
80 #<strong>de</strong>fine setTokenSym(x,y) ((x).Sym = (y))<br />
81 #<strong>de</strong>fine getTokenTypequal(x) ((x).Typequal)<br />
82 #<strong>de</strong>fine setTokenTypequal(x,y) ((x).Typequal = (y))<br />
83 #<strong>de</strong>fine getTokenSclass(x) ((x).Sclass)<br />
84 #<strong>de</strong>fine setTokenSclass(x,y) ((x).Sclass = (y))<br />
85 #<strong>de</strong>fine getTokenPflag(x) ((x).Pflag)<br />
86 #<strong>de</strong>fine setTokenPflag(x,y) ((x).Pflag = (y))<br />
87 #<strong>de</strong>fine getTokenTab(x) ((x).Tab)<br />
88 #<strong>de</strong>fine setTokenTab(x,y) ((x).Tab = (y))<br />
89 #<strong>de</strong>fine getTokenTok(x) ((x).Tok)<br />
90 #<strong>de</strong>fine setTokenTok(x,y) ((x).Tok = (y))<br />
91 ********/<br />
92<br />
93<br />
94<br />
95 /*CUT symEntry*/<br />
96 type<strong>de</strong>f struct symentry_t {<br />
97 int tag; /* maker */<br />
98 unsigned int entry; /* entry number */<br />
99 struct symentry_t *next; /* link to next symentry */<br />
100 char *id; /* pointer to i<strong>de</strong>ntifier string */<br />
101 unsigned char sclass; /* storage class co<strong>de</strong> */<br />
102 unsigned char typequal; /* type qualifier */<br />
103 unsigned char level; /* scope level */<br />
104 unsigned char nspace; /* name space i<strong>de</strong>ntifier */<br />
105 char ass; /* used to flag assignment */<br />
106 type_expr * type; /* object type */<br />
107 val_t val; /* symbol value information */<br />
108 char *pname; /* previous file name */<br />
109 char *fname; /* file name pointer */<br />
110<br />
111 #if 0<br />
112 int calls; /* number of local references ma<strong>de</strong> */<br />
113 int Nref;<br />
114 struct symentry_t **ref; /* references */<br />
115 #endif<br />
116<br />
117 }symentry_t;<br />
118 /*END CUT*/<br />
119<br />
120 type<strong>de</strong>f struct {<br />
121 stab_t stab;<br />
122<br />
123 co<strong>de</strong>_t CODE;<br />
124 eicstack_t ARgar; /* for garbage collection of AR units*/<br />
125 unsigned int ARsize,sp;<br />
126 AR_t *AR; __ /* static activation record */<br />
127 unsigned int LARsize,lsp;<br />
128 AR_t *LAR;<br />
129 extern_t *link;<br />
130<br />
131 }environ_t;<br />
132<br />
133 #<strong>de</strong>fine getenvco<strong>de</strong>(env) ((env)->CODE)<br />
134<br />
135 type<strong>de</strong>f struct {<br />
136 int n; /* number of enumerators */<br />
122
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
137 int *eval; /* array of enumerator values */<br />
138 symentry_t **syms; /* list of symbol tabel entries */<br />
139 }enum_t;<br />
140<br />
141 type<strong>de</strong>f struct {<br />
142 int hsize;<br />
143 symentry_t **htab;<br />
144 }hashtab_t;<br />
145<br />
146 #endif<br />
123
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
1 /* global.h<br />
2 *<br />
3 * (C) Copyright May 7 1995, Edmond J. Breen.<br />
4 * ALL RIGHTS RESERVED.<br />
5 * This co<strong>de</strong> may be copied for personal, non-profit use only.<br />
6 *<br />
7 */<br />
8 #ifn<strong>de</strong>f GLOBALH<br />
9 #<strong>de</strong>fine GLOBALH<br />
10<br />
11 #<strong>de</strong>fine DONE 0<br />
12 #<strong>de</strong>fine BSIZE 128<br />
13 #<strong>de</strong>fine NONE -1<br />
14 #<strong>de</strong>fine EOS '\0'<br />
15 #<strong>de</strong>fine TRUE 1<br />
16 #<strong>de</strong>fine FALSE 0<br />
17<br />
18 type<strong>de</strong>f enum {/* the or<strong>de</strong>r of members in obj_t is important as it is<br />
19 * reflected in the binary operator function table BINFUN in<br />
20 * typesets.c<br />
21 */<br />
22 t_error, t_bool, t_char, t_uchar, t_short, t_ushort, /*5*/<br />
23 t_int, t_enum, t_uint, t_long, t_ulong, t_llong, /*11*/<br />
24 t_float, /*12*/<br />
25 t_double, t_pointer, t_void, t_struct, t_union, /*17*/<br />
26 t_lval, t_array, t_func, t_func<strong>de</strong>c, t_elem, t_eic, /*23*/<br />
27 t_builtin, t_var, t_hid<strong>de</strong>n, t_ref<br />
28 } obj_t;<br />
29<br />
30 /* unsafe macros */<br />
31 #<strong>de</strong>fine isArithmetic(t) (t >= t_char && t = t_char && t
<strong>Analyse</strong> <strong>dynamique</strong> <strong>de</strong> programmes C<br />
68 /*CUT nameSpaceCo<strong>de</strong>s*/<br />
69 extern int EiC_work_tab;<br />
70 enum{ /* name space co<strong>de</strong>s */<br />
71 eic_tab, /* name space for EiC commands */<br />
72 stand_tab, /* name space for basic variables */<br />
73 tag_tab, /* name space for struct/union and enumeration tags */<br />
74 lab_tab /* name space for goto labels */<br />
75 };<br />
76 /*END CUT*/<br />
77<br />
78 enum {eickmark, eicgstring, eicstay};<br />
79<br />
80<br />
81 #endif<br />
125
This document was created with Win2PDF available at http://www.daneprairie.com.<br />
The unregistered version of Win2PDF is for evaluation or non-commercial use only.