Error handling 嵌入式系统中堆栈溢出的处理

Error handling 嵌入式系统中堆栈溢出的处理,error-handling,embedded,stack-overflow,Error Handling,Embedded,Stack Overflow,在嵌入式软件中,如何以通用方式处理堆栈溢出? 我遇到了一些处理器,它确实在硬件方面提供了保护,比如最近的AMD处理器。 维基百科上有一些技巧,但这些是真正实用的方法吗 有谁能给出一个明确的建议方法,在今天的32位嵌入式处理器上,这种方法在任何情况下都有效吗?如果调用堆栈太大,堆栈内存就会耗尽,那么会发生堆栈溢出?e、 递归函数的层次太深 有一些技术可以通过在堆栈后放置已知数据来检测堆栈溢出,以便在堆栈增长过多并过度编写时可以检测到 有一些静态源代码分析工具,如GnatStack、StackAna

在嵌入式软件中,如何以通用方式处理堆栈溢出? 我遇到了一些处理器,它确实在硬件方面提供了保护,比如最近的AMD处理器。 维基百科上有一些技巧,但这些是真正实用的方法吗


有谁能给出一个明确的建议方法,在今天的32位嵌入式处理器上,这种方法在任何情况下都有效吗?

如果调用堆栈太大,堆栈内存就会耗尽,那么会发生堆栈溢出?e、 递归函数的层次太深

有一些技术可以通过在堆栈后放置已知数据来检测堆栈溢出,以便在堆栈增长过多并过度编写时可以检测到


有一些静态源代码分析工具,如GnatStack、StackAnalyzer from AbsInt和Bound-T,可用于确定或猜测最大运行时堆栈大小。

虽然嵌入式堆栈溢出可能是由递归函数失控引起的,但也可能是由错误的指针使用引起的(尽管这可能被认为是另一种错误),以及堆栈尺寸过小的正常系统操作。换句话说,如果您不分析堆栈的使用情况,它可能发生在缺陷或bug情况之外

在“处理”堆栈溢出之前,您必须识别它。一个好的方法是在初始化期间使用模式加载堆栈,然后监视在运行时有多少模式消失。通过这种方式,您可以识别堆栈达到的最高点

模式检查算法的执行方向应与堆栈增长方向相反。因此,如果堆栈从0x1000增长到0x2000,则模式检查可以从0x2000开始以提高效率。如果模式为0xAA,且0x2000处的值包含0xAA以外的内容,则您知道可能存在一些溢出


你还应该考虑在堆栈之后立即放置一个空RAM缓冲区,这样如果你检测到溢出,你可以关闭系统而不丢失数据。如果你的堆栈紧跟着堆或SRAM数据,那么识别一个溢出意味着你已经遭受了破坏。你的缓冲区将保护你一个LITTL。e位更长。在32位micro上,您应该有足够的RAM来提供至少一个小的缓冲区。

理想情况下,您可以使用静态堆栈使用率(无递归调用)编写代码。然后,您可以通过以下方法评估最大堆栈使用率:

  • 静态分析(使用工具)
  • 在完全覆盖代码的情况下运行代码时测量堆栈使用情况(或在您有合理的信心确定堆栈使用范围之前,尽可能高的代码覆盖率,只要很少运行的代码不会使用比正常执行路径更多的堆栈)
  • 但即使如此,您仍然希望有一种方法检测,然后处理堆栈溢出(如果可能的话),以提高健壮性。这在项目开发阶段尤其有用。检测溢出的一些方法:

  • 如果处理器支持内存读/写中断(即内存访问断点中断),则可以将其配置为指向堆栈区域的最远范围
  • 在内存映射配置中,设置一个小(或大)RAM块,它是一个“堆栈保护”区域。用已知值填充它。在嵌入式软件中,定期(尽可能经常)检查此区域的内容。如果它发生变化,则假设堆栈溢出
  • 一旦你检测到它,你就需要处理它。我不知道有多少方法可以让代码从堆栈溢出中优雅地恢复,因为一旦发生,你的程序逻辑几乎肯定会失效。所以你所能做的就是

  • 记录错误
  • 记录错误非常有用,因为否则症状(意外重新启动)可能很难诊断
  • 警告:即使在堆栈损坏的情况下,日志记录例程也必须能够可靠地运行。该例程应该简单。即,如果堆栈损坏,您可能无法尝试使用您喜欢的EEPROM写入后台任务写入EEPROM。可能只需将错误记录到为此目的而保留的非初始化RAM中的结构中,而非初始化RAM则无法重新启动后,必须检查hen
  • 重新启动(或者关机,特别是错误反复出现时)
  • 可能的替代方案:如果您使用的是RTOS,则只重新启动特定任务,并且您的系统设计为隔离堆栈损坏,并且所有其他任务都能够处理该任务重新启动。这需要认真考虑设计问题

  • 如果您使用的是带有内存管理单元的处理器,那么您的硬件可以用最小的软件开销为您做到这一点。大多数现代32位处理器都有内存管理单元,越来越多的32位微控制器也有内存管理单元

    在MMU中设置一个用于堆栈的内存区域。该内存区域应由MMU不允许访问的两个内存区域包围。当应用程序运行时,一旦堆栈溢出,就会收到异常/中断

    因为在错误发生的那一刻,您会得到一个异常,因此您确切地知道应用程序中堆栈的损坏位置。您可以查看调用堆栈,以确切地了解您是如何到达所处位置的。这比在问题发生很久之后通过检测问题来找出问题所在要容易得多

    我已经在PPC和AVR32处理器上成功地使用了它。当你开始使用MMU时,你会觉得这是浪费时间,因为多年来没有它,你过得很好,但一旦你在内存问题发生的确切位置看到异常的优点,你就再也不会回去了。MMU还可以检测零指针访问,如果您不允许对yo的底部公园进行内存访问