Difference between revisions of "Debugging Inkscape"
Johanengelen (talk | contribs) |
|||
Line 1: | Line 1: | ||
* If you're hunting down a GTK warning, you can set a breakpoint in gdb for "g_logv" so you can capture a backtrace. ("br g_logv", "run", "bt") | * If you're hunting down a GTK warning, you can set a breakpoint in gdb for "g_logv" so you can capture a backtrace. ("br g_logv", "run", "bt") | ||
* If you're hunting down a g_assert, you can set a breakpoint in gdb for "g_assertion_message_expr" (or "g_assertion_message" maybe) to stop execution and make a backtrace. | |||
* gdb can catch <b>throwing of an exception</b>. Type: "catch throw" and gdb will stop execution at the point of where the exception is thrown, without unwinding the stack, so you can get a backtrace! | * gdb can catch <b>throwing of an exception</b>. Type: "catch throw" and gdb will stop execution at the point of where the exception is thrown, without unwinding the stack, so you can get a backtrace! |
Revision as of 22:32, 19 March 2009
- If you're hunting down a GTK warning, you can set a breakpoint in gdb for "g_logv" so you can capture a backtrace. ("br g_logv", "run", "bt")
- If you're hunting down a g_assert, you can set a breakpoint in gdb for "g_assertion_message_expr" (or "g_assertion_message" maybe) to stop execution and make a backtrace.
- gdb can catch throwing of an exception. Type: "catch throw" and gdb will stop execution at the point of where the exception is thrown, without unwinding the stack, so you can get a backtrace!
- Bug list
- w32 version asks for (that crappy) Verdana typeface (which is not the most usual w32 typeface, also some users have deleted it to save disk space)
Debugging Tips for OS X
When running the .app package for OS X, it can be difficult to get a backtrace because the application binary is launched through another application and 2 scripts. One way to get a backtrace is:
- Add '-g' to $CFLAGS in your build script before building.
- Remove the signal() calls (
segv_handler = signal (SIGSEGV,...
) ) in inkscape_application_init() in src/inkscape.cpp. - In the Resources/bin/inkscpe script, change the last line from:
exec "$CWD/inkscape-bin" "$@"
to:exec "/usr/bin/gdb" "stuff/inkscape-bin"
- Build and package the app (see CompilingMacOsX).
- Run the application in Terminal:
$ cd packaging/macosx
$ Inkscape.app/Contents/MacOS/Inkscape
...
(gdb) run
Debugging Tips for Windows
First, have a look at the Using Eclipse page for how to use that program on Windows to debug Inkscape.
Second, make use of the View > Messages... dialog from within the program. Capturing the log here will show you messages printed with g_message(), g_warning(), and g_error()..
Finally, look into how to compile Inkscape as a command line app so you can capture debug messages at the prompt, more like you would do in Linux.
How Johan works
Of course I am always compiling with -mconsole, instead of -mwindows. I don't compile with -g or any other extra flags. This is unnecessary and reduces build times significantly.
For example for crashes, usually I add g_message("blah") to the code to see where the execution of code goes and to see on which line things break:
g_message("1"); some_piece_of_code1(); g_message("2"); some_piece_of_code2(); g_message("3"); some_piece_of_code3(); g_message("4"); some_piece_of_code4(); g_message("5");
If I see the message "2" but not "3" I know the crash happened in some_piece_of_code2.
I also use GDB to get backtraces. Again, don't compile with -g. Not necessary at all! One of the problems with running Inkscape in gdb is that you cannot open a file with the file dialog: Inkscape will hang. I don't know the reason, but I do know a solution! Open the file through Inkscape's cmdline parameters:
D:\Inkscape\inkscape>gdb GNU gdb 6.6 Copyright (C) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-mingw32". (gdb) file inkscape.exe inkscape.dbg Reading symbols from D:\Inkscape\inkscape/inkscape.exe...(no debugging symbols found)...done. Reading symbols from D:\Inkscape\inkscape/inkscape.dbg...done. (gdb) run Tekening.svg Starting program: D:\Inkscape\inkscape/inkscape.exe Tekening.svg
Example of how to fix a bug
See this bugreport: https://bugs.launchpad.net/inkscape/+bug/169135
I started gdb like above. And then I saw this:
Program received signal SIGSEGV, Segmentation fault. 0x005c94ec in Inkscape::UI::Widget::Scalar::setValue () (gdb) bt #0 0x005c94ec in Inkscape::UI::Widget::Scalar::setValue () #1 0x0044fc11 in Inkscape::CanvasXYGrid::readRepr () #2 0x0044de22 in Inkscape::CanvasXYGrid::onReprAttrChanged ()
The crashing piece of code looked like this:
void Scalar::setValue(double value) { g_assert(_widget != NULL); setProgrammatically = true; // callback is supposed to reset back, if it cares static_cast<Gtk::SpinButton*>(_widget)->set_value(value); }
Nothing much can crash there, the assert checks that _widget is not NULL, and then the cast is valid aswell. So what crashed? What happens is that the setValue method is called for an object that does not exist. _widget is not NULL, but "this" is! this->_widget would crash. g_assert (this != NULL) would give an assertion message. (checked by adding " if (this==NULL) g_message("ja hoor"); " )
It is absurd to check for "this" to be non-NULL at the start of every method, so the bug is not in this method but in the function calling it! That's why we turn our attention to Inkscape::CanvasXYGrid::readRepr ().
readRepr is long, but we only have to look where it does something with a Scalar widget. It's the validateScalar functions. When we comment those out, the bug is solved. (it causes another bug with the specific SVG file, where Inkscape hangs when the grid spacing equals zero. validateScalar used to check for that...) The strange thing is that the widgets are all created and initialized in the constructor of CanvasXYGrid. So perhaps readRepr is being called *during* construction of CanvasXYGrid, while the Scalar widget is still invalid? Using the g_message tip above I found out that the problem code was:
sutemp = _rsu_sx.getSU(); g_message("CanvasXYGrid 1"); sutemp->setDigits(4); g_message("CanvasXYGrid 2");
Researching the setDigits path, I could not find a bug. Then it hit me: _rsu_sx is initialized, then readRepr is called, but this is before _rsu_sy is initialized. Then
void RegisteredScalarUnit::setValue (double val) { _widget->setValue (val); }
is called, but _widget is still NULL, hence the crash. As usual, the fix is easy:
void RegisteredScalarUnit::setValue (double val) { if (_widget) _widget->setValue (val); }
Don't forget to fix the setValue methods of the other Registered widgets!!!
The fix can be seen in SVN revision 16544.
Problems running GDB
From an inexperienced user of GDB just trying to get backtraces, here is a tip I found running gdb.
I simply downloaded the latest version of Inkscape Dev full debug, extracted to a directory and ran gdb exactly as above from within the directory, only changing the name of the svg file.
Everything went exactly as above for "file inkscape.exe inkscape.dbg", however after executing the "run {filename.svg}" command, I received the following message;
Program received signal SIGSEV, Segmentation fault. 0x03de8cf1 in xslDebugStatus ()
This has stumped me once before, but this time I checked out the help menus, and found under "help running" that I could simply type "continue". I figured that xslDebugStatus was nothing to do with the Inkscape program itself, but more to do with gdb, and after typing "continue" it seems to run Inkscape under gdb as normal, allowing backtraces.
Debugging Tips for Linux
Debugging Inkscape on Linux is most easily done using Eclipse (or any other IDE). When however a breakpoint is reached while Inkscape is handling events (or something like that), then X will stop responding. If you want to debug in such a case then you'll have to use gdb from the console. In Fedora 10 you'll get to the console when pressing ctrl-alt-F5. Now enter
declare -x DISPLAY=":0"
and startup gdb to load Inkscape and the debugging symbols, set your breakpoints, and start Inkscape. Now you can switch back to X (ctrl-alt-F1) and interact with Inkscape. When Inkscape stops responding because it hit a breakpoint, switch back to the console and do your debugging.
If you happen to run into some issues with one of the Gtk+ libraries and want to step through its code using the debugger, you will have to install its debugging symbols. For Fedora 10 you can simply enable the fedora-debuginfo repository in /etc/yum.repos.d/fedora.repo and then use yum to install for example the "gtk2-debuginfo" and "glib-debuginfo" package. For other distros you'll find some usefull information here:
http://live.gnome.org/GettingTraces/DistroSpecificInstructions