Gdb MIPS核心转储,ra和pc等于0000000
我在我们的一个进程中得到了间歇性的堆芯转储。 除了崩溃的线程之外,所有线程的堆栈看起来都正常,并且解析正确 崩溃的线程具有明显损坏的调用堆栈。 堆栈有两个帧,都是0x00000000。 从寄存器上看,PC和RA都是0(这解释了调用堆栈…) 原因寄存器为00800008Gdb MIPS核心转储,ra和pc等于0000000,gdb,mips,coredump,Gdb,Mips,Coredump,我在我们的一个进程中得到了间歇性的堆芯转储。 除了崩溃的线程之外,所有线程的堆栈看起来都正常,并且解析正确 崩溃的线程具有明显损坏的调用堆栈。 堆栈有两个帧,都是0x00000000。 从寄存器上看,PC和RA都是0(这解释了调用堆栈…) 原因寄存器为00800008 有没有办法让我获得更多关于崩溃线程的信息 为什么寄存器本身已损坏?(或者反过来,调试器在内核转储中根据堆栈填充这些寄存器?) 谢谢 首先回答(2)——因为了解实际发生的情况对于了解更多有关坠机根本原因的信息非常重要: 实际上,在运
#包括
内栏(空)
{
char buf[10]=“ABCDEFGHI”;
memset(buf,0,50);
返回0;
}
int foo(无效)
{
返回杆();
}
int main(int argc,char*argv[])
{
返回foo();
}
如果我们看一下foo()的反汇编:
(gdb)disas foo
函数foo的汇编程序代码转储:
0x00400408:附加sp,sp,-32
0x0040040c:sw ra,28(sp)
0x00400410:sw s8,24(sp)
0x00400414:移动s8,sp
0x00400418:jal 0x4003a0
0x0040041c:否
0x00400420:移动sp,s8
0x00400424:lw ra,28(sp)
0x00400428:lw s8,24(sp)
0x0040042c:附加sp,sp,32
0x00400430:jr ra
0x00400434:否
汇编程序转储结束。
我们非常清楚地看到,RA存储在函数开始时的堆栈上(sw-RA,28(sp)
),然后在结束时恢复(lw-RA,28(sp)
),然后跳转返回(jr-RA
)。我显示了For(),因为它较短,但是对于Bar(),完全相同的结构是真的——除了在Bar()中,还有MeMeSET()在中间,它在堆栈上覆盖RA(它将50字节写入大小为10的数组);然后恢复到寄存器中的是0,最终导致崩溃
所以,现在我们知道崩溃的根本原因是某种堆栈损坏,这让我们回到问题(1):有没有办法获得关于崩溃线程的更多信息
好吧,这有点困难,调试更像是一门艺术而不是一门科学,但这里有一些要记住的原则:
- 基本思想是找出导致堆栈损坏的原因——很可能是对某个本地缓冲区的写入,如上面的示例所示
- 尽可能多地关注流程中发生损坏的位置。日志记录在这里有很大的帮助:您看到的最后一个日志显然发生在崩溃之前(虽然不一定发生在崩溃之前!)——在可疑区域添加更多日志记录,以锁定崩溃位置。当然,如果您有权访问调试器,还可以单步执行代码以找出崩溃的位置
- 一旦找到崩溃位置,从那里向后工作就容易多了:首先,在崩溃之前,PC还没有设置为0,因此您应该能够看到回溯(不过,请注意回溯本身是“计算的”使用存储在堆栈上的值——一旦这些值损坏,就无法计算出超出损坏范围的回溯。但在这种情况下,这实际上很有用:这可以非常准确地告诉您损坏在内存中的位置:回溯被截断的点是损坏的RA(在堆栈上)
- 一旦发现了损坏的内容,但仍然不知道是什么导致了损坏,请使用观察点:一旦进入将最终被覆盖的RA放在堆栈上的函数,就在其上设置一个观察点。一旦腐败发生,这应该会导致中断
#include <string.h>
int bar(void)
{
char buf[10] = "ABCDEFGHI";
memset(buf, 0, 50);
return 0;
}
int foo(void)
{
return bar();
}
int main(int argc, char *argv[])
{
return foo();
}
(gdb) disas foo
Dump of assembler code for function foo:
0x00400408 <+0>: addiu sp,sp,-32
0x0040040c <+4>: sw ra,28(sp)
0x00400410 <+8>: sw s8,24(sp)
0x00400414 <+12>: move s8,sp
0x00400418 <+16>: jal 0x4003a0 <bar>
0x0040041c <+20>: nop
0x00400420 <+24>: move sp,s8
0x00400424 <+28>: lw ra,28(sp)
0x00400428 <+32>: lw s8,24(sp)
0x0040042c <+36>: addiu sp,sp,32
0x00400430 <+40>: jr ra
0x00400434 <+44>: nop
End of assembler dump.