检测堆栈覆盖错误

时间:2012-06-18 11:47:30

标签: c debugging arm cortex-m3

我正在开发用于Cortex-M3嵌入式微控制器的软件(Atmel SAM3S) 我使用的是IAR EWARM IDE&编译器。 我怀疑由于某种原因,我有一个缓冲区溢出或内存泄漏,导致堆栈被破坏,因为我突然发现自己被困在我的代码空间之外。

我问这个问题的原因是,很难找出导致这种混乱的原因,并且我想知道当你想找出问题的原因时你使用了哪种技术。

您使用的是内存调试器,在线跟踪调试硬件等吗?

4 个答案:

答案 0 :(得分:4)

您应该尝试使用金丝雀值。这就是它基本上如何 - 比如你有一些struct

struct foo {
    unsigned long bar;
    void * baz;
};

修改它,看起来像这样:

struct foo {
    unsigned long canary1;
    unsigned long bar;
    void * baz;
    unsigned long canary2;
};

初始化struct时,请将一些任意值放入canary1canary2。每当您对struct执行某些操作时,请检查值是否保持不变。这样,如果您有缓冲区溢出或堆栈粉碎,您将检测到它。您可以使用自动变量执行相同的内部函数:

int foo(int bar) {
      unsigned long canary1 = 0xDEADBABE;
      char baz[20];
      unsigned long canary2 = 0xBAD0C0DE;
      ...
}

等等。不要忘记在return之前检查值是否保持不变。此外,如果您可以让代码始终跳转到同一位置,请尝试在那里放置一些代码(或断点)并获取堆栈跟踪。

GCC知道如何自己添加这些canary值,但我不知道你的编译器是否可以这样做。但你仍然可以手动完成。

答案 1 :(得分:2)

程序计数器是一个寄存器,因此不能“覆盖”。正如你所说,可能发生的事情是堆栈被覆盖,然后你执行一个返回指令,从堆栈中读取一个无效的返回地址,从而导致跳转到la-la-land。

我最喜欢的调试方法是打印出来,当然,在嵌入式目标上可能很难。第二好的是逐步完成可疑程序。

您还应该调查已知会导致跳转的事情,例如中断服务例程。

答案 2 :(得分:2)

我在STM32上使用IAR EWARM时遇到了类似的问题。内存转储,反汇编,金丝雀,一切都没有发现。最后回滚到早期版本的EWARM,问题就消失了。我向IAR支持发了一条消息,但从未收到回复。对不起,我不记得这是哪个版本的EWARM。这是几个项目之前。

我会打开一个内存窗口并首先尝试金丝雀测试。如果它仍然随机跳出代码空间,请尝试安装旧版本的EWARM。

答案 3 :(得分:1)

我可以补充的一点是,对于ARM芯片,有可能在某处使用BL而不是BX或BLX导致芯片进入错误的Thumb / ARM模式。不像以后的芯片那么常见,但仍然......

当我发现无处跳转时,我会查找错误的函数指针表,覆盖任何中断向量表,是的,堆栈溢出是最容易测试的。将已知的字节值丢弃到堆栈区域,当崩溃发生时,查看调试器剩余的堆栈数。如果没有,你去吧。

我也会做标准,看看过去X天里发生了什么变化,试图找出任何问题。最后,只需打印出你的代码就可以尝试缩小发生错误跳转的位置。如果你可以将它归结为一个或两个函数,你可以跟踪汇编程序并查看它是否是编译器问题,内存问题或中断问题。祝好运!