7

你通常如何解决这个问题?想象一下,一个线程在 Computer1 上的 libc 代码(这是一个系统共享库)内崩溃,然后生成一个 coredump。但是将在其上分析此 coredump 的 Computer2 可能具有不同版本的 libc。

所以:

  1. 在远程计算机上拥有相同的共享库有多重要?gdb 会在 Computer2 上没有完全相同版本的 libc 的情况下正确重建堆栈跟踪吗?

  2. 为 libc 提供正确的调试符号有多重要?gdb 会在 Computer2 上没有完全相同的调试符号的情况下正确重建堆栈跟踪吗?

  3. 对于共享系统库,避免这种调试符号不匹配问题的“正确”方法是什么?对我来说,似乎没有单一的解决方案可以优雅地解决这个问题?也许有人可以分享他的经验?

4

1 回答 1

13
  1. 这取决于。在某些处理器上,例如GDB 需要x86_64正确的展开描述符才能正确展开堆栈。在这样的机器上,用不匹配的 libc 分析 coredump 可能会产生完全的垃圾。

  2. 您不需要 libc 的调试符号来获取堆栈跟踪。如果没有调试符号,您将无法获得文件和行号,但您应该获得正确的函数名称(除非发生内联)。

  3. 您问题的前提是错误的-调试符号与此无关。在 C1 上生成 coredump 时,在 C2 上分析 coredump 的“正确”方法是拥有 C1 库的副本(例如/tmp/C1/lib/...)并指示 GDB 使用该副本而不是安装libcC2

    (gdb) set solib-absolute-prefix /tmp/C1

命令。

注意:在将内核加载到 GDB 之前,上述设置必须生效。这个:

gdb exe core
(gdb) set solib-absolute-prefix /tmp/C1

将不起作用(在设置生效之前读取核心)。

这是正确的方法:

gdb exe
(gdb) set solib-absolute-prefix /tmp/C1
(gdb) core core

(我试图在网上找到对此的参考,但没有)。

什么是展开描述符?

当代码在没有帧指针的情况下编译时需要展开描述符(优化模式下 x86_64 的默认设置)。此类代码不保存%rbp 寄存器,因此需要告诉 GDB 如何从当前帧“后退”到调用者帧(此过程也称为堆栈展开)。

为什么 C1 的 libc.so 不包含在核心中?

核心文件通常只包含程序地址空间的可写段的内容。通常不需要只读段(可执行代码和展开描述符所在的位置)——您可以直接从磁盘上的 libc.so 读取它们。

除了在 C2 上分析 C1 的核心时这不起作用!

一些(但不是全部)操作系统允许配置“完整核心转储”,操作系统也将转储只读映射,这样您就可以在任何机器上分析核心。

于 2010-12-03T05:54:48.340 回答