我有一个已部署到客户站点的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 ?? ()
虽然编译调试版本并将其部署在客户的网站然后等待另一次崩溃是可行的,但由于多种原因,这将是相对困难和不可取的。
我对代码非常熟悉,并且根据客户的错误报告对代码崩溃的位置有了更好的了解。
有什么方法可以从这个核心转储中收集更多信息?通过字符串或其他调试器或任何东西?感谢。
答案 0 :(得分:9)
gdb的这种响应:
(gdb) bt
#0 0xc0199470 in ?? ()
也可能发生在堆栈被缓冲区溢出破坏的情况下,其中返回地址被覆盖在内存中,因此程序计数器被设置为看似随机的区域。
这是即使使用相应的符号数据库进行构建也会导致符号查找错误(或奇怪的回溯)的方法之一。如果您在拥有符号表后仍然可以获得此信息,那么您的问题很可能是客户的数据导致代码出现问题。
答案 1 :(得分:6)
未来:
对于这种情况:
你知道一般区域,所以要看你是否正确,去堆栈跟踪并找到汇编代码 - 眼球它,看看你认为它是否与你的来源匹配(如果你有一些想法,这会更容易源生成此程序集)。如果它看起来正确,那么您对您的假设进行了一些验证。您可以通过查看堆栈来找出局部变量的值(因为您知道传入并声明了什么)。
答案 2 :(得分:3)
在gdb下,“info registers”应该在崩溃时为您提供足够的执行状态,以便与可执行文件和相关共享库的反汇编一起使用。我通常使用objdump进行反汇编,将输出重定向到一个文件,然后在我最喜欢的编辑器中调出文件 - 这对于保存记录就很有用了。此外,gdb的“info target”和“info sharedlib”可用于确定加载共享库的位置。
随着寄存器状态,堆栈内容和反汇编以及一点运气,重建callstack应该是直截了当的(如果单调乏味)(当然,除非堆栈已被缓冲区溢出或类似的灾难破坏) ......在这种情况下可能需要一个Ouija板或水晶球。)
您也可以将使用-g构建的较新版本的反汇编与剥离版本的反汇编关联起来。
答案 3 :(得分:2)
答案 4 :(得分:1)
您是否拥有用于编译旧版本的完全源代码(例如;通过源代码树中的标记或类似内容)?也许您可以使用它重建,并可能了解发生崩溃的位置?
答案 5 :(得分:1)
尝试对核心文件运行“pmap”(如果hp / ux有此工具)。这应该报告核心文件中所有模块的起始地址。有了这些信息,您应该能够获取故障位置的地址并找出崩溃的库。崩溃地址与库中已知函数的地址之间的进一步地址比较(对应库的“nm”)可以帮助您确定崩溃的函数。
即使你确实设法识别堆栈顶部的函数,这个函数也不太可能是问题的根源......希望它实际上已经在你的代码中崩溃而不是,比方说,标准C字符串库。重建堆栈跟踪是当时的下一个最好的事情。
答案 6 :(得分:0)
这里没有太多信息。剥离二进制文件。但是看看分段错误......你应该寻找有可能覆盖一块内存的地方。
这只是一个建议。可能会有很多问题。
顺便说一句,如果您无法在本地计算机上重现,那么客户数据量可能就成了问题。答案 7 :(得分:0)
我认为核心文件不应包含符号。您需要能够构建一个与您发送给客户的完全相同的程序版本,但使用-g。如果剥离调试可执行文件,它应该与发布的版本相同。只有这样,gdb才能为您提供有用的东西。