带有freertos的gnu arm cortex m4上的C ++异常处理程序

Posted

技术标签:

【中文标题】带有freertos的gnu arm cortex m4上的C ++异常处理程序【英文标题】:C++ exception handler on gnu arm cortex m4 with freertos 【发布时间】:2017-01-20 23:11:20 【问题描述】:

2016-12 年更新 现在还有一个关于这种行为的最小示例:https://community.nxp.com/message/862676


我正在使用带有 freertos 的 ARM Cortex M4,使用 freescales Freedom Kinetis IDE(gnu arm 工具链)。问题是

try 
    throw 4; // old scenario also not working: throw std::runtime_error("wut");
 catch (...) 

导致 CPU 停止,try 之后的代码或(当添加一些时)catch 处理程序中的代码未执行。

可以在这里找到组装:https://gist.github.com/Superlokkus/3c4201893b4c51e154e2a0afdf78fef0

我假设这会导致 SVC 中断,很抱歉我弄错了,Freertos 欺骗了我,因为当我抛出一些东西时它会在 DefaultISR 中停止。

throw 确实跳转到 __cxa_throw 然后从那里跳转到 ___Unwind_RaiseException __gnu_Unwind_RaiseException __cxa_begin_catch> <_zst9terminatev> 所以看起来 std::terminate 被调用了,但是 catch all 块不应该允许这样做。或者我的假设是错误的,这种行为是因为 gcc C++ 运行时异常支持是一个总是调用终止的存根?!

2016-09 更新:因为我看到 rand() 尝试使用 malloc(),所以我还定义了一个有效的 malloc()/freeRTOS 函数,等等:__cxa_allocate_exception 使用 malloc(我想知道工具链希望我如何处理 bad_alloc 案例)。 所以现在,它仍然崩溃,但是在异常分配之后(我认为): 执行路径为:

(throwing function after exception allocation)
__cxa_throw
   ...                        //(some intructions in __cxa_throw)
   __cxa_begin_catch  //I guess something went wrong here
    _ZSt9terminatev // Immediately after __cxa_begin_catch
        _ZN10__cxxabiv111__terminateEPFvvE:
         00016dfc: push r3, lr
         00016dfe: blx r0  //Goes directly to WDOG_EWM_IRQHandler or hard fault handler
         00016e00: bl 0x194ac <abort>

如果您想知道或者它可能会有所帮助:如果我没有定义 hard_fault 处理程序和自己的默认处理程序,我的调试器会说它是我崩溃的 WDOG_EWM_IRQHandler。

所以我猜堆栈展开时出了点问题,因为我在 _throw 中通过了一些名称中带有“完成的堆栈展开”的符号,但我没有捕捉到我在对象的析构函数中设置的断点应该已经清理干净了。这似乎促使 __cxa_begin_catch 调用 abort 之类的。

( Kinetis Design Studio 3.2.0. 与 GNU ARM C/C++ 交叉编译器 版本:1.12.1.201502281154 对于我们的 FRDM-KV31F)

【问题讨论】:

恕我直言,对于嵌入式设备,c++ 异常机制有点复杂。 FreeRTOS 也使用 SVC 中断,所以如果你这样做,你必须知道你做了什么来避免破坏 FreeRTOS 你说的是C++异常还是ARM内核异常? 我不知道 gcc 期望从那里调用什么,但是您必须在 FreeRTOS 上方插入自己的 SVC_Handler 以检查它为什么到达那里。 SVC 接受一个以 R0 IIRC 结尾的参数,而 FreeRTOS 默认调用 SVC #0,因此根据 gcc 为 SVC 参数插入的内容,您可能能够区分来源。不过,它会阻止您担心的 RTOS 中断。 我所能看到的只是 IAR EWARM 是如何处理它的,它在不使用处理器异常的情况下处理它。你能发布一个 MCVE 的反汇编吗? 您是否设置了看门狗并对其进行了适当的维护?我也遇到了放入错误向量的问题,因此如果您放入的向量没有意义,请仔细检查您的向量表上的对齐方式是否正确。 【参考方案1】:

在使用 freescales Kinetis 和 asking the same problem on the nxp community 成功创建一个空白项目后,NXP 工程师(假设是 NXP 徽章)告诉我答案:

By default new projects link to newlib-nano which has it exception support disabled.

The libstdc++ built along with newlib-nano have exception handling disabled.

所以解决方案是简单地链接到 newlib。这可以通过简单地删除“其他链接器标志”中的“-specs=nano.specs”行来完成,并确保添加相同选项的复选框也被禁用。 然后一切都按预期进行。只有代码在 ROM/文本大小中增加了 27 kB,在 RAM/数据中增加了 2kB。

【讨论】:

【参考方案2】:

由于故障,您的大多数异常都会执行默认处理程序,因此您需要做的第一件事是确定实际执行的是哪个异常。您可以在以下页面上查看“确定正在执行的异常处理程序”部分:http://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html

我猜,因为您没有在代码中使用外围设备,所以它将是一个故障处理程序,可能是硬故障。同一页面(见上面的链接)也提供了调试说明。

除此之外 - 确保您执行正常的 FreeRTOS 调试工作,例如确保您已定义 configASSERT() 并且您已启用堆栈溢出检查。有关这些主题的信息可在此页面上找到:http://www.freertos.org/FAQHelp.html

【讨论】:

这是硬故障,因为它在我定义自己的 HardFault_Handler 后抛出后停在那里。我目前最大的问题是:C++ 异常处理是否应该开箱即用,使用 freeRTOS 还是没有操作系统?!我之所以问,是因为这是我投入的一个棕色领域项目,如果你说“是的,它应该可以工作,所以它看起来像错误的中断管理”,我知道去哪里找。 @Superlokkus 它应该在有或没有 freeRTOS 的情况下工作。我认为如果您遇到硬故障,可能是因为您没有捕获异常......或者某个地方的指针错误 谢谢@Garf365 !!【参考方案3】:

从 RTOS 方面来看,C++ 异常只是一种美化的跳跃。只要它们从您的代码中跳转到另一个,它们就不会干扰 RTOS。所以你可以写一个try catch(std::exception)

没有 C++ 处理程序时,RTOS 确实必须在你的 C++ 代码停止运行时介入。

【讨论】:

你永远不会进入 catch 部分,因为此时,无论何时抛出 C++ 异常,无论是否被捕获,都会调用 arm 硬件异常,但默认情况下会处理它excpetion 处理程序,这意味着 CPU 只是停止,它实际上是这样做的。 @Superlokkus:你有这个说法的来源吗?由于 AFAICT,GCC 遵循 ARM 上的 Itanium ABI,并且使用硬件异常。 处理器异常!= C++ 异常。这就是我之前问的原因。 这是一个页面,其中包含@MSalters 提到的有关 Itanium ABI 的一些信息:wiki.osdev.org/C++_Exception_Support @Superlokkus 您发布的链接只是处理器异常模型,而不是 gcc 未使用 Itanium ABI 处理异常的来源。发布一些反汇编,显示您的 throw 语句导致 svc 指令,如果不是,请向我们展示它的结果。

以上是关于带有freertos的gnu arm cortex m4上的C ++异常处理程序的主要内容,如果未能解决你的问题,请参考以下文章

ARM汇编基础

学习FreeRTOS:初始化阶段的中断状态

ARM裸机开发篇1:Cortex-A7开发环境搭建

ARM汇编基础详解

FreeRTO之Cortex-M中断管理

arm各种交叉编译工具的区别