Debugging Inkscape

To get debug symbols for Inkscape, you'll probably need to recompile it. We use cmake and it has a Debug mode which produces debugging symbols:

cmake -DCMAKE_BUILD_TYPE=Debug ../

This assumes that you're building everything in a build folder and the repository root is the parent directory.

If you're looking an older non-cmake version, you'll need to enable the CXXFLAGS manually.

Debugging with GDB

To start debugging Inkscape with GDB, load it up:

gdb path/to/inkscape

If you want Inkscape to start right away and your version of GDB is new enough, you can start it with

gdb path/to/inkscape -ex r

To keep gdb from paginating (splitting output from commands into pages, makes creating backtraces for bug reports more difficult) you can put this in ~/.gdbinit:

set pagination off

To use GDB's text UI, you can run gdb -tui or gdbtui.

When the program crashes you might see something like this:

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

To find out where the crash occurred (you might not always be able to), you should run:

(gdb) backtrace


(gdb) where


(gdb) bt

Each does the same thing, and refers to the command backtrace.

More advanced debugging with GDB

When you run bt, you get a list of frames:

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

These frames are all selectable:

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

(If you have the same crash in a debugger better suited to your platform, you can use select frame to specify the address if GDB cannot find it.)

Now you have activated frame 2. You can see the state of the processor registers in frame 2 and any local variables that the compiler has embedded in the debug symbols.

(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"}}

Stepping execution and breakpoints

Sometimes, you would like to be in control of program execution instead of just letting it run wildly.

You can tell GDB to stop when it reaches a certain function, upon a certain condition, or when a value in memory changes. These are known as breakpoints and watchpoints.

Stopping when a function is called:

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

Stopping if any exception is thrown:

(gdb) catch throw
Catchpoint 2 (throw)

Stopping if a condition is met:

(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.

Stopping when a memory value changes:

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

Listing breakpoints:

(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

Disabling breakpoints:

(gdb) disable 4

Deleting breakpoints:

(gdb) delete 3

Creating breakpoints that will only be stopped on once:

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

Evaluating expressions

If GDB can figure out what you are talking about, it can print pretty much anything. GDB also is immune to the private boundary of a class.

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

A handy feature to try to determine if a heap object still exists (hasn't been delete()d yet) is to use the new GDB command 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*)>

Here's what a delete()d object's vtable might look like:

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