8

我想在我的自定义 linux 发行版上调试 pthread,但我遗漏了一些东西。我的主机是 Ubuntu 12.04,我的目标是使用 crosstool-NG 交叉编译器工具集构建的 i486 定制嵌入式 Linux,操作系统的其余部分是使用 Buildroot 构建的。

我将列出事实:

  • 我可以在我的目标上运行多线程应用程序

  • 当我在目标上运行多线程应用程序时,Google Breakpad无法创建崩溃报告。当我在我的主机上运行它时,具有完全相同构建的 Breakpad 库的完全相同的应用程序将成功。

  • GDB 无法在我的目标上调试多线程应用程序。

例如

$./gdb -n -ex "thread apply all backtrace" ./a.out --pid 716

dlopen failed on 'libthread_db.so.1' - /lib/libthread_db.so.1: undefined symbol: ps_lgetfpregs
GDB will not be able to debug pthreads.
GNU gdb 6.8

我不认为 ps_lgetfpregs 是因为这个问题。

  • 我的 crosstool 构建创建了 libthread_db.so 文件,并将其放在目标上。

  • 我的 crosstool 构建为我的目标创建了 gdb,因此它应该与我在目标上运行的相同库链接。

  • 如果我在我的主机上运行 gdb,针对我的测试应用程序,我会得到每个正在运行的线程的回溯。

我怀疑 Breakpad 的问题与 GDB 的问题有关,但我无法证实这一点。唯一的共同点是缺乏多线程调试。

我的主机和目标之间存在一些重要的差异,这使我无法在目标上调试 pthread。

有谁知道它是什么?

编辑:

来自 TI 的Denys Dmytriyenko说:

通常,GDB 不是很挑剔,您可以混合搭配不同版本的 gdb 和 gdbserver。但是,不幸的是,如果您需要调试多线程应用程序,则需要对特定 API 进行一些依赖...

例如,如果您没有为线程支持正确构建 GDB,这是您可能会看到的消息之一:

dlopen 在“libthread_db.so.1”上失败 - /lib/libthread_db.so.1:未定义符号:ps_lgetfpregs GDB 将无法调试 pthread。

请注意,此错误与我得到的错误相同,但他没有详细说明如何“正确”构建 GDB。

GDB FAQ说:

(Q) GDB 没有看到除了发生崩溃的线程之外的任何线程;或者当我设置断点时 SIGTRAP 会杀死我的程序。

(A) 这在 Linux 上经常发生,尤其是在嵌入式目标上。有两个常见的原因:

  • 您正在使用 glibc,并且您已经剥离了 libpthread.so.0

  • libpthread.so.0 和 libthread_db.so.1 不匹配

GDB 本身不知道如何解码 glibc 维护的“线程控制块”,被认为是 glibc 私有实现细节。它使用 libthread_db.so.1(glibc 的一部分)来帮助它这样做。因此,libthread_db.so.1 和 libpthread.so.0 的版本和编译标志必须匹配。此外,libthread_db.so.1 要求某些非全局符号存在于 libpthread.so.0 中。

解决方案:使用 strip --strip-debug libpthread.so.0 代替 strip libpthread.so.0。

我尝试了一个未剥离的 libpthread.so.0,但它没有任何区别。我将调查 pthread 和 thread_db 之间的任何不匹配。

4

2 回答 2

5

这个:

dlopen failed on 'libthread_db.so.1' - /lib/libthread_db.so.1: undefined symbol: ps_lgetfpregs
GDB will not be able to debug pthreads.

表示该libthread_db.so.1库无法ps_lgetfpregs在 gdb 中找到该符号。

为什么?

因为我使用带有“构建静态本机 gdb”选项的 Crosstoolg-NG 构建了 gdb,这将-static选项添加到 gcc。

本机 gdb 是使用该-rdynamic选项构建的,这会在 ELF 文件中的.dynsym符号表中填充所有符号,甚至是未使用的符号。libread_db 使用此符号表ps_lgetfpregs从 gdb 中查找。

但是从-staticELF.dynsym文件中删除表。

此时有两种选择:

  1. 如果要调试线程,请不要构建静态本机 gdb。
  2. 构建一个静态 gdb 和一个静态 libthread_db(未测试)

编辑:

顺便说一句,这并不能解释为什么 Breakpad 无法在我的目标上调试多线程应用程序。

于 2012-09-11T08:04:06.010 回答
0

只是...要使用 gdb 调试器,您需要使用 -g 选项编译代码。例如,gcc -g -c *.c。

于 2013-10-14T18:35:49.480 回答