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