17

我有一个已部署到客户站点的 C 应用程序。它是在 HP-UX 上编译和运行的。用户报告了崩溃,我们获得了核心转储。到目前为止,我一直无法复制内部的崩溃。

正如您所怀疑的,核心文件/部署的可执行文件完全没有任何类型的符号。当我在 gdb 中加载它并执行 bt 时,我得到的最好的结果是:

(gdb) bt
#0  0xc0199470 in ?? ()

我可以在文件上做一个“字符串核心”,但我的理解是我得到的只是可执行文件中的所有字符串,所以在那里追踪任何东西似乎是半不可能的。

我确实有可执行文件的调试版本(使用 -g 编译),不幸的是,它比发布的版本更新了几个月。如果我尝试使用该集线器启动 gdb,我会看到:

warning: exec file is newer than core file.
Core was generated by `program_name'.
Program terminated with signal 11, Segmentation fault.
__dld_list is not valid according to __dld_flags.

#0  0xc0199470 in ?? ()
(gdb) bt
#0  0xc0199470 in ?? ()

虽然编译调试版本并将其部署在客户站点然后等待另一次崩溃是可行的,但由于多种原因,这相对困难且不可取。

我对代码非常熟悉,并且根据客户的错误报告对代码崩溃的位置有一个相对较好的了解。

有什么方法可以从这个核心转储中收集更多信息吗?通过字符串或其他调试器或任何东西?谢谢。

4

8 回答 8

9

为未来:

  1. 确保您始终使用外部符号数据库进行构建(这不是调试构建——它是发布构建,但您单独存储符号表)
  2. 为您部署的版本保留它

对于这种情况:

您知道一般区域,因此要查看您是否正确,请转到堆栈跟踪并找到汇编代码 - 观察它并查看您是否认为它与您的源代码匹配(如果您知道是什么源代码生成的,这会更容易)部件)。如果它看起来是正确的,那么你对你的假设有一些验证。您可以通过查看堆栈来找出局部变量的值(因为您知道传入和声明的内容)。

于 2009-06-26T18:23:54.487 回答
9

来自 gdb 的这种类型的响应:

(gdb) bt
#0  0xc0199470 in ?? ()

也可能发生在堆栈被缓冲区溢出破坏的情况下,其中返回地址在内存中被覆盖,因此程序计数器被设置为看似随机的区域。

这是即使具有相应符号数据库的构建也可能导致符号查找错误(或奇怪的回溯)的方式之一。如果您在获得符号表后仍然得到此信息,则您的问题很可能是您的客户数据导致您的代码出现了一些问题。

于 2009-06-26T18:50:14.460 回答
4

在 gdb 下,“信息寄存器”应该在崩溃时为您提供足够的执行状态,以便与可执行文件和相关共享库的反汇编一起使用。我通常使用 objdump 进行反汇编,将输出重定向到一个文件,然后在我最喜欢的编辑器中调出该文件——这对于在弄清楚事情时记笔记很有用。gdb 的“信息目标”和“信息共享库”对于确定共享库的加载位置也很有用。

有了寄存器状态、堆栈内容和反汇编以及一点运气,重建调用堆栈应该很简单(如果乏味的话)(当然,除非堆栈被缓冲区溢出或类似的灾难破坏......在这种情况下可能需要一个占卜板或水晶球。)

您还可以将使用 -g 构建的较新版本的反汇编与剥离版本的反汇编相关联。

于 2009-06-26T20:08:59.667 回答
3
  1. 始终使用源代码控制(CVS/GIT/Subversion/etc),即使是测试版本
  2. 标记所有版本
  3. 考虑(将来)使用调试(-g)进行构建并在发布前剥离可执行文件。注意:不要使用和不使用 -g 进行两次构建;它们很可能不匹配,因为 -g 即使在相同的优化级别有时也会导致生成不同的代码。在超级性能关键代码中,您可以放弃关键文件的 -g - 大多数它不会产生任何影响。
  4. 如果你真的卡住了,转储堆栈并将堆的相关部分转储到十六进制并手动查看;也许获取一个检测副本并在生成的代码和堆栈中寻找类似的“签名”。这是真正的“老派”调试... :-)
于 2009-06-26T19:46:16.280 回答
1

您是否有用于编译旧版本的确切源代码(例如,通过源代码树中的标签或类似的东西)?也许您可以使用它进行重建,并可能深入了解崩溃发生的位置?

于 2009-06-26T18:21:00.390 回答
1

尝试对核心文件运行“pmap”(如果 hp/ux 有这个工具)。这应该报告核心文件中所有模块的起始地址。有了这些信息,您应该能够获取故障位置的地址并找出哪个库崩溃了。崩溃地址和库中已知函数的地址之间的进一步地址比较(“nm”对库应该得到)可以帮助您确定哪个函数崩溃了。

即使您确实设法识别了堆栈顶部的函数,该函数也不太可能是问题的根源......希望它实际上已经在您的代码中崩溃了,而不是标准 C字符串库。重建堆栈跟踪是当时最好的事情。

于 2009-06-26T20:20:22.233 回答
0

这里没有太多信息。二进制文件已被剥离。但是查看分段错误...您应该寻找有可能覆盖一段内存的地方。

这只是一个建议。可能有很多问题。

顺便说一句,如果您无法在本地机器上重现,那么客户的数据量可能是个问题。

于 2009-06-26T18:22:08.250 回答
0

我不认为核心文件应该包含符号。您需要能够构建与您交付给客户的程序完全相同的程序版本,但使用 -g。如果您剥离您的调试可执行文件,它应该与交付的版本相同。只有这样,gdb 才能为您提供任何有用的东西。

于 2009-06-27T14:11:45.557 回答