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 Windows
For Visual Studio debugging, please see the Debugging for Windows guide.
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 ?? (gdb)
To find out where the crash occurred (you might not always be able to), you should run:
(gdb) backtrace
or
(gdb) where
or
(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 (gdb)
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> …