跳转至内容

调试

来自 ArchWiki
(重定向自 分步调试指南)

本文章或章节需要扩充。

原因:本文也可以讨论一般的调试,以便将诸如 ltrace 之类的其他有用工具添加到此处。(讨论请参见 Talk:Debugging

本页面主要介绍如何收集有关错误报告的更多信息。尽管使用了“debug”(调试)一词,但它并非旨在指导如何在开发过程中调试程序。

检查核心转储可用性

核心转储(core dump)是一个文件,它包含了进程意外终止时进程的地址空间(内存)。如果应用程序以易于调试的方式编译,则“core”文件可用于找出问题所在。

核心转储的位置可能因操作系统配置而异。请参阅 core dump 以了解您的系统是否启用了核心转储文件的生成以及它们去了哪里。

段错误

有几种技术可用于弄清楚哪里出了问题。请戴上您的侦探帽。

GDB

gdb 是一个古老且经过充分测试的应用程序,用于调试应用程序。有关如何使用它获取跟踪信息的更多说明,请参阅 Debugging/Getting traces#Getting the trace。在从 gdb 运行时,您可能需要等待段错误发生。之后,将跟踪信息发布到 粘贴服务,并在错误报告中包含 URL。

如果您有一个“core”文件,可以将其与 GDB 配合使用以获取回溯信息 (backtrace)

$ gdb appname core
bt full

Valgrind

假设您有一个未剥离符号并且没有内联函数的二进制文件,通常最好也通过 valgrind 运行该程序。valgrind 是一个模拟 CPU 的工具,通常会显示问题所在或提供比 gdb 更多信息。

$ valgrind appname

如果发生崩溃,它将提供大量有用的调试输出。考虑使用 -v--leak-check=full 以获得更多信息。

或者,使用

$ valgrind --tool=callgrind appname

并通过 kcachegrind 运行输出,以图形化方式探索程序使用的函数。如果程序挂起,这会更容易确定错误的发生位置。

内存错误

在某些情况下,可能需要弄清楚应用程序是否正确处理其内存。这仅影响用 内存不安全 语言编写的应用程序。例如,一些崩溃可能是由内存错误引起的,如堆溢出。

请记住,Arch Linux 上的软件包使用额外的标志进行编译以加强应用程序安全性,这可能会影响内存错误。请参阅 Arch package guidelines/Security

AddressSanitizer

为了使 ASan 正常工作,应用程序必须使用 -f sanitize=address 和调试符号进行编译。

启用 ASan 后,编译后的应用程序会变慢,但这在很大程度上取决于软件本身、使用的编译器(包括其版本)以及使用的 -O 值等。如果应用程序慢得无法忍受,尝试不同的组合是值得的。一个极端的例子是,使用 GCC 9 和 ASan 编译的 Cataclysm: Dark Days Ahead 加载一个简单的存档需要 60 分钟。没有 ASan,加载存档不到一分钟。GCC 14 将加载时间减半(使用 ASan),但仍需 30 分钟,这是不可接受的慢。Clang 18 配合 ASan 没有这个问题,减速可以忽略不计。然而,强制 GCC 14 使用 -O3 和 ASan 会大大加快加载速度,但仍然需要一分钟才能加载,并且不如 clang 快。

另一个复杂因素是,只有 GCC 9 能够触发特定的错误,即堆溢出。使用 GCC 14 编译的版本无法重现该错误。因此,也要牢记编译器版本很重要。

注意 避免在 gdb 等调试器中运行使用 ASan 编译的应用程序。在调试器中运行它会限制 ASan。ASan 本身发出的跟踪信息比调试器产生的常规回溯信息要详细得多。

要查找内存错误,只需像平常一样运行应用程序。ASan 将会自动因堆溢出或使用已释放内存等问题而崩溃应用程序。发生这种情况时,输出中会包含详细且有用的跟踪信息。ASan 的行为可以通过 ASAN_OPTIONS 环境变量 在运行时进行影响。此外,还有一些编译标志可以更改其行为。

此环境变量的一个常见用途是告诉 ASan 在发现除内存泄漏以外的任何内容时,不要致命地崩溃应用程序

ASAN_OPTIONS=halt_on_error=0

可以在以下位置找到更多信息

Valgrind

Valgrind 也可以用来检测这些行为,与 ASan 不同,它不需要编译进去。与 ASan 相比,它速度慢得多,并且功能稍有限。

为了查找内存错误,使用以下命令调用 Valgrind:

$ valgrind --tool=memcheck --track-origins=yes --keep-stacktraces=alloc-and-free application

另请参阅 #Valgrind

文件或库丢失

Strace

strace 详细找出应用程序实际在做什么。如果应用程序尝试打开一个不存在的文件,strace 可以发现它。

查找名为 appname 的程序尝试打开哪些文件

$ strace -eopen appname
提示 如果您想 grep strace 的输出,可以尝试:strace -o /dev/stdout appname | grep string

LD_DEBUG

设置 LD_DEBUG=files 可以提供应用程序正在查找哪些文件的另一个概览。对于名为 appname 的应用程序

$ LD_DEBUG=files appname > appname.log 2>&1

输出将写入 appname.log

有关更多信息,请参阅 ld-linux(8)

Readelf

如果您在运行应用程序时收到 no such file or directory 错误,请尝试以下命令

$ readelf -a /usr/bin/appname | grep interp

(将 /usr/bin/appname 替换为您的可执行文件的位置)

请确保您正在使用的解释器(例如 /lib/ld-linux-x86-64.so.2)确实存在。如果需要,请安装 ld-lsb

不是二进制文件

对可执行文件使用 file 命令以获取更多信息

$ file /usr/bin/appname

如果显示 ELF,则它是二进制可执行文件。如果显示 Python script,则表明您正在处理一个用 Python 编写的应用程序。

如果它是一个 shell 脚本,请在文本编辑器中打开该 shell 脚本,并查看(通常在文件底部)是否能找到实际应用程序(ELF 文件)的名称。然后,您可以在 shell 脚本中,在可执行文件名称之前,临时加上“gdb”以进行调试。请参阅上方关于 gdb 的部分。如果相关可执行文件还需要参数,请在命令前加上 gdb --args

对于纯 shell 脚本,您也可以使用 bash -x script_namebash -xv script_name

对于 Python 应用程序,输出通常会说明崩溃发生在哪个文件和哪一行。如果您精通 Python,可以尝试修复此问题,并将修复包含在错误报告中。

报告错误

首先检查所讨论的错误是否是打包错误。如果错误是由于 Arch Linux 打包该应用程序的方式引起的,请向 https://gitlab.archlinux.org/groups/archlinux/packaging/-/issues 报告。这也包括库或依赖项的问题(例如,如果其中一个没有构建特定的所需功能)。检查该软件包的 PKGBUILD,这可以通过 Arch build system 完成,以了解其打包方式。有关更多信息,请参阅 Bug reporting guidelines#Upstream or Arch?

如果错误与 Arch Linux 无关,并且可以在其他地方重现,则仅向上游报告。Arch Linux 无法神奇地修复上游错误。向 Arch 错误跟踪器报告它无济于事,甚至可能适得其反,因为它倾向于浪费错误管理员的时间。

参见

© . This site is unofficial and not affiliated with Arch Linux.

Content is available under GNU Free Documentation License 1.3 or later unless otherwise noted.