Les syscalls de Linux
Un programme en espace utilisateur ne fait rien directement: quand il lit un fichier, alloue de la mémoire ou envoie un paquet réseau, il demande au kernel de le faire. Cette demande est un syscall (system call): le programme exécute une instruction spéciale (int 0x80 ou sysenter sur x86), le kernel prend la main, exécute la demande et rend le contrôle au programme. C’est la frontière entre l’espace utilisateur (ring 3) et l’espace kernel (ring 0).
Les syscalls de base
Linux expose environ 300 syscalls. Les plus fréquents:
| syscall | ce qu’il fait |
|---|---|
read | lire depuis un fd |
write | écrire dans un fd |
open | ouvrir un fichier |
close | fermer un fd |
stat | les métadonnées d’un fichier |
mmap | mapper de la mémoire |
fork/clone | créer un process |
execve | charger un binaire |
socket | créer un socket |
connect | se connecter à un socket distant |
bind | attacher un socket à un port |
listen | écouter sur un socket |
accept | accepter une connexion |
Chaque syscall a un numéro (l’offset dans la sys_call_table) et des arguments passés dans les registres (eax = numéro, ebx/ecx/edx/esi/edi = arguments sur x86 32 bits).
strace: observer les syscalls
strace intercepte les syscalls d’un process (via ptrace) et les affiche:
strace ls
execve("/bin/ls", ["ls"], [/* 24 vars */]) = 0
brk(0) = 0x805c000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f7a000
open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=62350, ...}) = 0
mmap2(NULL, 62350, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f6b000
close(3) = 0
...
Chaque ligne est un syscall: le nom, les arguments et la valeur de retour (= 0 signifie succès, -1 signifie erreur avec errno). Le ENOENT après open("/etc/ld.so.preload") signifie que le fichier n’existe pas, ce qui est normal (ld.so.preload est optionnel).
strace sur un process existant
strace -p 12345
Attache strace à un process en cours (via ptrace, donc nécessite root ou être le propriétaire).
Les options qui changent tout
strace -f ls # suivre aussi les processus enfants
strace -e trace=open,read ls # seulement open et read
strace -e trace=network wget example.com # seulement les syscalls réseau
strace -c ls # compter les syscalls au lieu de les afficher
strace -t ls # afficher les timestamps
strace -c est le plus instructif:
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
39.87 0.000257 257 1 execve
28.87 0.000186 3 62 13 open
15.78 0.000102 2 55 2 read
...
62 appels à open pour lister un directory: c’est le chargement des librairies partagées (chaque librairie est cherchée dans chaque directory du LD_LIBRARY_PATH). Le errors montre 13 opens qui ont échoué: les directories où le fichier n’existe pas. C’est le mécanisme de recherche de ld.so.
Ce que strace révèle
strace révèle ce que le programme fait réellement, pas ce qu’il prétend faire. Un programme qui prétend lire un fichier de config révèle les directories où il cherche, l’ordre de recherche et les erreurs errno à chaque tentative. Un programme qui “ne fonctionne pas” révèle souvent un open sur un fichier qui n’existe pas avec un ENOENT. C’est l’outil de debug le plus under-rated de Linux.
[edit: 2026] strace n’a pas changé. Les syscalls ont augmenté (environ 450 en 2026, contre 300 en 2008, avec io_uring, bpf, clone3, openat2). ltrace (tracing des appels de librairie) complète strace (tracing des syscalls). strace -c reste l’outil de premier diagnostic et strace -f reste le seul moyen de savoir ce qu’un programme fait vraiment sans lire son code source. Le ptrace est toujours le mécanisme et ptrace est toujours la cible des durcissements de sécurité (Yama LSM).