调试没有符号的核心文件

我有一个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 ?? () 

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

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

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

这种来自gdb的响应:

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

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

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

为未来:

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

对于这种情况:

你知道一般的区域,所以要看你是否正确,转到堆栈跟踪并找到汇编代码 – 眼球它,看看你认为它是否与你的源匹配(如果你知道什么来源产生了这个,这会更容易部件)。 如果它看起来正确,那么您对您的假设进行了一些validation。 您可以通过查看堆栈来找出局部变量的值(因为您知道传入并声明了什么)。

在gdb下,“info registers”应该在崩溃时给你足够的执行状态,以便与可执行文件和相关共享库的反汇编一起使用。 我通常使用objdump进行反汇编,将输出重定向到一个文件,然后在我最喜欢的编辑器中调出文件 – 这对于保存笔记很有用。 此外,gdb的“info target”和“info sharedlib”可用于确定加载共享库的位置。

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

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

  1. 始终使用源代码控制(CVS / GIT / Subversion / etc),即使对于测试版本也是如此
  2. 标记所有版本
  3. 考虑(将来)使用调试(-g)进行构建并在发送之前删除可执行文件。 注意:不要使用和不使用-g进行两次构建; 它们可能不匹配,因为-g有时会导致即使在相同的优化级别也会生成不同的代码。 在超级性能关键代码中,您可以放弃关键文件的-g – 大多数它不会产生影响。
  4. 如果你真的陷入困境,请转储堆栈并将堆的相关部分转储为hex并手动查看; 也许采用一个仪表化的副本,并在生成的代码和堆栈中寻找类似的“签名”。 这是真正的 “老派”调试…… 🙂

您是否拥有用于编译旧版本的确切来源(例如;通过源代码树中的标记或类似内容)? 也许您可以使用它重建,并可能了解发生崩溃的位置?

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

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

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

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

顺便说一句,如果您无法在本地计算机上重现,那么客户数据量可能就成了问题。

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