使用"bt"调试崩溃不会在 GDB 中打印任何内容



我的应用程序(多线程)中随机崩溃,我正在尝试调试它。

但是,当我使用"bt"命令时,我得到以下输出(而不是跟踪):

#0 0x9f665582 in ?? ()

我不知道这是造成这种情况的原因。因此,为了查看详细信息,我尝试打印当前$ip(指令指针):

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

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

<Address 0xblabla out of bounds>

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

此外,当我运行"list"命令时,我获取了父线程的源代码,它什么都不做,只是在不做任何工作的循环中运行。我怀疑父线程导致此崩溃。但是,可能是某个线程损坏了父线程的堆栈帧。但是我如何找到哪个数据结构/线程正在执行此操作?

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

有多种

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

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

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

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

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

狩猎愉快!

最新更新