Jump to content

Guidelines and HOWTOs/Debugging/Debugging with GDB: Difference between revisions

From KDE Community Wiki
Nmariusp (talk | contribs)
m ps aux
Nmariusp (talk | contribs)
m gdb kwrite
Line 119: Line 119:
Sometimes it is not practical to start an application from within gdb.
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
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
crash and you get the friendly DrKonqi dialog informing you about
a crash you are just in time to start your debugger.
a crash. At that point, you are just in time to start your debugger.


First lets attach gdb to an application that hasn't crashed (yet).
First lets attach gdb to an application that hasn't crashed (yet).
Line 136: Line 136:


<pre>
<pre>
> gdb kedit 21570
$ gdb kwrite 175939
GNU gdb 4.95.0
GNU gdb (GDB) 12.0.90.20220320-git
Copyright 2000 Free Software Foundation, Inc.
Copyright (C) 2022 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
welcome to change it and/or distribute copies of it under certain conditions.
This is free software: you are free to change and redistribute it.
Type "show copying" to see the conditions.
There is NO WARRANTY, to the extent permitted by law.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
Type "show copying" and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
This GDB was configured as "x86_64-pc-linux-gnu".
/home1/bastian/21570: No such file or directory.
Type "show configuration" for configuration details.
Attaching to program: /ext/kde2.0/bin/kedit, Pid 21570
For bug reporting instructions, please see:
Reading symbols from /ext/kde2.0/lib/kedit.so.0...done.
<https://www.gnu.org/software/gdb/bugs/>.
Loaded symbols for /ext/kde2.0/lib/kedit.so.0
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
 
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from kwrite...
Attaching to program: /home/n/kde/usr/bin/kwrite, process 175939
[New LWP 175940]
...
...
Reading symbols from /lib/ld-linux.so.2...done.
[New LWP 175996]
Loaded symbols for /lib/ld-linux.so.2
[Thread debugging using libthread_db enabled]
Reading symbols from /lib/libnss_compat.so.2...done.
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Loaded symbols for /lib/libnss_compat.so.2
0x00007fcb25abad7f in poll () from /lib/x86_64-linux-gnu/libc.so.6
Reading symbols from /lib/libnsl.so.1...done.
Loaded symbols for /lib/libnsl.so.1
0x40c3d88e in __select () from /lib/libc.so.6
(gdb)
(gdb)
</pre>
</pre>


You will usually end up in the middle of a select() call from the event-loop.
You will usually end up in the middle of a poll() call from the event-loop.
This is the place where a KDE application spends most of its time, waiting
This is the place where a KDE application with graphical user interface (GUI app) spends most of its time, waiting for things to happen.
for things to happen.


A backtrace will typically look something like this:
A backtrace will typically look something like this:

Revision as of 01:10, 30 May 2022

Warning

This page needs a review and probably holds information that needs to be fixed.

Parts to be reviewed:

Outdated info. Port to KF5



This is a short tutorial on debugging KDE applications. Throughout this tutorial I will use "kwrite" as an example application.

Debugging with GDB

There are three ways to debug an application with gdb:

  1. You can start the application from within gdb.
  2. You can attach gdb to an already running application.
  3. 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:

$ gdb kwrite
GNU gdb (GDB) 12.0.90.20220320-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from kwrite...
(gdb)

You can now set the command line arguments that you want to pass to kwrite with the gdb command "set args":

(gdb) set args myfile.txt
(gdb)

gdb has loaded the kwrite 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:

(gdb) break main
Breakpoint 1 at 0x2ee6: file /home/n/kde/src/utilities/kate/apps/kwrite/main.cpp, line 26.
(gdb) run
Starting program: /home/n/kde/usr/bin/kwrite myfile.txt
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main (argc=2, argv=0x7fffffffdcc8) at /home/n/kde/src/utilities/kate/apps/kwrite/main.cpp:26
26      {
(gdb) 

You can now set breakpoints everywhere. For example lets set a breakpoint in the KAboutData constructor.

(gdb) break KAboutData::KAboutData
Breakpoint 2 at 0x555555556570 (8 locations)
(gdb)

We can now continue the execution of kwrite. 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 KAboutData constructor:

(gdb) continue
Continuing.
[New Thread 0x7ffff0787640 (LWP 174356)]
[New Thread 0x7fffef3bd640 (LWP 174357)]

Thread 1 "kwrite" hit Breakpoint 2, 0x0000555555556570 in KAboutData::KAboutData(QString const&, QString const&, QString const&, QString const&, KAboutLicense::LicenseKey, QString const&, QString const&, QString const&, QString const&)@plt ()
(gdb)

You can set a breakpoint on a given source code line. 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:

(gdb) list main.cpp:200
file: "/home/n/kde/src/frameworks/ki18n/src/i18n/main.cpp", line number: 200, symbol: "???"
Line number 195 out of range; /home/n/kde/src/frameworks/ki18n/src/i18n/main.cpp has 77 lines.
(gdb) list /home/n/kde/src/utilities/kate/apps/kwrite/main.cpp:115
110         /**
111          * bugzilla
112          */
113         aboutData.setProductName(QByteArray("kate/kwrite"));
114
115         /**
116          * set and register app about data
117          */
118         KAboutData::setApplicationData(aboutData);
119
(gdb) break 118
Breakpoint 2 at 0x55555555732b: file /home/n/kde/src/utilities/kate/apps/kwrite/main.cpp, line 118.
(gdb) continue
Continuing.

Thread 1 "kwrite" hit Breakpoint 2, main (argc=1, argv=0x7fffffffdce8) at /home/n/kde/src/utilities/kate/apps/kwrite/main.cpp:118
118         KAboutData::setApplicationData(aboutData);
(gdb)

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 and you get the friendly DrKonqi dialog informing you about a crash. At that point, 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. ps aux:

$ ps aux | grep kwrite
n  175939  0.9  0.4 1948832 134148 pts/8  Sl   04:00   0:00 kwrite myfile.txt
n  176073  0.0  0.0   9076  2172 pts/8    S+   04:01   0:00 grep --color=auto kwrite

From this you learn that kwrite has process id 175939. Now you can start gdb as follows:

$ gdb kwrite 175939
GNU gdb (GDB) 12.0.90.20220320-git
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from kwrite...
Attaching to program: /home/n/kde/usr/bin/kwrite, process 175939
[New LWP 175940]
...
[New LWP 175996]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
0x00007fcb25abad7f in poll () from /lib/x86_64-linux-gnu/libc.so.6
(gdb)

You will usually end up in the middle of a poll() call from the event-loop. This is the place where a KDE application with graphical user interface (GUI app) spends most of its time, waiting for things to happen.

A backtrace will typically look something like this:

(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 <main>, argc=1,
    argv=0xbffff854, init=0x8048514 <_init>, fini=0x80486cc <_fini>,
    rtld_fini=0x4000aa20 <_dl_fini>, stack_end=0xbffff84c)
    at ../sysdeps/generic/libc-start.c:92
(gdb)

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:

 ulimit -c 100000
 kedit --nocrashhandler

Do not forget to use --nocrashhandler option. Core file would be created if the application crashed, so you can use gdb with created core file:

gdb kedit ./core-file #in my system it is core.PID

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 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 qt import register_qt_printers
 from kde import register_kde_printers

 register_qt_printers (None)
 register_kde_printers (None)
 end

 set print pretty on