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

C++ exception handler on gnu arm cortex m4 with freertos

更新 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 并且在 catch 处理程序中的 try 或(当添加了一些代码时)代码不会被执行。

组装可以在这里找到: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>

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

所以我猜堆栈展开时出了点问题,因为我在 _throw 中遍历了一些名称中带有 "finished stack unwinding" 的符号,但我没有捕捉到我在析构函数中设置的断点应该清理的对象。这似乎促使 __cxa_begin_catch 调用 abort 或其他东西。

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

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

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

由于错误,您的大部分异常将执行默认处理程序,因此您需要做的第一件事是确定实际执行的是哪个异常。您可以在以下页面上看到 "Determining Which Exception Handler is Executing" 部分:http://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html

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

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

在飞思卡尔 Kinetis 中使用默认设置成功创建空白项目后,asking the same problem on the nxp community、Alice_Yang 一位 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.

所以解决办法就是link干脆newlib。这可以通过简单地删除 "other linker flags" 中的“-specs=nano.specs”行并确保添加相同选项的复选框也被禁用来完成。 然后一切都按预期运行。 只有代码在 ROM/text 大小中增加了 27 kB,在 RAM/data 中增加了 2kB。