19.06.2014 Views

Rim Chaabane. Analyse dynamique de ... - Université Paris 8

Rim Chaabane. Analyse dynamique de ... - Université Paris 8

Rim Chaabane. Analyse dynamique de ... - Université Paris 8

SHOW MORE
SHOW LESS

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.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!