Difference between revisions of "Development/Tutorials/Debugging/Debugging with GDB"

Jump to: navigation, search
(not fully qt5 compatible)
(Replaced content with "{{Moved To Community | Guidelines_and_HOWTOs/Debugging }}")
 
Line 1: Line 1:
 
+
{{Moved To Community | Guidelines_and_HOWTOs/Debugging }}
This is a short tutorial on debugging KDE applications. Throughout this
 
tutorial I will use "kedit" as an example application.
 
 
 
==Debugging with GDB==
 
 
 
The recommended version of gdb to use is version 4.95 or higher; older
 
versions have problems generating proper backtraces.
 
 
 
There are three ways to debug an application with gdb:
 
 
 
# You can start the application from within gdb.
 
# You can attach gdb to an already running application.
 
# You can run gdb after an application has crashed using a core file.
 
 
 
==Starting applications from within gdb==
 
 
 
To start an application with gdb you can start gdb as follows:
 
 
 
<pre>
 
> gdb kedit
 
GNU gdb 4.95.0
 
Copyright 2000 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-linux-gnu"...
 
(gdb)
 
</pre>
 
 
 
You can now set the command line arguments that you want to pass to kedit with
 
the gdb command "<tt>set args</tt>":
 
 
 
<pre>
 
(gdb) set args myfile.txt
 
(gdb)
 
</pre>
 
 
 
gdb has loaded the kedit executable on startup but it hasn't loaded any of
 
the libraries yet. This means that you can't set any breakpoints in the
 
libraries yet. The easiest way to do that is to set a breakpoint in the
 
first line of main and then start the program:
 
 
 
<pre>
 
(gdb) break main
 
Breakpoint 1 at 0x804855c
 
(gdb) run
 
Starting program: /ext/kde2.0/bin/kedit myfile.txt
 
Breakpoint 1 at 0x4002cf18: file kedit.cpp, line 1595.
 
 
Breakpoint 1, main (argc=2, argv=0xbffff814) at kedit.cpp:1595
 
1595            bool have_top_window = false;
 
Current language:  auto; currently c++
 
(gdb)
 
</pre>
 
 
 
You can now set breakpoints everywhere. For example lets set a breakpoint
 
in the KApplication constructor. Unfortunately, gdb is not very good in
 
handling C++ names, so it is not really possible to specify the constructor
 
directly after the break command. Instead we look up a line of source
 
code where we want to place the breakpoint. An external editor is of great
 
use at this point. With the list command we can select the source file we
 
are interested in and verify that we have found the correct source line:
 
 
 
<pre>
 
(gdb) list kapp.cpp:220
 
215    parseCommandLine( argc, argv );
 
216 }
 
217
 
218 KApplication::KApplication( bool allowStyles, bool GUIenabled ) :
 
219  QApplication( *KCmdLineArgs::qt_argc(), *KCmdLineArgs::qt_argv(),
 
220                GUIenabled ),
 
221  KInstance( KCmdLineArgs::about),
 
222  d (new KApplicationPrivate)
 
223 {
 
224    if (!GUIenabled)
 
(gdb) break 224
 
Breakpoint 2 at 0x4048aa7e: file kapp.cpp, line 224.
 
(gdb)
 
</pre>
 
 
 
We can now continue the execution of kedit. Execution will stop when it hits
 
a breakpoint or when the program exits. In this case execution will stop
 
in the first line of the KApplication constructor:
 
 
 
<pre>
 
(gdb) continue
 
Continuing.
 
Qt: gdb: -nograb added to command-line options.
 
        Use the -dograb option to enforce grabbing.
 
 
Breakpoint 2, KApplication::KApplication (this=0xbffff6a8, allowStyles=true,
 
    GUIenabled=true) at kapp.cpp:224
 
224        if (!GUIenabled)
 
(gdb)
 
</pre>
 
 
 
{{Note|
 
Important: many applications use "KUniqueApplication" to ensure that only one instance can exist at a given time in a given KDE session. This is the case for kwin, kontact, konsole, plasma, etc. To debug those applications, attach to them while they're running (see next session) or use <tt>set args --nofork</tt>
 
}}
 
 
 
==Attaching gdb to already running applications==
 
 
 
Sometimes it is not practical to start an application from within gdb.
 
E.g. in those cases where you didn't know the application was about to
 
crash :-) When you get the friendly DrKonqi dialog informing you about
 
a crash you are just in time to start your debugger.
 
 
 
First lets attach gdb to an application that hasn't crashed (yet).
 
 
 
You start with finding the process of the application with e.g. <tt>ps -aux</tt>:
 
 
 
<pre>
 
> ps -aux | grep kedit
 
bastian  21570 15.1  6.8 13740 8800 pts/6    S    15:34  0:01 kedit
 
bastian  21582  0.0  0.3  1132  412 pts/6    R    15:34  0:00 grep kedit
 
</pre>
 
 
 
From this you learn that kedit has process id 21570. Now you can start gdb as
 
follows:
 
 
 
<pre>
 
> gdb kedit 21570
 
GNU gdb 4.95.0
 
Copyright 2000 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-linux-gnu"...
 
/home1/bastian/21570: No such file or directory.
 
Attaching to program: /ext/kde2.0/bin/kedit, Pid 21570
 
Reading symbols from /ext/kde2.0/lib/kedit.so.0...done.
 
Loaded symbols for /ext/kde2.0/lib/kedit.so.0
 
...
 
Reading symbols from /lib/ld-linux.so.2...done.
 
Loaded symbols for /lib/ld-linux.so.2
 
Reading symbols from /lib/libnss_compat.so.2...done.
 
Loaded symbols for /lib/libnss_compat.so.2
 
Reading symbols from /lib/libnsl.so.1...done.
 
Loaded symbols for /lib/libnsl.so.1
 
0x40c3d88e in __select () from /lib/libc.so.6
 
(gdb)
 
</pre>
 
 
 
You will usually end up in the middle of a select() call from the event-loop.
 
This is the place where a KDE application spends most of its time, waiting
 
for things to happen.
 
 
 
A backtrace will typically look something like this:
 
 
 
<pre>
 
(gdb) bt
 
#0  0x40c3d88e in __select () from /lib/libc.so.6
 
#1  0x40a22844 in __DTOR_END__ () at fam.c++:356
 
#2  0x407293bf in QApplication::enter_loop (this=0xbffff6e8)
 
    at kernel/qapplication.cpp:2552
 
#3  0x406b1d7b in QApplication::exec (this=0xbffff6e8)
 
    at kernel/qapplication_x11.cpp:2217
 
#4  0x4002d500 in main (argc=1, argv=0xbffff854) at kedit.cpp:1662
 
#5  0x40bbba5e in __libc_start_main (main=0x8048568 &lt;main&gt;, argc=1,
 
    argv=0xbffff854, init=0x8048514 &lt;_init&gt;, fini=0x80486cc &lt;_fini&gt;,
 
    rtld_fini=0x4000aa20 &lt;_dl_fini&gt;, stack_end=0xbffff84c)
 
    at ../sysdeps/generic/libc-start.c:92
 
(gdb)
 
</pre>
 
 
 
==Debugging core files with GDB==
 
 
 
Debugging process requires much memory. If you have to inspect crash, you can debug core files. It's much faster and requires less memory. First limit the maximum size of core files and run the application:
 
<pre>
 
ulimit -c 100000
 
kedit --nocrashhandler
 
</pre>
 
Do not forget to use <tt>--nocrashhandler</tt> option. Core file would be created if the application crashed, so you can use gdb with created core file:
 
<pre>
 
gdb kedit ./core-file #in my system it is core.PID
 
</pre>
 
 
 
==Improving your gdb experience for KDE/Qt applications==
 
 
 
Since version 7 GDB supports Python scripting for pretty printers. There are such scripts for basic Qt types (QString, QList, QMap, QHash, QDateTime and many others) in [http://quickgit.kde.org/?p=kdevelop.git&a=tree&f=debuggers/gdb/printers KDevelop git repository]. Download the scripts and add following lines to your ~/.gdbinit to load the scripts automatically as start:
 
 
 
python
 
import sys
 
sys.path.insert(0, '/folder/where/you/downloaded/the/scripts')
 
from qt4 import register_qt4_printers
 
from kde4 import register_kde4_printers
 
 
register_qt4_printers (None)
 
register_kde4_printers (None)
 
end
 
 
set print pretty on
 
 
 
Note that the pretty printers are written for Qt 4, it is only partially compatible with Qt 5. See also https://bugs.kde.org/show_bug.cgi?id=331044
 
 
 
If you want to go even further, you can apply those [http://developer.kde.org/documentation/other/gdb-patches patches to the gdb source],
 
to fix a few annoyancies in gdb:
 
 
 
* source.c: don't try to open a directory in "." that has the same name as the executable we want to open (not needed for gdb-6.0 and above)
 
* symfile.c: no prompting at end of page while opening shared libraries (not needed for gdb-6.2 and above)
 
* solib.c: less output when opening shared libraries
 
 
 
Those patches are maintained by [mailto:faure@kde.org David Faure].
 
 
 
Have fun with gdb! Hmm, ok, the definition of 'fun' is very relative...
 

Latest revision as of 09:01, 5 August 2016

This page is now on the community wiki.


This page was last edited on 5 August 2016, at 09:01. Content is available under Creative Commons License SA 4.0 unless otherwise noted.