我的应用程序中有一个随机崩溃(多线程),我正在尝试调试它。 但是,当我使用'bt'命令时,我得到以下输出(而不是跟踪):
#0 0x9f665582 in ?? ()
我不知道这是造成这种情况的原因。因此,为了查看细节,我尝试打印当前的$ ip(指令指针):
x /i $eip
0x9f665582: mov (%esi),%edi
现在,当我尝试在“%esi”和“%edi”检查内存的内容(上下512字节)时,我会在所有情况下得到以下内容:
<Address 0xblabla out of bounds>
看起来目的地/来源地址已损坏,对吧?
此外,当我运行'list'命令时,我得到了父线程的源代码,它除了在循环中运行之外什么都不做。我怀疑父线程是否导致此崩溃。但是,可能有些线程正在破坏父线程的堆栈帧。但是我如何找到哪个数据结构/线程呢? 或者如果你想到任何其他原因,我会在这里提出一些建议。
答案 0 :(得分:1)
回溯中单帧(#0)中缺少符号名称与%eip
值不在有效代码中的前提一致(尽管缺少符号表也可能导致)。如果0x9f665582
实际上不在函数内,则碰巧在那里的数据不一定是指令,在这种情况下,我们不希望%esi
必须包含映射地址。简而言之,%eip
的价值更可能是%esi
的价值。
%eip
可以通过多种方式设置为虚假值。堆栈损坏(此处已提到)是一种方式。如果某个类似缓冲区溢出的内容存储在堆栈中,则返回指令将分支到被破坏位置的值而不是正确的返回地址。
另一种方式%eip
可以设置为伪值,是一个函数指针通过具有伪值的指针取消引用。可能发生的一个例子是对包含函数指针的结构的陈旧引用。如果这个结构的内存被释放然后被该内存的合法(新)所有者覆盖,那么尝试使用该结构将会有问题。
为了理解这次崩溃的细节,我想说有两点需要关注。一个是各种寄存器的值;另一个是堆栈的内容。在堆栈上查找有效返回地址的一种方法是使用类似x/32a
的内容检查堆栈的范围(/a
引导gdb以查找与地址对应的名称)。返回地址通常呈现为函数名称加上偏移量;如果您反汇编该函数,并且紧接在堆栈上的地址之前的指令是一个调用指令,则使其成为返回地址。如果单调乏味,可以通过匹配堆栈上的返回地址值来重建部分回溯;如果代码使用%ebp
作为帧指针而不仅仅是另一个寄存器(检查反汇编可以帮助确定),这会更容易。
崩溃时%esp
的值可能会告诉您堆栈的哪个部分最近处于活动状态,尽管这可能会以多种方式混淆。要记住的一件事是发生崩溃的“指令”可能不是%eip
的初始虚假值,而只是试图取消引用未映射地址的第一个“指令”。 (我引用“指令”,因为取决于%eip
确切到达的位置,该内存的内容可能甚至不是合法的代码。分支到杂草时可能会出现各种各样的问题,包括非法指令,但在这次崩溃中,它试图取消引用未映射的地址。
在这种情况下,最近的挑战似乎是找到一个连贯的参考框架,用于最近按预期行事的内容。基于合法返回地址的重建部分回溯似乎是最有可能的候选者。
快乐狩猎!