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