Déboguer Inkscape

Pour obtenir des symboles de débogage avec Inkscape, vous devrez probablement le recompiler. Nous utilisons CMake, et la production dispose d'un mode de débogage qui produits les symboles :

cmake -DCMAKE_BUILD_TYPE=Debug ../

Ceci suppose que vous effectuez la production dans un dossier build et que la racine du dépôt est le répertoire parent.

Si vous souhaitez déboguer une ancienne version d'Inkscape n'utilisant pas CMake, vous devrez définir la valeur de CXXFLAGS manuellement.

Déboguer avec GDB

Pour démarrer le débogage d'Inkscape avec GDB, chargez-le :

gdb /chemin/vers/inkscape

Si vous voulez qu'Inkscape démarre immédiatement et votre version de GDB est suffisamment récente, vous pouvez le démarrer avec :

gdb /chemin/vers/inkscape -ex r

Pour enlever la pagination de GDB (le découpage de la sortie en pages numérotées, ce qui rend la création des traces pour les rapports de bogues plus difficiles), vous pouvez mettre cela dans ~/.gdbinit :

set pagination off

Pour utiliser l'interface utilisateur textuelle de GDB, vous pouvez exécuter gdb -tui ou gdbtui.

Lorsque le programme plante, vous devriez voir quelque chose comme ça :

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ??
(gdb)

Pour savoir où le plantage s'est produit (l'information peut être indisponible), écrivez :

(gdb) backtrace

ou

(gdb) where

ou

(gdb) bt

Chacune de ces commandes a le même effet, et fournit la trace du programme jusqu'à son plantage.

Débogage plus avancé avec GDB

Lors de l'affichage de la trace, vous obtenez une liste de « cadres », comme suit :

Program receieved signal SIGTRAP, Trace/breakpoint trap.
0x0000000000aa849f in SPDesktopWidget::createInstance (namedview=0x33a57a0) at ../../src/widgets/desktop-widget.cpp:1708
1708    UXManager::getInstance()->connectToDesktop( toolboxes, dtw->desktop );
(gdb) bt
#0 0x0000000000aa849f in SPDesktopWidget::createInstance (namedview=0x33a57a0) at ../../src/widgets/desktop-widget.cpp:1708
#1 0x0000000000aa8065 in sp_desktop_widget_new (namedview=0x33a57a0) at ../../src/widgets/desktop-widget.cpp:1659
#2 0x000000000052430d in sp_file_new (templ=...) at ../../src/file.cpp:155
#3 0x00000000005249ba in sp_file_new_default () at ../../src/file.cpp:226
#4 0x000000000048865e in sp_main_gui (argc=1, argv=0x7fffffffe0b8) at ../../src/main.cpp:1071
#5 0x0000000000487fab in main (argc=1, argv=0x7fffffffe0b8) at ../../src/main.cpp:789
(gdb)

Ces cadres peuvent être sélectionnés :

(gdb) frame 2
#2 0x000000000052430d in sp_file_new (templ=...) at ../../src/file.cpp:155

(Si le même type de plantage se produit dans un débogueur plus adapté à votre système, vous pouvez utiliser select frame pour spécifier l'adresse si GDB ne peut pas la trouver.)

Vous avez alors activé le cadre 2. Vous pouvez voir l'état des registres du processeur dans le cadre 2 et des variables locales que le compilateur a embarquées dans les symboles de débogage.

(gdb) info locals
doc = 0x27fbea0
myRoot = 0x27f8850
nodeToRemove = 0x0
olddesktop = 0x0
dtw = 0x7fffffffdd30
desktop = 0x33a0710

(gdb) print templ
$1 = (const std::string &) @0x7fffffffddb8: {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x339fdd8 "/usr/local/share/inkscape/templates/default.svg"}}

Exécution pas à pas et points d'arrêt

Parfois, vous souhaitez contrôler l'exécution du programme plutôt que de la laisser se dérouler d'un seul coup.

Vous pouvez dire à GDB de s'arrêter lorsqu'il atteint une certaine fonction, jusqu'à ce qu'une condition soit vérifiée, ou lorsqu'une valeur change dans la mémoire. Ces fonctions sont appelées points d'arrêt et points de surveillance.

S'arrêter à l'appel d'une fonction :

(gdb) break Inkscape::UI::Tools::SelectTool::root_handler
Breakpoint 1 at 0xf64ab7: file ../../src/ui/tools/select-tool.cpp, line 460.

S'arrêter au lancement d'une exception :

(gdb) catch throw
Catchpoint 2 (throw)

S'arrêter lorsqu'une condition est vérifiée :

(gdb) break ../../src/ui/tools/select-tool.cpp:629 if group_at_point == 0
Breakpoint 3 at 0xf657a5: file ../../src/ui/tools/select-tool.cpp, line 629.

S'arrêter lorsqu'une valeur change dans la mémoire :

(gdb) print desktop
$2 = (SPDesktop *) 0x33a0710
(gdb) awatch *0x33a0710
Hardware access (read/write) watchpoint 4: *0x33a0710

Lister les points d'arrêt :

(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000f64ab7 in Inkscape::UI::Tools::SelectTool::root_handler(_GdkEvent*) at ../../src/ui/tools/select-tool.cpp:460
2       breakpoint     keep y   0x00007ffff03a4a30 exception throw
3       breakpoint     keep y   0x0000000000f657a5 in Inkscape::UI::Tools::SelectTool::root_handler(_GdkEvent*) at ../../src/ui/tools/select-tool.cpp:629
        stop only if group_at_point == 0
4       acc watchpoint keep y                      *0x33a0710

Désactiver les points d'arrêt :

(gdb) disable 4

Supprimer les points d'arrêt :

(gdb) delete 3

Créer des points d'arrêt qui ne stopperont qu'une fois :

(gdb) tbreak foo::bar
(gdb) tcatch throw

Évaluer des expressions

Si GDB parvient à comprendre de quoi vous parlez, il peut afficher à peu près n'importe quoi. Il n'est pas affecté par la visibilité des membres des classes.

(gdb) print arc_context->arc
$3 = (SPGenericEllipse *) 0x3afb610

Un moyen pratique d'essayer de déterminer si un objet du tas existe toujours (n'a pas encore été supprimé avec un delete) est d'utiliser la nouvelle commande info vtbl de GDB :

(gdb) print UXManager::getInstance()
$4 = (Inkscape::UI::UXManager *) 0x3b6f1d0
(gdb) info vtbl $4
vtable for 'Inkscape::UI::UXManager' @ 0x136e500 (subobject @ 0x3b6f1d0):
[0]: 0xbc7720 <Inkscape::UI::UXManagerImpl::~UXManagerImpl()>
[1]: 0xbc7740 <Inkscape::UI::UXManagerImpl::~UXManagerImpl()>
[2]: 0xbc81e0 <Inkscape::UI::UXManagerImpl::addTrack(SPDesktopWidget*)>
…

Voici à quoi peut ressembler la table virtuelle (vtable) d'un objet supprimé :

(gdb) call 'operator delete'($4)
(gdb) info vtbl $4
vtable for 'Inkscape::UI::UXManager' @ 0x3f27f80 (subobject @ 0x3b6f1d0):
[0]: 0x190
[1]: 0x20
[2]: 0x3d91db0
[3]: 0x0
[4]: 0x448d40 <g_free@plt>
…