Difference between revisions of "Debugging TDE applications"
(Added debugging instructions (imported from tdelibs/DEBUG file)) |
(Update information about placing a breakpoint in gdb) |
||
(4 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | This is a short tutorial on debugging Trinity applications. Throughout this tutorial I will use |
+ | This is a short tutorial on debugging Trinity applications. Throughout this tutorial I will use <code>kedit</code> as example application. |
= Configuring for debugging = |
= Configuring for debugging = |
||
+ | To build with debugging code, pass <code>-DCMAKE_BUILD_TYPE="Debug"</code> to CMake while configuring. If the application you are building is still using Autotools, you can use <code>--enable-debug</code> with the configure script to get debug code in it. |
||
− | You can use <code>--enable-debug</code> with the configure script, if you want to have debug code in your TDE libs. If you have the space and can stand code that's somewhat slower, this is worth it. The extra information really helps debugging and thus bugfixing. |
||
− | On the other hand, <code>--disable-debug</code> removes all debug messages, leading to a faster and cleaner desktop. |
+ | If you have the space and can stand code that's somewhat slower, this is worth it. The extra information really helps debugging and thus bugfixing. On the other hand, <code>-DCMAKE_BUILD_TYPE="Release"</code> (for CMake) and <code>--disable-debug</code> (for Autotools) removes all debug messages, leading to a faster and cleaner desktop. |
= Debugging with GDB = |
= Debugging with GDB = |
||
Line 17: | Line 17: | ||
# You can run gdb after an application has crashed using a core file. |
# You can run gdb after an application has crashed using a core file. |
||
− | = Starting applications from within gdb = |
+ | == Starting applications from within gdb == |
To start an application with gdb you can start gdb as follows: |
To start an application with gdb you can start gdb as follows: |
||
Line 56: | Line 56: | ||
</syntaxhighlight> |
</syntaxhighlight> |
||
− | You can now set breakpoints everywhere. For example lets set a breakpoint in the <code>TDEApplication</code> constructor. |
+ | You can now set breakpoints everywhere. For example lets set a breakpoint in the <code>TDEApplication</code> constructor. We can use the C++ function name or, if that does not work, look up the 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: |
<syntaxhighlight lang="shell-session"> |
<syntaxhighlight lang="shell-session"> |
||
Line 89: | Line 89: | ||
</syntaxhighlight> |
</syntaxhighlight> |
||
− | = Attaching |
+ | == Attaching GDB to already running applications == |
− | 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 crash :-) |
⚫ | |||
⚫ | |||
− | First lets attach gdb to an application that hasn't crashed (yet). |
||
− | You start with finding the process of the application with e.g. |
+ | First, let's attach gdb to an application that hasn't crashed (yet). You start with finding the process of the application with e.g. <code>ps -aux</code>: |
<syntaxhighlight lang="shell-session"> |
<syntaxhighlight lang="shell-session"> |
||
Line 151: | Line 150: | ||
</syntaxhighlight> |
</syntaxhighlight> |
||
− | = Getting core dumps = |
+ | == Getting core dumps == |
If you want to have a core dump after your application crashes you need to |
If you want to have a core dump after your application crashes you need to |
||
Line 162: | Line 161: | ||
$ ulimit -c unlimited |
$ ulimit -c unlimited |
||
</syntaxhighlight> |
</syntaxhighlight> |
||
+ | |||
+ | = Getting kdDebug() output = |
||
+ | |||
+ | When a program is configured with debugging mode on, you also get to see debug messages from your code (generated by <code>kdDebug()</code>). The easiest way to see them is run the program from a Konsole window. |
||
+ | |||
+ | You can configure the messages you see through <code>tdedebugdialog</code> You can also redirect these messages to the syslog or a file. To configure this, launch <code>tdedebugdialog</code> with the <code>--fullmode</code> argument. |
||
[[Category:Developers]] |
[[Category:Developers]] |
Latest revision as of 13:27, 13 June 2023
This is a short tutorial on debugging Trinity applications. Throughout this tutorial I will use kedit
as example application.
Configuring for debugging
To build with debugging code, pass -DCMAKE_BUILD_TYPE="Debug"
to CMake while configuring. If the application you are building is still using Autotools, you can use --enable-debug
with the configure script to get debug code in it.
If you have the space and can stand code that's somewhat slower, this is worth it. The extra information really helps debugging and thus bugfixing. On the other hand, -DCMAKE_BUILD_TYPE="Release"
(for CMake) and --disable-debug
(for Autotools) removes all debug messages, leading to a faster and cleaner desktop.
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:
$ 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)
You can now set the command line arguments that you want to pass to kedit with
the gdb command set args
:
(gdb) set args myfile.txt
(gdb)
gdb has loaded the kedit
executable on startup but it hasn't loaded any of the libraries yet. This means that you can 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 0x804855c
(gdb) run
Starting program: /opt/trinity/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)
You can now set breakpoints everywhere. For example lets set a breakpoint in the TDEApplication
constructor. We can use the C++ function name or, if that does not work, look up the 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:
(gdb) list kapp.cpp:220
215 parseCommandLine( argc, argv );
216 }
217
218 TDEApplication::TDEApplication( bool allowStyles, bool GUIenabled ) :
219 QApplication( *TDECmdLineArgs::tqt_argc(), *TDECmdLineArgs::tqt_argv(),
220 GUIenabled ),
221 TDEInstance( TDECmdLineArgs::about),
222 d (new TDEApplicationPrivate)
223 {
224 if (!GUIenabled)
(gdb) break 224
Breakpoint 2 at 0x4048aa7e: file kapp.cpp, line 224.
(gdb)
We can now continue the execution of kedit. Execution will stop when it hits a breakpoint of when the program exits. In this case execution will stop in the first line of the TDEApplication constructor:
(gdb) continue
Continuing.
Qt: gdb: -nograb added to command-line options.
Use the -dograb option to enforce grabbing.
Breakpoint 2, TDEApplication::TDEApplication (this=0xbffff6a8, allowStyles=true,
GUIenabled=true) at kapp.cpp:224
224 if (!GUIenabled)
(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 :-)
When you get the friendly DrKonqi dialog informing you about a crash you are just in time to start your debugger.
First, let's 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 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
From this you learn that kedit has process id 21570. Now you can start gdb as follows:
$ 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: /opt/trinity/bin/kedit, Pid 21570
Reading symbols from /opt/trinity/lib/kedit.so.0...done.
Loaded symbols for /opt/trinity/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)
You will usually end up in the middle of a select()
call from the event-loop.
This is the place where a TDE application 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)
Getting core dumps
If you want to have a core dump after your application crashes you need to do two things:
- Disable the TDE crash handler. This can be done either by using the
--nocrashhandler
command line option or by setting theTDE_DEBUG
environment variable to some value e.g.TDE_DEBUG=true
. - Enable core dump generation by changing the so called 'ulimits' with the following command:
$ ulimit -c unlimited
Getting kdDebug() output
When a program is configured with debugging mode on, you also get to see debug messages from your code (generated by kdDebug()
). The easiest way to see them is run the program from a Konsole window.
You can configure the messages you see through tdedebugdialog
You can also redirect these messages to the syslog or a file. To configure this, launch tdedebugdialog
with the --fullmode
argument.