Comment fonctionne le débogueur Rust sous le capot : analyse pas à pas

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Débogueur Rust : comment regarder sous le capot step by step

\n\n

Vous êtes-vous déjà demandé : « Step by step interactive debugger for Rust : comment ça marche sous le capot ? » Si vous avez programmé en Rust et tenté de traquer un bug retors, vous avez sûrement rencontré GDB, LLDB ou même des outils comme rust-gdb. Mais comment parviennent-ils à arrêter l'exécution d'un programme, à afficher les valeurs des variables et à parcourir le code source pas à pas ?

\n\n

Dans cet article, nous ne nous contenterons pas d'expliquer comment utiliser le débogueur. Nous allons regarder à l'intérieur : du code machine aux points d'arrêt, des cadres de pile aux symboles de débogage. Si vous voulez savoir non seulement quoi faire, mais aussi pourquoi cela fonctionne, vous êtes au bon endroit.

\n\n

Pourquoi Rust est-il un cas particulier pour le débogage ?

\n\n

Rust est compilé en code natif via LLVM. Cela signifie que pour le débogage, nous utilisons les mêmes outils que pour le C/C++ : GDB et LLDB. Mais Rust ajoute ses propres complexités :

\n\n
    \n
  • Propriété et emprunt — les variables peuvent être déplacées, et le débogueur doit le suivre.
  • \n
  • Monomorphisation des génériques — chaque T se transforme en un type concret, et les noms de fonctions deviennent « chiffrés ».
  • \n
  • Optimisations — le compilateur peut réorganiser le code, et le débogueur doit « dérouler » cela en sens inverse.
  • \n
\n\n

C'est pourquoi le step by step interactive debugger for Rust n'est pas simplement un lancement de programme sous GDB. C'est tout un système qui traduit les adresses machine en lignes de code source.

\n\n

Comment fonctionne un point d'arrêt (breakpoint) sous le capot ?

\n\n

Imaginez : vous placez un point d'arrêt sur la ligne println!("Hello");. Que se passe-t-il dans le processeur ?

\n\n

Lorsque vous lancez un programme sous le débogueur, il effectue les opérations suivantes :

\n\n
    \n
  1. Il lit les informations de débogage (format DWARF) dans le fichier exécutable. Elles contiennent la correspondance : adresse mémoire → ligne dans le code.
  2. \n
  3. Il remplace l'instruction à cette adresse par une commande spéciale INT3 (sur x86 — 0xCC). C'est un « piège » pour le processeur.
  4. \n
  5. Lorsque l'exécution atteint ce point, le processeur génère un signal SIGTRAP.
  6. \n
  7. Le débogueur intercepte le signal, sauvegarde l'état des registres et vous affiche la ligne actuelle.
  8. \n
\n\n

Voici un exemple de programme simple en Rust :

\n\n
fn main() {\n    let x = 42;\n    let y = x + 10; // <-- point d'arrêt\n    println!("y = {}", y);\n}
\n\n

Lorsque vous placez un breakpoint sur let y = x + 10;, le débogueur trouve l'adresse de cette instruction dans le binaire et remplace le premier octet par 0xCC. Après l'arrêt, il restaure l'octet d'origine, exécute l'étape, puis replace le piège — si vous souhaitez continuer.

\n\n

Step over, step into, step out — comment le débogueur sait-il où se trouve la « ligne suivante » ?

\n\n

C'est sans doute la partie la plus magique. Comment le débogueur sait-il qu'après let y = x + 10; vient println! ?

\n\n

Tout est question de tables de débogage. Le compilateur Rust (via LLVM) génère une section .debug_line au format DWARF. C'est une table compressée qui fait correspondre les adresses des instructions aux numéros de ligne dans le code source.

\n\n

Par exemple, pour notre code, la table pourrait ressembler à ceci :

\n\n
Adresse 0x1000 → ligne 2 (let x = 42;)\nAdresse 0x1010 → ligne 3 (let y = x + 10;)\nAdresse 0x1020 → ligne 4 (println!)
\n\n

Lorsque vous appuyez sur step over, le débogueur calcule l'adresse de l'instruction suivante qui n'appartient pas à la ligne actuelle, et y place un point d'arrêt temporaire. L'exécution continue jusqu'à cette adresse — et vous passez à la ligne suivante.

\n\n

Pour step into — le débogueur vérifie s'il y a un appel de fonction à l'adresse actuelle. Si oui, il cherche la première ligne de cette fonction

Blogs

Book Recommendations