【问题标题】:Debugging crash with bt printing nothing in gdb在 gdb 中不打印任何内容的 bt 调试崩溃
【发布时间】:2016-01-18 19:34:50
【问题描述】:

我的应用程序(多线程)发生随机崩溃,我正在尝试调试它。 但是,当我使用“bt”命令时,我得到以下输出(而不是跟踪):

#0 0x9f665582 in ?? ()

我不知道是什么原因造成的。因此,为了查看细节,我尝试打印当前的 $ip(指令指针):

x /i $eip
0x9f665582:    mov   (%esi),%edi

现在,当我尝试检查“%esi”和“%edi”的内存内容(上下 512 个字节)时,在所有情况下都会得到以下结果:

<Address 0xblabla out of bounds>

看起来目标/源地址已损坏,对吧?

另外,当我运行“list”命令时,我得到了父线程的源代码,它什么都不做,只是在一个循环中运行,没有任何工作。我怀疑父线程导致了这次崩溃。但是,可能是某个线程正在破坏父线程的堆栈帧。但是我怎么能找到哪个数据结构/线程在做呢? 或者,如果您想到任何其他原因,我将不胜感激。

【问题讨论】:

    标签: debugging segmentation-fault gdb


    【解决方案1】:

    回溯中单帧 (#0) 中缺少符号名称与 %eip 值不在有效代码内的前提一致(尽管缺少符号表也可能导致这种情况)。如果0x9f665582 不在函数内,那么恰好存在的数据不一定是指令,在这种情况下,我们不会期望%esi 一定包含映射地址。简而言之,%eip 的值比%esi 的值更可能是问题所在。

    %eip 可以通过多种方式设置为虚假值。堆栈损坏(这里已经提到)是一种方法。如果像缓冲区溢出这样的东西破坏了存储在堆栈上的返回地址,则返回指令将跳转到被破坏位置的值而不是正确的返回地址。

    %eip 可以设置为虚假值的另一种方法是通过具有虚假值的指针取消对函数指针的引用。可能发生这种情况的一个例子是对包含函数指针的结构的过时引用。如果此类结构的内存被释放,然后被该内存的合法(新)所有者覆盖,则尝试使用该结构将是有问题的。

    为了了解这次崩溃的细节,我想说有两件事需要关注。一是各个寄存器的值;另一个是堆栈的内容。在堆栈上找到有效返回地址的一种方法是检查堆栈的范围,例如x/32a/a 引导 gdb 查找与地址对应的名称)。返回地址通常呈现为函数名加上偏移量;如果您反汇编该函数,并且地址在堆栈上的指令之前的指令是调用指令,则该指令使其成为返回地址。如果很乏味,可以通过匹配堆栈上的返回地址值来重建部分回溯;如果代码使用%ebp 作为帧指针而不是另一个寄存器,这会更容易(反汇编检查可以帮助确定)。

    崩溃时%esp 的值可能会告诉您堆栈的哪一部分最近处于活动状态,尽管这可能会以多种方式混淆。要记住的一件事是,发生崩溃的“指令”可能不是%eip 的初始虚假值,而只是第一个试图取消引用未映射地址的“指令”。 (我引用“指令”是因为根据%eip 的确切位置,该内存的内容甚至可能不是合法代码)。分支到杂草中时可能会出现各种错误,包括非法指令,但在这次崩溃中,它试图取消引用未映射的地址。

    在这种情况下,当前面临的挑战似乎是为最近表现符合预期的事物找到一个连贯的参考框架。基于合法返回地址重建的部分回溯似乎是最有可能的候选者。

    狩猎愉快!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-26
      • 2021-02-13
      相关资源
      最近更新 更多