Depurando o Inkscape
Para obter símbolos de depuração para o Inkscape, você provavelmente precisará recompilá-lo. Usamos cmake e ele tem um modo de Depuração que cria os símbolos de depuração:
cmake -DCMAKE_BUILD_TYPE=Debug ../
Isso pressupõe que você está construindo tudo em uma pasta de compilação e a raiz do repositório é o diretório pai.
Se você estiver procurando uma versão anterior não cmake, você precisará habilitar o CXXFLAGS manualmente.
Depurando com GDB
Para iniciar a depuração do Inkscape com o GDB, carregue-o:
gdb path/to/inkscape
Se você quiser que o Inkscape comece imediatamente e com uma nova versão do GDB, você pode iniciá-la com
gdb path/to/inkscape -ex r
Para manter a paginação do gdb (dividir a saída dos comandos em páginas, torna a criação de pontos de interrupção para relatórios de erros mais difícil) você pode colocar isso ~/.gdbinit:
set pagination off
Para usar o texto do GDB na interface do usuário, você pode executar gdb -tui
ou gdbtui
.
Quando o programa falha você poderá ver algo como isto:
Program received signal SIGSEGV, Segmentation fault. 0x0000000000000000 in ?? (gdb)
Para descobrir onde ocorreu o problema (nem sempre será possível), você deve executar:
(gdb) backtrace
ou
(gdb) where
ou
(gdb) bt
Todos eles fazem a mesma coisa e referem-se ao comando backtrace
.
Depuração mais avançada com GDB
Quando você executa bt, você obtém uma lista de quadros:
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)
Esses quadros são todos selecionáveis:
(gdb) frame 2 #2 0x000000000052430d in sp_file_new (templ=...) at ../../src/file.cpp:155
(Se você tiver o mesmo erro em um depurador mais apropriado para sua plataforma, você pode usar select frame
para especificar um endereço se o GDB não puder encontrá-lo.)
Agora você ativou o quadro 2. Você pode ver o estado dos registradores do processador no quadro 2 e quaisquer variáveis locais onde houver símbolos de depuração incorporados pela compilação.
(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"}}
Etapas de execução e pontos de interrupção
Às vezes, você gostaria de estar no controle da execução do programa em vez de deixá-lo executar descontroladamente.
Você pode dizer ao GDB para parar quando atingir uma determinada função, mediante uma determinada condição, ou quando um valor é alterado na memória. Estes são conhecidos como pontos de interrupção e pontos de observação.
Parando quando uma função é chamada:
(gdb) break Inkscape::UI::Tools::SelectTool::root_handler Breakpoint 1 at 0xf64ab7: file ../../src/ui/tools/select-tool.cpp, line 460.
Parando se alguma exceção for lançada:
(gdb) catch throw Catchpoint 2 (throw)
Parando se uma condição for atendida:
(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.
Parando quando um valor de memória é alterado:
(gdb) print desktop $2 = (SPDesktop *) 0x33a0710 (gdb) awatch *0x33a0710 Hardware access (read/write) watchpoint 4: *0x33a0710
Listagem de pontos de interrupção:
(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
Desativar pontos de interrupção:
(gdb) disable 4
Exclusão de pontos de interrupção:
(gdb) delete 3
Criação de pontos de interrupção que só serão interrompidos na primeira vez:
(gdb) tbreak foo::bar (gdb) tcatch throw
Avaliando expressões
Se o GDB pode descobrir o que você quer dizer, ele pode imprimir praticamente qualquer coisa. O GDB também é imune ao limite privado de uma classe.
(gdb) print arc_context->arc $3 = (SPGenericEllipse *) 0x3afb610
Um recurso útil para tentar determinar se um objeto ainda existe na pilha (caso ainda não tenha sido excluído) é usar o novo comando do GDB info vtbl
:
(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*)> …
Aqui está o que um delete()d do objeto vtable pode parecer:
(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> …