🔝 Retour au Sommaire
LLDB (Low Level Debugger) est le débogueur moderne et puissant qui a remplacé GDB (GNU Debugger) pour les plateformes Apple et de nombreux systèmes Linux. Delphi 13 Florence intègre la version 12 de LLDB, apportant des améliorations significatives en termes de performances, de stabilité et de fonctionnalités.
Pour un débutant, LLDB peut sembler intimidant avec son interface en ligne de commande et ses nombreuses options. Cependant, une fois que vous comprenez ses concepts de base, LLDB devient un outil extraordinairement puissant qui vous donne un contrôle total sur l'exécution de votre application.
Ce chapitre vous guide à travers les capacités avancées de LLDB v12, en commençant par les bases et en progressant vers des techniques sophistiquées de débogage.
LLDB est un débogueur de nouvelle génération développé par le projet LLVM. Il est utilisé par :
- Xcode d'Apple (pour macOS et iOS)
- Android Studio (pour le débogage natif)
- De nombreux IDE modernes
- Delphi (depuis la version 10.3 Rio)
LLDB offre une architecture modulaire et extensible, ce qui le rend adapté à de nombreuses plateformes et langages de programmation.
Performances supérieures
- Démarrage plus rapide
- Réponse plus réactive lors des commandes
- Meilleure gestion de la mémoire
Architecture moderne
- Code plus propre et maintenable
- Meilleure extensibilité
- Support natif des nouvelles plateformes
Support Apple
- Seul débogueur officiellement supporté pour macOS et iOS modernes
- Intégration optimale avec les outils Apple
Support Delphi amélioré
- Meilleure compréhension des types Object Pascal
- Visualisation améliorée des structures Delphi
- Intégration fluide avec l'IDE
Lorsque vous déboguez une application Delphi sur :
- macOS : LLDB est utilisé automatiquement
- iOS : LLDB est le seul débogueur disponible
- Linux : LLDB est utilisé (selon la configuration)
- Android : LLDB peut être utilisé pour le débogage natif
- Windows : Le débogueur Windows natif est utilisé par défaut
Delphi 13 Florence intègre LLDB version 12, qui apporte de nombreuses améliorations par rapport aux versions précédentes.
Démarrage accéléré
Le temps de démarrage d'une session de débogage a été réduit de manière significative :
- Chargement plus rapide des symboles de débogage
- Initialisation optimisée du débogueur
- Connexion plus rapide aux processus cibles
Temps de réponse amélioré
Les opérations courantes sont plus rapides :
- Évaluation d'expressions (variables, propriétés)
- Navigation dans la pile d'appels
- Inspection de structures complexes
- Exécution pas à pas
Gestion mémoire optimisée
LLDB v12 utilise moins de mémoire lors du débogage d'applications complexes, permettant :
- Le débogage d'applications plus volumineuses
- Des sessions de débogage plus longues sans ralentissement
- Meilleure stabilité générale
Chaînes de caractères
LLDB v12 comprend mieux les types de chaînes Delphi :
String(UnicodeString)AnsiStringShortStringWideString
L'affichage est plus naturel et ne montre plus de données brutes illisibles.
Tableaux dynamiques
Les tableaux dynamiques (TArray<T>) sont maintenant :
- Correctement reconnus et affichés avec leur taille
- Navigables élément par élément
- Affichés avec leur contenu réel
Génériques
Le support des types génériques a été considérablement amélioré :
TList<T>,TDictionary<K,V>, etc. sont correctement reconnus- Les types paramétrés s'affichent clairement
- L'inspection des éléments internes fonctionne mieux
Enregistrements (Records)
Les records complexes, notamment ceux avec méthodes et opérateurs, sont mieux gérés :
- Affichage structuré des champs
- Support des records génériques
- Meilleure visualisation des variants records
Moins de crashs
LLDB v12 est plus robuste face à :
- Des structures de données corrompues
- Des pointeurs invalides
- Des conditions de threading complexes
- Des applications avec beaucoup de modules
Récupération d'erreurs
En cas de problème, LLDB v12 :
- Tente de récupérer gracieusement
- Fournit des messages d'erreur plus clairs
- Maintient la session de débogage active si possible
Débogage multi-thread amélioré
Le support du multi-threading a été renforcé :
- Meilleure synchronisation entre threads
- Moins de deadlocks lors du débogage
- Visualisation plus claire de l'état des threads
Watchpoints améliorés
Les watchpoints (surveillance de modification de mémoire) sont :
- Plus fiables
- Plus rapides
- Supportent plus de cas d'usage
Expressions conditionnelles plus puissantes
Les conditions dans les breakpoints peuvent maintenant :
- Évaluer des expressions plus complexes
- Appeler des fonctions (avec précaution)
- Utiliser des opérateurs avancés
Support de scripting Python amélioré
LLDB v12 offre une meilleure intégration avec Python pour :
- Automatiser des tâches de débogage
- Créer des commandes personnalisées
- Analyser des dumps mémoire
Lorsque vous déboguez une application sur une plateforme utilisant LLDB, vous pouvez accéder à la console LLDB directement depuis l'IDE.
Ouvrir la console LLDB :
- Démarrez une session de débogage (F9)
- Mettez l'application en pause (point d'arrêt ou pause manuelle)
- Dans Delphi, allez dans View > Debug Windows > LLDB Console
- Une fenêtre s'ouvre affichant l'invite LLDB :
(lldb)
À quoi ressemble la console :
(lldb) target create "/Users/dev/MyApp/MyApp"
Current executable set to '/Users/dev/MyApp/MyApp' (x86_64).
(lldb) process attach --pid 12345
Process 12345 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
(lldb)
Vous pouvez maintenant taper des commandes LLDB directement.
Avant d'explorer les commandes avancées, familiarisons-nous avec les commandes de base.
help : Obtenir de l'aide
(lldb) help
(lldb) help breakpoint # Aide sur les breakpoints
(lldb) help thread # Aide sur les threads
process : Contrôler le processus
(lldb) process continue # Reprendre l'exécution (équivalent F9)
(lldb) process interrupt # Mettre en pause
(lldb) process kill # Terminer le processus
thread : Travailler avec les threads
(lldb) thread list # Lister tous les threads
(lldb) thread select 2 # Sélectionner le thread 2
(lldb) thread backtrace # Voir la pile du thread actuel
frame : Naviguer dans la pile d'appels
(lldb) frame select 0 # Sélectionner le frame 0 (fonction actuelle)
(lldb) frame variable # Voir toutes les variables locales
(lldb) frame info # Infos sur le frame actuel
expression (ou expr ou p) : Évaluer une expression
(lldb) expr MonAge
(int) $0 = 25
(lldb) p MonNom
(string) $1 = "Jean Dupont"
(lldb) expr MaListe.Count
(int) $2 = 10
step : Exécution pas à pas
(lldb) step # Équivalent F7 (Step Into)
(lldb) next # Équivalent F8 (Step Over)
(lldb) finish # Équivalent Shift+F8 (Step Out)
(lldb) continue # Équivalent F9 (Continue)
Raccourcis :
spourstepnpournextcpourcontinue
backtrace (ou bt) : Pile d'appels
(lldb) bt
* thread #1, queue = 'com.apple.main-thread'
* frame #0: 0x00000001000015a0 MyApp`TForm1.Button1Click at MainForm.pas:42
frame #1: 0x00000001000023b0 MyApp`TControl.Click at Controls.pas:1234
frame #2: 0x0000000100003210 MyApp`TButton.Click at Buttons.pas:567
frame #3: 0x0000000100005678 MyApp`ApplicationRun at Forms.pas:890
frame variable : Variables locales
(lldb) frame variable
(int) Counter = 5
(string) Name = "Test"
(TMyObject *) MyObj = 0x00007f9e8c400000
thread list : État de tous les threads
(lldb) thread list
Process 12345 stopped
* thread #1: tid = 0x1a03, 0x00000001000015a0 MyApp`TForm1.Button1Click
thread #2: tid = 0x1a04, 0x00007fff204050c0 libsystem_kernel.dylib`__workq_kernreturn
thread #3: tid = 0x1a05, 0x00007fff204050c0 libsystem_kernel.dylib`__workq_kernreturn
L'astérisque (*) indique le thread actuel.
Bien que vous puissiez créer des breakpoints dans l'IDE, LLDB offre plus de contrôle.
Breakpoint sur une ligne spécifique :
(lldb) breakpoint set --file MainForm.pas --line 42
Breakpoint 1: where = MyApp`TForm1.Button1Click + 20 at MainForm.pas:42
Raccourci :
(lldb) br s -f MainForm.pas -l 42
Breakpoint sur une fonction :
(lldb) breakpoint set --name TForm1.Button1Click
Breakpoint 2: where = MyApp`TForm1.Button1Click at MainForm.pas:40
Raccourci :
(lldb) br s -n TForm1.Button1Click
Breakpoint avec wildcard :
(lldb) breakpoint set --func-regex ".*Click"
# S'arrête sur toutes les fonctions dont le nom se termine par "Click"
Les breakpoints conditionnels ne se déclenchent que si une condition est vraie.
Syntaxe :
(lldb) breakpoint set -f MainForm.pas -l 42 -c "Counter > 100"
L'application ne s'arrêtera à la ligne 42 que si Counter est supérieur à 100.
Exemples de conditions :
# S'arrêter si un pointeur est nil
(lldb) br s -f MyUnit.pas -l 50 -c "MyObject == nullptr"
# S'arrêter si une chaîne contient un texte
(lldb) br s -f MyUnit.pas -l 75 -c "strcmp(Name, \"Test\") == 0"
# S'arrêter sur une valeur spécifique
(lldb) br s -f MyUnit.pas -l 100 -c "ID == 12345"
Modifier une condition existante :
(lldb) breakpoint modify 1 --condition "Age >= 18"
Déclencher un breakpoint après N passages :
(lldb) breakpoint set -f MyUnit.pas -l 42 --ignore-count 99
Le breakpoint se déclenchera au 100ème passage (ignore les 99 premiers).
Cas d'usage :
Utile dans les boucles où vous voulez examiner un état spécifique :
for i := 0 to 999 do
begin
TraiterElement(i); // Breakpoint qui se déclenche au 500ème passage
end;Exécuter des commandes LLDB automatiquement quand un breakpoint est atteint :
(lldb) breakpoint set -f MyUnit.pas -l 42
Breakpoint 3: where = MyApp`ProcessData...
(lldb) breakpoint command add 3
Enter your debugger command(s). Type 'DONE' to end.
> frame variable Counter
> expr MyList.Count
> continue
> DONE
Maintenant, chaque fois que le breakpoint 3 est atteint, LLDB :
- Affiche la valeur de
Counter - Affiche
MyList.Count - Continue automatiquement l'exécution
Cas d'usage :
Journaliser des valeurs sans arrêter l'exécution :
(lldb) br s -f MyUnit.pas -l 50
(lldb) br command add 1
> expr printf("Counter = %d\n", Counter)
> continue
> DONE
Lister tous les breakpoints :
(lldb) breakpoint list
Current breakpoints:
1: file = 'MainForm.pas', line = 42, exact_match = 0, locations = 1
2: name = 'TForm1.Button1Click', locations = 1
3: file = 'DataModule.pas', line = 150, exact_match = 0, locations = 1
Activer/désactiver :
(lldb) breakpoint disable 1 # Désactiver le breakpoint 1
(lldb) breakpoint enable 1 # Réactiver le breakpoint 1
Supprimer :
(lldb) breakpoint delete 1 # Supprimer le breakpoint 1
(lldb) breakpoint delete # Supprimer TOUS les breakpoints (demande confirmation)
Informations détaillées :
(lldb) breakpoint list 1 -v # Détails verbeux sur le breakpoint 1
Les watchpoints (points d'observation) sont différents des breakpoints. Ils surveillent une zone mémoire et s'arrêtent quand cette mémoire est lue ou modifiée.
Surveiller une variable :
(lldb) watchpoint set variable MonCompteur
Watchpoint created: Watchpoint 1: addr = 0x7ffeefbff5a8 size = 4 state = enabled type = w
Le programme s'arrêtera chaque fois que MonCompteur est modifié.
Surveiller une adresse mémoire spécifique :
(lldb) watchpoint set expression -- 0x7ffeefbff5a8
Surveiller en lecture ET écriture :
(lldb) watchpoint set variable MonCompteur --watch read_write
Surveiller uniquement en écriture (défaut) :
(lldb) watchpoint set variable MonCompteur --watch write
Trouver qui modifie une variable
Vous avez une variable globale qui change de manière inattendue :
var
GlobalCounter: Integer = 0; // Qui modifie cette variable ?(lldb) watchpoint set variable GlobalCounter
(lldb) continue
Le programme s'arrêtera à la ligne exacte qui modifie GlobalCounter.
Détecter la corruption de données
Si une structure de données se corrompt :
type
TImportantData = record
ID: Integer;
Status: Integer;
Name: string;
end;
var
MyData: TImportantData;(lldb) watchpoint set expression -- &MyData
Toute modification de n'importe quel champ de MyData déclenchera le watchpoint.
Débogage de pointeurs
Surveiller où un pointeur est modifié :
(lldb) watchpoint set variable MyPointer
Lister :
(lldb) watchpoint list
Number of supported hardware watchpoints: 4
Current watchpoints:
Watchpoint 1: addr = 0x7ffeefbff5a8 size = 4 state = enabled type = w
old value: 5
new value: 10
Désactiver/activer :
(lldb) watchpoint disable 1
(lldb) watchpoint enable 1
Supprimer :
(lldb) watchpoint delete 1
Limitation importante :
Les watchpoints utilisent des ressources matérielles limitées. La plupart des processeurs supportent seulement 4 watchpoints simultanés. Si vous en créez trop, LLDB vous avertira.
LLDB permet d'inspecter directement la mémoire brute.
Syntaxe de base :
(lldb) memory read <adresse>
Exemples :
# Lire 16 octets à une adresse
(lldb) memory read --size 1 --count 16 0x00007ffeefbff5a8
# Lire sous forme de mots de 4 octets (integers)
(lldb) memory read --size 4 --count 10 0x00007ffeefbff5a8
# Afficher en hexadécimal ET en ASCII
(lldb) memory read --format hex 0x00007ffeefbff5a8
Formats d'affichage :
hex: Hexadécimaldecimal: Décimalbinary: Binairecharacter: Caractères ASCIIfloat: Nombres à virgule flottantepointer: Adresses pointeur
Exemple de sortie :
(lldb) memory read --size 1 --count 32 --format hex 0x00007ffeefbff5a8
0x7ffeefbff5a8: 0x05 0x00 0x00 0x00 0x48 0x65 0x6c 0x6c
0x7ffeefbff5b0: 0x6f 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Pour utiliser memory read, vous avez besoin de l'adresse. Comment la trouver ?
(lldb) expr &MonCompteur
(int *) $3 = 0x00007ffeefbff5a8
(lldb) memory read 0x00007ffeefbff5a8
Ou directement :
(lldb) memory read `&MonCompteur`
Les backticks ` permettent d'évaluer l'expression et d'utiliser le résultat.
Attention : Modifier la mémoire directement peut corrompre votre application. Utilisez cette fonctionnalité avec précaution.
(lldb) memory write 0x00007ffeefbff5a8 0x0A
Ceci écrit la valeur 0x0A (10 en décimal) à l'adresse spécifiée.
Cas d'usage :
Tester rapidement comment l'application se comporte avec une valeur différente :
if Status = 1 then
ProcessNormal
else
ProcessSpecial;Pendant le débogage, vous pouvez changer Status en mémoire pour forcer un chemin spécifique.
Rechercher un pattern dans la mémoire :
(lldb) memory find --size 4 --count 1 --expression 0x12345678 0x100000000 0x200000000
Recherche la valeur 0x12345678 dans la plage mémoire de 0x100000000 à 0x200000000.
Rechercher une chaîne :
(lldb) memory find --string "Error" 0x100000000 0x200000000
Cas d'usage :
Trouver où une chaîne spécifique est stockée en mémoire, utile pour déboguer des problèmes de corruption de chaînes.
Nous avons vu les bases avec expr. Allons plus loin.
Opérations arithmétiques :
(lldb) expr 2 + 2
(int) $0 = 4
(lldb) expr MonAge * 2
(int) $1 = 50
(lldb) expr (Prix * Quantite) * 1.20
(double) $2 = 144.0
Comparaisons :
(lldb) expr Age > 18
(bool) $3 = true
(lldb) expr Status == 0
(bool) $4 = false
LLDB peut appeler des fonctions pendant le débogage. C'est puissant mais potentiellement dangereux.
Exemple :
function CalculerTotal(Prix: Double; Quantite: Integer): Double;
begin
Result := Prix * Quantite;
end;(lldb) expr CalculerTotal(10.5, 3)
(double) $5 = 31.5
Précautions :
- La fonction ne doit pas avoir d'effets de bord dangereux
- Évitez d'appeler des fonctions qui modifient l'état global
- Ne jamais appeler des fonctions qui pourraient planter
- Les fonctions peuvent avoir accès aux variables du scope actuel
Cas d'usage utile :
(lldb) expr ShowMessage("Debug: Counter = " + IntToStr(Counter))
Afficher un message depuis le débogueur sans recompiler.
LLDB vous permet de créer des variables temporaires pendant le débogage :
(lldb) expr int $mytemp = 42
(lldb) expr $mytemp * 2
(int) $6 = 84
Les variables commençant par $ sont des variables LLDB, pas des variables de votre programme.
Usage :
Stocker un calcul complexe pour y faire référence plus tard :
(lldb) expr double $total = (Prix * Quantite) * 1.20
(lldb) expr $total > 100
(bool) $7 = true
Forcer un type lors de l'évaluation :
(lldb) expr (int)MyFloatValue
(lldb) expr (char*)MyPointer
(lldb) expr (TMyClass*)MyObject
Utile quand LLDB ne peut pas déterminer automatiquement le type.
Les applications modernes utilisent souvent plusieurs threads. LLDB offre des outils puissants pour les déboguer.
(lldb) thread list
Process 12345 stopped
* thread #1, name = 'MainThread', queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
thread #2, name = 'WorkerThread1'
thread #3, name = 'WorkerThread2'
thread #4, name = 'NetworkThread'
L'astérisque (*) indique le thread actuellement sélectionné.
(lldb) thread select 2
* thread #2, name = 'WorkerThread1'
frame #0: 0x0000000100002340 MyApp`WorkerProc at Worker.pas:25
Toutes les commandes suivantes s'appliqueront à ce thread.
(lldb) thread backtrace all
Affiche la stack trace de TOUS les threads, utile pour comprendre ce que fait toute l'application.
Exemple de sortie :
* thread #1, name = 'MainThread'
* frame #0: 0x0000000100001000 MyApp`TForm1.Button1Click at MainForm.pas:42
frame #1: 0x0000000100002000 MyApp`TControl.Click at Controls.pas:200
thread #2, name = 'WorkerThread1'
frame #0: 0x00007fff204050c0 libsystem_kernel.dylib`__psynch_cvwait
frame #1: 0x0000000100003000 MyApp`TWorkerThread.Execute at Worker.pas:30
thread #3, name = 'WorkerThread2'
frame #0: 0x00007fff204050d0 libsystem_kernel.dylib`__select
frame #1: 0x0000000100004000 MyApp`NetworkWait at Network.pas:50
(lldb) thread continue 2
Reprend l'exécution du thread 2 seulement, les autres restent en pause.
(lldb) thread apply all bt
Exécute bt (backtrace) sur tous les threads.
Créer un breakpoint qui ne se déclenche que sur un thread spécifique :
(lldb) breakpoint set -f Worker.pas -l 30 --thread-index 2
Le breakpoint ne se déclenchera que quand le thread 2 atteint cette ligne.
Un deadlock survient quand deux threads s'attendent mutuellement.
Diagnostic :
- L'application semble figée
- Mettez en pause (Pause button ou Ctrl+C dans la console)
- Examinez tous les threads :
(lldb) thread backtrace all
- Cherchez les patterns de verrouillage :
- Thread 1 attend un mutex détenu par Thread 2
- Thread 2 attend un mutex détenu par Thread 1
Exemple de ce que vous pourriez voir :
thread #1: waiting on mutex at 0x12345678
thread #2: waiting on mutex at 0x23456789
En examinant les stack traces, vous pouvez identifier l'ordre des verrouillages qui cause le deadlock.
Les data races surviennent quand plusieurs threads accèdent à la même donnée sans synchronisation.
Utiliser les watchpoints :
(lldb) watchpoint set variable SharedCounter
Maintenant, si plusieurs threads modifient SharedCounter, vous verrez exactement quand et par quel thread.
LLDB supporte les scripts Python pour automatiser des tâches complexes.
(lldb) script print("Hello from Python")
Hello from Python
(lldb) script
>>> import lldb
>>> target = lldb.debugger.GetSelectedTarget()
>>> process = target.GetProcess()
>>> print(f"Process ID: {process.GetProcessID()}")
Process ID: 12345
>>>
Tapez Ctrl+D pour sortir du mode script.
Vous pouvez créer des commandes LLDB personnalisées en Python.
Exemple : Commande pour afficher toutes les variables locales formatées
# Fichier : mycommands.py
import lldb
def show_all_vars(debugger, command, result, internal_dict):
target = debugger.GetSelectedTarget()
process = target.GetProcess()
thread = process.GetSelectedThread()
frame = thread.GetSelectedFrame()
print("=== Variables locales ===")
for var in frame.GetVariables(True, True, True, True):
print(f"{var.GetName()} = {var.GetValue()}")
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand('command script add -f mycommands.show_all_vars showvars')
print("Commande 'showvars' chargée")Charger le script :
(lldb) command script import /path/to/mycommands.py
Commande 'showvars' chargée
Utiliser la commande :
(lldb) showvars
=== Variables locales ===
Counter = 5
Name = "Test"
MyObj = 0x00007f9e8c400000
Exemple : Détecter les fuites mémoire potentielles
def check_nil_pointers(debugger, command, result, internal_dict):
frame = debugger.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame()
nil_pointers = []
for var in frame.GetVariables(True, True, True, True):
if var.GetTypeName().endswith('*'): # C'est un pointeur
if var.GetValueAsUnsigned() == 0:
nil_pointers.append(var.GetName())
if nil_pointers:
print("⚠️ Pointeurs nil détectés:")
for name in nil_pointers:
print(f" - {name}")
else:
print("✓ Aucun pointeur nil")Créez un fichier .lldbinit dans votre home directory :
# ~/.lldbinit
command script import ~/lldb_scripts/mycommands.py
command script import ~/lldb_scripts/memory_tools.py
# Alias utiles
command alias pv frame variable
command alias bt thread backtrace Ces commandes seront exécutées automatiquement au démarrage de LLDB.
Format personnalisé pour les expressions :
(lldb) type summary add --summary-string "Count: ${var.FCount}" TList
Maintenant, quand vous affichez un TList, LLDB montrera automatiquement son count.
Affichage en hexadécimal :
(lldb) expr --format hex -- MonEntier
(int) $8 = 0x0000007b
Affichage en binaire :
(lldb) expr --format binary -- MonEntier
(int) $9 = 0b01111011
Rediriger la sortie d'une commande vers un fichier :
(lldb) log enable lldb all -f /tmp/lldb.log
Tous les événements LLDB seront journalisés dans /tmp/lldb.log.
Voir le code assembleur :
(lldb) disassemble
Affiche le code assembleur de la fonction actuelle.
Désassembler une fonction spécifique :
(lldb) disassemble --name TForm1.Button1Click
Cas d'usage :
Comprendre exactement ce que fait le compilateur, utile pour :
- Optimisation de performance
- Comprendre des bugs subtils
- Analyse de sécurité
Voir les registres du processeur :
(lldb) register read
Exemple de sortie (x64) :
General Purpose Registers:
rax = 0x0000000000000005
rbx = 0x00007ffeefbff5a8
rcx = 0x0000000000000000
rdx = 0x0000000000000010
...
Modifier un registre :
(lldb) register write rax 0x0000000000000042
Attention : Modifier les registres peut rendre votre programme instable. À utiliser seulement si vous savez ce que vous faites.
Lister les modules (DLLs, frameworks) chargés :
(lldb) image list
[ 0] 2A1E5B3C-0000-0000-0000-000000000000 0x0000000100000000 /Users/dev/MyApp/MyApp
[ 1] 65289842-0000-0000-0000-000000000000 0x00007fff20400000 /usr/lib/libSystem.B.dylib
[ 2] 91FD34AB-0000-0000-0000-000000000000 0x00007fff30000000 /System/Library/Frameworks/Foundation.framework/Foundation
Chercher dans quel module se trouve une adresse :
(lldb) image lookup --address 0x0000000100001234
Address: MyApp[0x0000000000001234] (MyApp.__TEXT.__text + 1234)
Summary: MyApp`TForm1.ProcessData at MainForm.pas:125
Si votre application a planté et généré un core dump, vous pouvez l'analyser avec LLDB.
Charger un core dump :
lldb --core /path/to/core.dump /path/to/executableAnalyser :
(lldb) bt
(lldb) frame variable
(lldb) thread list
Vous pouvez examiner l'état exact du programme au moment du crash.
Lorsque vous utilisez la console LLDB dans Delphi, certaines commandes peuvent ne pas se synchroniser avec l'interface graphique.
Commandes qui se synchronisent :
breakpoint: Les breakpoints apparaîtront dans l'éditeurthread: Le thread actuel se synchroniseraframe: La fenêtre de code suivra
Commandes qui ne se synchronisent pas toujours :
- Modifications de variables via
expr - Watchpoints créés manuellement
- Commandes avancées de script
Conseil : Après des opérations complexes dans la console LLDB, rafraîchissez l'IDE en cliquant dans une fenêtre de débogage (Watch List, Call Stack).
Stratégie recommandée :
-
Utiliser l'IDE pour :
- Placer des breakpoints simples
- Navigation de base (Step Into, Step Over)
- Inspection rapide de variables (hover)
-
Utiliser la console LLDB pour :
- Breakpoints conditionnels complexes
- Watchpoints
- Inspection mémoire détaillée
- Analyse multi-thread avancée
- Scripts et automatisation
Pour partager des informations de débogage avec votre équipe :
(lldb) thread backtrace all > /tmp/all_threads.txt
(lldb) frame variable > /tmp/variables.txt
Les fichiers peuvent être ouverts dans un éditeur de texte et partagés.
Ne tentez pas de maîtriser toutes les commandes LLDB d'un coup. Commencez par :
bt(backtrace)frame variableexprthread list
Ajoutez progressivement des commandes plus avancées à votre arsenal.
Pour les commandes que vous utilisez souvent :
(lldb) command alias pv frame variable
(lldb) command alias allvars frame variable --show-types
Maintenant pv est un raccourci pour frame variable.
Quand vous trouvez quelque chose d'intéressant :
# Créer un fichier de notes
(lldb) log enable lldb all -f debug_session.log
Vous aurez un enregistrement complet de votre session.
LLDB conserve un historique des commandes. Utilisez les flèches ↑ et ↓ pour naviguer dans l'historique.
Tapez le début d'une commande et appuyez sur Tab pour l'auto-complétion :
(lldb) break<Tab>
breakpoint break
Appeler des fonctions depuis LLDB peut avoir des effets de bord. Ne le faites que si :
- Vous comprenez ce que fait la fonction
- La fonction n'a pas d'effets de bord critiques
- Vous êtes prêt à redémarrer le débogage si quelque chose tourne mal
Si vous avez créé de nombreux breakpoints complexes :
(lldb) breakpoint write -f /tmp/my_breakpoints.txt
Pour les recharger plus tard :
(lldb) breakpoint read -f /tmp/my_breakpoints.txt
LLDB a une documentation complète intégrée :
(lldb) help
(lldb) help breakpoint
(lldb) help breakpoint set
Consultez-la régulièrement pour découvrir de nouvelles fonctionnalités.
Créez une petite application de test pour expérimenter avec les commandes LLDB sans risquer d'endommager un projet important.
Si vous trouvez une technique utile, documentez-la et partagez-la avec votre équipe.
Symptôme : Les commandes LLDB ne retournent rien ou prennent très longtemps.
Solutions :
- Vérifiez la connexion réseau (pour le débogage distant)
- Vérifiez que le processus cible est toujours en cours :
process status - Si figé, interrompez : Ctrl+C
- En dernier recours, arrêtez et relancez la session de débogage
Cause : LLDB ne peut pas trouver ou évaluer l'expression.
Solutions :
- Vérifiez l'orthographe
- Assurez-vous que la variable est dans le scope actuel
- Vérifiez que les symboles de débogage sont présents
- Essayez de spécifier le type explicitement :
(int)MaVariable
Symptôme : Les noms de variables n'apparaissent pas, tout est en adresses.
Solution :
- Recompilez avec les informations de débogage activées
- Vérifiez dans Project > Options > Delphi Compiler > Compiling
- Assurez-vous que Debug Information est coché
- Redéployez l'application
Cause : L'optimisation du compilateur peut réorganiser ou éliminer du code.
Solution :
- Désactivez l'optimisation en mode Debug
- Project > Options > Delphi Compiler > Compiling > Optimization = Off
- Recompilez et redéployez
Symptôme : LLDB lui-même plante pendant le débogage.
Solutions :
- Vérifiez que vous utilisez la bonne version de LLDB pour votre plateforme
- Mettez à jour vers la dernière version de Delphi/LLDB
- Simplifiez votre session de débogage (moins de breakpoints, moins de watchpoints)
- Redémarrez Delphi
Cause : Trop de breakpoints, watchpoints, ou expressions complexes.
Solutions :
- Réduisez le nombre de breakpoints actifs
- Supprimez les watchpoints non nécessaires
- Simplifiez les expressions dans la Watch List
- Utilisez des breakpoints conditionnels au lieu de vérifier manuellement
Utilisez cette checklist pour les sessions de débogage complexes :
□ Préparation
- Informations de débogage activées dans le projet
- Optimisation désactivée en mode Debug
- Application déployée sur la cible
- LLDB console ouverte dans Delphi
□ Session de débogage
- Breakpoints placés aux endroits stratégiques
- Watchpoints configurés si nécessaire
- Thread approprié sélectionné
- Variables clés surveillées
□ Analyse
- Stack trace examinée (
bt) - Variables locales inspectées (
frame variable) - État des threads vérifié (
thread list) - Mémoire examinée si nécessaire
□ Documentation
- Résultats notés
- Commandes utiles sauvegardées
- Breakpoints complexes exportés si nécessaire
- LLDB Official Documentation : https://lldb.llvm.org/
- LLDB Tutorial : https://lldb.llvm.org/use/tutorial.html
- LLDB Command Reference : https://lldb.llvm.org/use/map.html
- Stack Overflow : Questions avec le tag [lldb]
- Forums Embarcadero : Section Debugging
- LLDB Mailing List : lldb-dev@lists.llvm.org
Créez votre propre cheat sheet avec vos commandes préférées. Voici un exemple de départ :
=== LLDB Quick Reference ===
Navigation:
continue (c) - Continue execution
step (s) - Step into
next (n) - Step over
finish - Step out
Inspection:
bt - Backtrace
frame variable - Show local variables
expr <expr> - Evaluate expression
thread list - List all threads
Breakpoints:
br s -f file.pas -l 42 - Set breakpoint
br s -n FunctionName - Break on function
br s -f file.pas -l 42 -c "x>10" - Conditional
br list - List all
br delete <n> - Delete breakpoint
Watchpoints:
watchpoint set variable <var> - Watch variable
watchpoint list - List all
watchpoint delete <n> - Delete watchpoint
Threads:
thread select <n> - Select thread
thread backtrace all - All stacks
thread continue <n> - Continue one thread
Memory:
memory read <addr> - Read memory
memory write <addr> <val> - Write memory
LLDB v12 est un outil de débogage extraordinairement puissant qui vous donne un contrôle total sur l'exécution de vos applications Delphi sur macOS, iOS, Linux et Android. Bien que son interface en ligne de commande puisse sembler intimidante au début, les capacités qu'elle offre en font un atout inestimable pour le débogage de problèmes complexes.
Points clés à retenir :
Nouveautés v12 : LLDB v12 apporte des améliorations significatives en performance, stabilité et support des types Delphi.
Commandes essentielles : Maîtrisez d'abord bt, frame variable, expr, et thread list avant d'explorer les fonctionnalités avancées.
Breakpoints avancés : Les conditions, compteurs et commandes automatiques rendent les breakpoints extrêmement flexibles.
Watchpoints : Surveillez les modifications mémoire pour trouver les bugs insaisissables.
Multi-threading : LLDB offre des outils excellents pour déboguer les applications multi-thread et diagnostiquer les deadlocks.
Scripting : L'intégration Python permet d'automatiser des tâches complexes et de créer des outils personnalisés.
Pratique progressive : Commencez par les bases et ajoutez progressivement des techniques avancées à votre workflow.
Documentation : Utilisez help généreusement et consultez la documentation officielle pour approfondir.
En maîtrisant LLDB, vous rejoignez les rangs des développeurs capables de résoudre même les bugs les plus difficiles et obscurs. C'est un investissement en temps qui rapporte énormément, particulièrement pour le développement multi-plateformes avec Delphi. Pratiquez régulièrement, expérimentez avec les différentes commandes, et vous découvrirez rapidement que LLDB devient un outil indispensable dans votre arsenal de débogage.