调试/获取跟踪数据
通常,为了让可执行文件尽可能小,会在编译和链接时移除和运行无关的调试信息。这种可执行文件的栈回溯信息非常少,所以在调试软件或者报告 Bug 的时候,需要安装带调试信息的版本,或者使用相关服务补充调试信息。这样在报告软件 bug 时就可以提供完整的栈回溯信息,对开发者的帮助更大。
确认软件包[编辑 | 编辑源代码]
首先是确认需要调试信息的软件包名称。
[...]
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 [...]
可以看到在出现??
的地方调试信息是缺失的,库的名称和执行的函数也是。相似的,当这一行(no debugging symbols found)
出现在调试信息中时,需要寻找需要的文件。使用Pacman来获取包信息:
# pacman -Qo /lib/libthread_db.so.1 /lib/libthread_db.so.1 is owned by glibc 2.5-8
可以确认需要的是 glibc包 软件包的 2.5-8 版本。重复这一步,确认获取完整的堆栈回溯需要的软件包列表。
通过下面几种方式获取调试信息。
Debuginfod[编辑 | 编辑源代码]
For packages in the official repositories that support it [1], debug information can be retrieved directly over HTTP with debuginfod.
If one wants to 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
Debuggers like gdb can download them automatically.
You can do for example:
# coredumpctl gdb
And then inside gdb
(gdb) bt full
and you will have the debug symbols of the last crashed application in your system.
Install 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 [testing-debug] Include = /etc/pacman.d/mirrorlist [community-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 [community-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 ...
重新编译软件包[编辑 | 编辑源代码]
如果软件包没有被 debuginfod 支持,比如 AUR 中的软件包,可以通过源码重新编译获取调试信息。官方软件仓库中的软件包请参考ABS, AUR 中的软件参考 AUR#Acquire build files。
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.
编译设置[编辑 | 编辑源代码]
Pacman 从 4.1 开始,会使用 etc/makepkg.conf
中的 DEBUG_CFLAGS
和 DEBUG_CXXFLAGS
编译标志。要使用它们,请开启debug
makepkg选项并禁用strip
。这两个选项会强制编译调试信息并在链接成可执行文件时保留这些信息。
/etc/makepkg.conf
OPTIONS+=(debug !strip)
要修改单个软件包设定, 修改 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} [...]
构建和安装软件包[编辑 | 编辑源代码]
当在PKGBUILD的文件夹中使用makepkg
,这可能花费些时间:
$ makepkg
然后安装这个软件包:
# pacman -U glibc-2.26-1-x86_64.pkg.tar.gz
获得回溯[编辑 | 编辑源代码]
真正的回溯 (或堆栈回溯)现在可以通过例如GNU调试器gdb包来获得。 通过以下任一命令运行它:
# gdb /path/to/file
或:
# gdb (gdb) exec /path/to/file
如果已经在$PATH
变量中设定过了,路径可以省略
然后在gdb
中,键入run
连同以下任何你想要程序运行时的参数,例如:
(gdb) run --no-daemon --verbose
开始执行这个文件,复现要追踪的 bug。对于实际日志,键入以下行:
(gdb) set logging file trace.log (gdb) set logging enabled on
然后:
(gdb) thread apply all bt full
然后输出回溯到在gdb
运行的目录中trace.log
。退出时,键入:
(gdb) set logging enabled off (gdb) quit
# gdb /usr/bin/python (gdb) run <python application>
你也可以调试一个已经运行的程序,例如:
# gdb --pid=$(pidof firefox) (gdb) continue
要调试已经崩溃的程序,请用 gdb
分析 core dump.