Обработчик исключений С++ на gnu arm cortex m4 с freertos

Обновление 2016-12 В настоящее время также существует минимальный пример такого поведения: https://community.nxp.com/message/862676


Я использую ARM Cortex M4 с freertos, используя свободу свободного времени. Kinetis IDE (gnu arm toolchain). Проблема в том, что

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

приводит к остановке CPU и кода после попытки или (когда некоторые добавлены) в обработчике catch не выполняется.

И сборку можно найти здесь: https://gist.github.com/Superlokkus/3c4201893b4c51e154e2a0afdf78fef0

Я ПРИНИМАЮ, что это приводит к прерыванию SVC, извините, что я ошибался, Freertos обманул меня в этом, потому что, когда я бросаю что-то, это останавливается в DefaultISR.

Бросок действительно переходит на __ cxa_throw, а затем оттуда до ___Unwind_RaiseException __gnu_Unwind_RaiseException __cxa_begin_catch >  < _ZSt9terminatev > Таким образом, похоже, что вызывается std::terminate, но блокировка catch не должна этого допускать. Или мое предположение неверно, и это поведение объясняется тем, что поддержка исключений во время выполнения gcc С++ - это заглушка, которая всегда вызывает завершение?!

Обновление 2016-09. Поскольку я видел, что rand() пытается использовать malloc(), я также определил рабочую функцию malloc()/freeRTOS и et voilà: __cxa_allocate_exception использует malloc (мне интересно как toolchain ожидает, что я обработать случай 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, но я не нашел точку прерывания, которую я установил в деструкторе объекта, который должны были быть очищены. И это, по-видимому, мотивирует __cxa_begin_catch на вызов прерывания или что-то в этом роде.

(Kinetis Design Studio 3.2.0. с Перекрестный компилятор GNU ARM C/С++ Версия: 1.12.1.201502281154 для нашего FRDM-KV31F)

Ответ 1

После успешного создания пустого проекта с настройками по умолчанию в freescales Kinetis и задавая ту же проблему в сообществе nxp, Alice_Yang, NXP инженер (предполагая значок NXP), сказал мне ответ:

По умолчанию новые проекты ссылаются на newlib-nano, у которого отключена поддержка исключения.

У libstdС++, созданного вместе с newlib-nano, отключена обработка исключений.

Таким образом, решение заключается в том, чтобы просто ссылаться на newlib. Это можно сделать, просто удалив строку "-specs = nano.specs" в "других флагах компоновщика" , а также убедитесь, что флажок, который добавляет ту же опцию, также отключен. Затем все работает так, как ожидалось. Только код увеличился на 27 кБ в ROM/текстовом размере и 2 КБ в ОЗУ/данных. введите описание изображения здесь

Ответ 2

По ошибке большинство ваших исключений будут выполнять обработчик по умолчанию, поэтому первое, что вам нужно сделать, это определить, какое исключение фактически выполняется. Вы можете увидеть раздел "Определение того, какой обработчик исключений выполняется" на следующей странице: http://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html

Я бы предположил, что, поскольку вы не используете периферийное устройство в своем коде, это будет обработчик ошибок, возможно, жесткий отказ. На этой же странице (см. Ссылку выше) также содержатся инструкции по ее отладке.

Кроме этого - убедитесь, что вы выполняете обычные функции отладки FreeRTOS, например, убедитесь, что у вас есть configASSERT(), и что у вас есть проверка. Информация по этим темам находится на этой странице: http://www.freertos.org/FAQHelp.html

Ответ 3

С точки зрения RTOS, исключения С++ - это просто прославленный прыжок. Пока они перескакивают с одного бита вашего кода на другой, они не мешают RTOS. Поэтому вы можете написать try { } catch(std::exception) { }.

Когда нет обработчика С++, RTOS действительно должен будет войти, поскольку ваш код на С++ перестает работать.