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> …