Debugging/Getting traces
This article aims to help debugging software by providing traces and debug information. This information can then be used for the bug report to the (upstream) software developers or package maintainers.
Introduction
Usually, executable files are stripped of human readable context to make them smaller. Not only that, but enhanced debugging information is usually not added to the executable in the first place, which drastically reduces the usefulness of the trace. So, before being able to obtain traces with debug information, one has to rebuild the package with debugging symbols enabled.
Use the complete stack trace to inform developers of a bug you have discovered before. This will be highly appreciated by them and will help to improve your favorite program.
When looking at debug messages, such as by using gdb on a core dump (See #Getting the trace):
[...] Backtrace was generated from '/usr/bin/epiphany' (no debugging symbols found) Using host libthread_db library "/lib/libthread_db.so.1". (no debugging symbols found) [Thread debugging using libthread_db enabled] [New Thread -1241265952 (LWP 12630)] (no debugging symbols found) 0xb7f25410 in __kernel_vsyscall () #0 0xb7f25410 in __kernel_vsyscall () #1 0xb741b45b in ?? () from /lib/libpthread.so.0 [...]
??
shows where debugging info is missing, as well as the name of library or executable which called the function. Similarly, when (no debugging symbols found)
appears, you should look for the stated file names.
To retrieve debug information, proceed with one of sections #Debuginfod, #Installing debug packages or #Rebuilding packages.
Debuginfod
For packages in the official repositories that support it (see https://debuginfod.archlinux.org/packages), debug information and symbols can be retrieved directly over HTTP with debuginfod.
gdb offers to download them automatically when the DEBUGINFOD_URLS
environment variable is set.
This variable is set by default in /etc/profile.d/
.
$ gdb application
This GDB supports auto-downloading debuginfo from the following URLs: <https://debuginfod.archlinux.org> Enable debuginfod for this session? (y or [n]) y Debuginfod has been enabled. To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit. Downloading separate debug info for /usr/bin/application Reading symbols from /home/user/.cache/debuginfod_client/fbaee841e2ed2c11ecbbda26f39eeec1da23d6c3/debuginfo...
Once you enabled debuginfo support you can continue with #Getting the trace
Manual download
If one wants to manually retrieve the debug symbols for zstd, along with some source files, one can utilize debuginfod-find:
$ debuginfod-find debuginfo /usr/bin/zstd
/home/user/.cache/debuginfod_client/70e1b456c5813658df6436a3deb71812e75a0267/debuginfo
$ debuginfod-find source /usr/bin/zstd /usr/src/debug/zstd-1.5.2/programs/fileio.c
/home/user/.cache/debuginfod_client/70e1b456c5813658df6436a3deb71812e75a0267/source##usr##src##debug##zstd-1.5.2##programs##fileio.c
Manually getting debug info
The first thing to do is to obtain the names of the packages which require rebuilding or the install of a debug package.
[...] Backtrace was generated from '/usr/bin/epiphany' (no debugging symbols found) Using host libthread_db library "/lib/libthread_db.so.1". (no debugging symbols found) [...]
For example for the above extract from a trace, the package name for the associated package can be obtained with pacman:
$ pacman -Qo /lib/libthread_db.so.1
/lib/libthread_db.so.1 is owned by glibc 2.5-8
The package is called glibc in version 2.5-8. Repeat this step for every package that needs debugging information.
Installing debug packages
A few mirrors currently distribute debug packages in accessible repositories. These are sponsored mirrors controlled by Arch Linux and are given access to the debug repositories.
- https://geo.mirror.pkgbuild.com (GeoDNS mirror)
To install a package you can install it directly from the repository. For example:
# pacman -U https://geo.mirror.pkgbuild.com/core-debug/os/x86_64/zstd-debug-1.5.2-2-x86_64.pkg.tar.zst
debug
mirror.Another option is to add the repositories to your pacman configuration.
/etc/pacman.conf
# Testing Repositories [core-testing-debug] Include = /etc/pacman.d/mirrorlist [extra-testing-debug] Include = /etc/pacman.d/mirrorlist [multilib-testing-debug] Include = /etc/pacman.d/mirrorlist # Stable repositories [core-debug] Include = /etc/pacman.d/mirrorlist [extra-debug] Include = /etc/pacman.d/mirrorlist [multilib-debug] Include = /etc/pacman.d/mirrorlist
Place a mirror with debug packages as the first one in the mirrorlist file:
/etc/pacman.d/mirrorlist
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch ...
Rebuilding packages
If debug information is not exposed through debuginfod (for example, when the package originates from the AUR), then it can be rebuilt from source. See ABS for packages in the official repositories, or AUR#Acquire build files for packages in the AUR.
To set the required #Compilation options, you can modify the makepkg configuration if you will only use makepkg for debug purposes. In other cases, you should modify package's PKGBUILD
file only for each package you would like to rebuild.
Compilation options
As of pacman 4.1, makepkg.conf(5) has debug compilation flags in DEBUG_CFLAGS
and DEBUG_CXXFLAGS
. To use them, enable the debug
makepkg option, and disable strip
.
These settings will force compilation with debug symbols and will disable their stripping from executables.
/etc/makepkg.conf
OPTIONS+=(debug !strip)
To apply this setting to a single package, modify the PKGBUILD
:
PKGBUILD
options=(debug !strip)
Alternatively you can put the debug information in a separate package by enabling both debug
and strip
, debug symbols will then be stripped from the main package and placed, together with source files to aid in stepping through the debugger, in a separate pkgbase-debug
package. This is advantageous if the package contains very large binaries (e.g. over a GB with debug symbols included) as it might cause freezing and other strange, unwanted behavior occurring.
/usr/lib/debug/
, and source files are installed under /usr/src/debug
. See the GDB documentation for more information about debug packages.glibc
Certain packages such as glibc are stripped regardless. Check the PKGBUILD
for sections such as:
strip $STRIP_BINARIES usr/bin/{gencat,getconf,getent,iconv,iconvconfig} \ usr/bin/{ldconfig,locale,localedef,nscd,makedb} \ usr/bin/{pcprofiledump,pldd,rpcgen,sln,sprof} \ usr/lib/getconf/* strip $STRIP_STATIC usr/lib/*.a strip $STRIP_SHARED usr/lib/{libanl,libBrokenLocale,libcidn,libcrypt}-*.so \ usr/lib/libnss_{compat,db,dns,files,hesiod,nis,nisplus}-*.so \ usr/lib/{libdl,libm,libnsl,libresolv,librt,libutil}-*.so \ usr/lib/{libmemusage,libpcprofile,libSegFault}.so \ usr/lib/{audit,gconv}/*.so
And remove them where appropriate.
Clang
Packages using Clang as the compiler will not build with the debug
option due to the debug flag -fvar-tracking-assignments'
not being handled (e.g. js78).
Add the following at the top of the build()
function to only remove the flag for the affected package:
build() { CFLAGS=${CFLAGS/-fvar-tracking-assignments} CXXFLAGS=${CXXFLAGS/-fvar-tracking-assignments} [...]
LTO
Using LTO will, both during compiling and in a debugger, use more memory[1][2]. Depending on the application, especially if it is a large one like Firefox or Qt, it might exceed the available memory. Build the application without LTO if this happens.
All packages in the official repositories are generally built with LTO.
Building and installing the package
Build the package from source using makepkg
while in the PKGBUILD
's directory. This could take some time:
$ makepkg
Then install the built package:
# pacman -U glibc-2.26-1-x86_64.pkg.tar.gz
Getting the trace
The actual backtrace (or stack trace) can now be obtained via gdb, the GNU Debugger. Run it via:
# gdb /path/to/executable
$PATH
, so an absolute path to the executable is not always needed.Then, within gdb
, type run
followed by any arguments you wish the program to start with:
(gdb) run arguments
Now do whatever is necessary to evoke the bug. gdb will automatically halt the application when it crashes and prompt for commands.
In case of freezes or similar issues, press Ctrl+c
and you will be returned to the command prompt, too.
(gdb) set logging enabled on
gdb.txt
. An alternate file name can be specified with:
(gdb) set logging file trace.log
And finally have the backtrace written to trace.log in the current working directory.
(gdb) thread apply all backtrace full
# gdb /usr/bin/python (gdb) run <python application>
You can also debug an already running application:
# gdb --pid=$(pidof firefox) (gdb) continue
To debug an application that has already crashed, you will want to invoke gdb
on its core dump.