我正在开发用于Cortex-M3嵌入式微控制器的软件(Atmel SAM3S) 我使用的是IAR EWARM IDE&编译器。 我怀疑由于某种原因,我有一个缓冲区溢出或内存泄漏,导致堆栈被破坏,因为我突然发现自己被困在我的代码空间之外。
我问这个问题的原因是,很难找出导致这种混乱的原因,并且我想知道当你想找出问题的原因时你使用了哪种技术。
您使用的是内存调试器,在线跟踪调试硬件等吗?
答案 0 :(得分:4)
您应该尝试使用金丝雀值。这就是它基本上如何 - 比如你有一些struct
:
struct foo {
unsigned long bar;
void * baz;
};
修改它,看起来像这样:
struct foo {
unsigned long canary1;
unsigned long bar;
void * baz;
unsigned long canary2;
};
初始化struct
时,请将一些任意值放入canary1
和canary2
。每当您对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天里发生了什么变化,试图找出任何问题。最后,只需打印出你的代码就可以尝试缩小发生错误跳转的位置。如果你可以将它归结为一个或两个函数,你可以跟踪汇编程序并查看它是否是编译器问题,内存问题或中断问题。祝好运!