C ++ обработчик исключений на GNU Arm Cortex M4 с freertos

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


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

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

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

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

Я предположил, что это приводит к прерыванию SVC, извините, что я ошибся, Freertos обманул меня, потому что, когда я что-то выбрасываю, он останавливается в DefaultISR.

Индекс бросков прыгает к __cxa_throw затем оттуда к ___Unwind_RaiseException __gnu_Unwind_RaiseException __cxa_begin_catch>
<_ZSt9terminatev>

Так выглядит std::terminate называется, но блок catch all не должен допустить этого. Или мое предположение неверно, и это происходит потому, что поддержка исключений среды выполнения gcc C ++ является заглушкой, которая всегда вызывает terminate ?!

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

(Студия дизайна Kinetis 3.2.0. С
Кросс-компилятор GNU ARM C / C ++
Версия: 1.12.1.201502281154
за наших
FRDM-KV31F)

11

Решение

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

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

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

8

Другие решения

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

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

7

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

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

В libstdc ++, собранном вместе с newlib-nano, обработка исключений отключена.

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

1