Quel fichier ce programme cherche-t-il ?
ltrace et strace sont deux outils qui affichent les appels qu’un programme fait, sans lire une seule instruction. ltrace montre les appels à la bibliothèque, strace ceux au système d’exploitation.
Un programme de la salle de lecture répond « Pas de profil. » sans dire de quel fichier il parle. Sa trace le dit. Rappel : seuls les programmes de votre labo se lisent ici.
À la fin de cette leçon
Remarque
Je peux voir avec ltrace et strace ce qu’un programme demande à la bibliothèque et au système.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Appel de bibliothèque | un appel à du code déjà écrit, fourni avec le système | strlen |
| Appel système | une demande du programme au noyau du système | openat |
| Noyau | le cœur du système, qui seul touche aux fichiers et à l’écran | |
| Trace | la liste des appels qu’un programme a faits, dans l’ordre | |
| ENOENT | le code du noyau pour « ce fichier n’existe pas » |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Une bibliothèque et un noyau, deux sortes d’appels
Un programme demande des choses à deux endroits. La bibliothèque fournit du code tout fait, comme strlen qui compte des lettres ou getenv qui lit une variable. Le noyau est le seul à toucher aux fichiers et à l’écran : on lui demande par un appel système, comme openat ou write.
Les deux Runs suivants écrivent profil.c et le compilent. Il lit la variable SALLE, puis cherche un fichier de réglages.
Écrire le programme profil.c
printf '%s\n' '#include <stdio.h>' '#include <stdlib.h>' '#include <string.h>' 'int main(void) {' ' const char *salle = getenv("SALLE");' ' if (salle == NULL) salle = "inconnue";' ' printf("Salle : %s (%d lettres)\n", salle, (int)strlen(salle));' ' FILE *f = fopen("/tmp/.profil-demo.cfg", "r");' ' if (f == NULL) { puts("Pas de profil."); return 1; }' ' fclose(f);' ' puts("Profil charge.");' ' return 0;' '}' > profil.cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Le compiler avec les réglages du labo
gcc -O0 -no-pie -fno-stack-protector -o profil profil.cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
ltrace affiche les appels à la bibliothèque
ltrace lance le programme et note chaque appel de bibliothèque avec ses arguments et ce qu’il rend. L’option -e getenv+fopen ne garde que ces deux fonctions.
Le trait de la sortie profil->getenv(…) dit que l’appel part du programme. nil veut dire « rien ». Le Run garde avec grep les lignes qui contiennent ->.
Suivre getenv et fopen
ltrace -e getenv+fopen ./profil 2>&1 | grep -- '->'Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Donner une valeur à la variable SALLE
SALLE=B12 ltrace -e getenv+fopen ./profil 2>&1 | grep -- '->'Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
strace affiche les appels au système
strace note chaque appel au noyau. -e trace=openat ne garde que l’ouverture de fichiers. Une ligne finit par = 3 si le fichier s’est ouvert, ou par = -1 ENOENT s’il n’existe pas.
Le premier Run garde avec grep la ligne qui contient ENOENT : le fichier que le programme a cherché en vain. Le second ne montre que l’appel write, avec le texte envoyé à l’écran.
Trouver le fichier qui manque
strace -e trace=openat ./profil 2>&1 | grep ENOENTAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Voir ce que le programme écrit
strace -e trace=write ./profil 2>&1 >/dev/nullAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Exemple travaillé : ce que montre chaque outil
| Outil | Il voit | Pour le programme profil |
|---|---|---|
| ltrace | Les appels de bibliothèque | getenv("SALLE"), puis fopen du fichier de réglages |
| strace | Les appels au noyau | openat du fichier, puis write du texte |
| Ni l’un ni l’autre | Les calculs entre deux appels | Le compte des lettres reste invisible |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Erreur fréquente
Attention
Beaucoup de gens pensent qu’une trace explique pourquoi le programme agit ainsi. Elle montre seulement ce qu’il a demandé et ce qu’on lui a répondu. Pour savoir pourquoi, il faut relire la décision avec objdump ou radare2. Et un ENOENT n’est pas toujours une erreur : le chargeur essaie plusieurs chemins de bibliothèques.
Pour aller plus loin
Lancez strace -e trace=openat,write ./profil 2>&1 | tail -3 et comptez les appels. Dans quel ordre le programme ouvre-t-il le fichier et écrit-il son texte ?
Dites ensuite ce que le programme ferait si le fichier cherché existait, en une phrase. Son texte « Profil charge. » est dans le C, et strings profil le montre sans lancer rien.