Обработка во встроенных системах

В встроенном программном обеспечении, как вы обрабатываете переполнение стека общим способом? Я сталкиваюсь с некоторыми процессорами, которые защищают аппаратным способом, как недавние процессоры AMD. Есть некоторые методы в Википедии, но являются ли они реальными практическими подходами?

Может ли кто-нибудь дать понятный предложенный подход, который работает во всех случаях на сегодняшних 32-битных встроенных процессорах?

Ответ 1

В идеале вы пишете свой код со статическим использованием стека (без рекурсивных вызовов). Затем вы можете оценить максимальное использование стека:

  • статический анализ (с использованием инструментов)
  • измерение использования стека при запуске вашего кода с полным охватом кода (или как можно более высокий охват кода до тех пор, пока у вас не будет достаточной уверенности, что вы указали степень использования стека, если ваш редко используемый код не используйте больше стека, чем обычные пути выполнения)

Но даже при этом вы все равно хотите иметь обнаружение, а затем обработку, если это произойдет, если это вообще возможно, для большей надежности. Это может быть особенно полезно на этапе разработки проекта. Некоторые методы для обнаружения:

  • Если процессор поддерживает прерывание чтения/записи памяти (то есть прерывание прерывания доступа к памяти), он может быть настроен так, чтобы указывать на наиболее удаленную область области стека.
  • В конфигурации карты памяти настройте небольшой (или большой) блок ОЗУ, который является областью защиты стека. Заполните его известными значениями. Во встроенном программном обеспечении регулярно (как можно чаще) проверяйте содержимое этой области. Если он когда-либо изменится, предположите переполнение стека.

Как только вы его обнаружите, вам нужно обработать. Я не знаю многих способов, из-за которых код может изящно восстанавливаться из, потому что как только это произошло, ваша программная логика почти наверняка недействительна. Итак, все, что вы можете сделать, это

  • запишите ошибку
    • Запись ошибки очень полезна, поскольку в противном случае симптомы (неожиданные перезагрузки) могут быть очень трудными для диагностики.
    • Предостережение. Процедура ведения журнала должна быть надежной, даже в сценарии с поврежденным стеком. Процедура должна быть простой. То есть с поврежденным стеком, вы, вероятно, не можете попытаться записать в EEPROM, используя вашу фантастическую задачу EEPROM. Возможно, просто зарегистрируйте ошибку в структуре, которая зарезервирована для этой цели, в неинтеральной ОЗУ, которая затем может быть проверена после перезагрузки.
  • Перезагрузка (или, возможно, остановка, особенно если ошибка повторяется повторно)
    • Возможная альтернатива: перезапустите только конкретную задачу, если вы используете RTOS, и ваша система спроектирована таким образом, что повреждение стека изолировано, и все остальные задачи могут обрабатывать эту перезагрузку. Это потребует серьезного рассмотрения.

Ответ 2

В то время как встроенное переполнение стека может быть вызвано из-за того, что рекурсивные функции выходят из-под контроля, это также может быть вызвано использованием ошибочного указателя (хотя это может считаться другим типом ошибки) и нормальной работой системы с нижним стеком. Другими словами, если вы не профилируете использование стека, это может произойти за пределами дефекта или ситуации с ошибкой.

Прежде чем вы сможете "обработать" переполнение стека, вам нужно его идентифицировать. Хорошим способом для этого является загрузка стека с шаблоном во время инициализации, а затем мониторинг того, какая часть шаблона исчезает во время выполнения. Таким образом, вы можете определить самую высокую точку, к которой достиг стек.

Алгоритм проверки шаблона должен выполняться в противоположном направлении роста стека. Таким образом, если стек растет от 0x1000 до 0x2000, то проверка вашего шаблона может начинаться с 0x2000 для повышения эффективности. Если ваш шаблон равен 0xAA, а значение в 0x2000 содержит что-то отличное от 0xAA, вы знаете, что у вас, вероятно, есть переполнение.

Вы также должны рассмотреть возможность размещения пустого RAM-буфера сразу после стека, чтобы, если вы обнаруживаете переполнение, вы можете отключить систему, не теряя данные. Если за вашим стеком немедленно следуют данные кучи или SRAM, то определение переполнения означает, что вы уже понесли коррупцию. Ваш буфер будет защищать вас немного дольше. На 32-битном микроресурсе у вас должно быть достаточно ОЗУ для обеспечения хотя бы небольшого буфера.

Ответ 3

Переполнение стека происходит, когда стек стека исчерпан слишком большим количеством стека вызовов? например рекурсивная функция слишком много уровней.

Существуют методы обнаружения путем размещения известных данных после стека, чтобы он мог быть обнаружен, если стек слишком сильно вырос и перезаписал его.

Существуют инструменты для анализа статического исходного кода, такие как GnatStack, StackAnalyzer от AbsInt и Bound-T, которые могут использоваться для определения или получения предположения в максимальном размере стека во время выполнения.

Ответ 4

Если вы используете процессор с блоком управления памятью, ваше оборудование может сделать это для вас с минимальными накладными расходами на программное обеспечение. Большинство современных 32-битных процессоров имеют их, и все больше и больше 32-битных микроконтроллеров также используют их.

Настройте область памяти в MMU, которая будет использоваться для стека. Он должен быть ограничен двумя областями памяти, где MMU не разрешает доступ. Когда приложение будет запущено, вы получите исключение/прерывание, как только вы переполните стек.

Поскольку вы получаете исключение в момент возникновения ошибки, вы точно знаете, где в вашем приложении стек пошел плохо. Вы можете посмотреть стек вызовов, чтобы точно узнать, как вы добрались до своего места. Это значительно облегчает поиск вашей проблемы, чем пытаться выяснить, что не так, обнаружив вашу проблему задолго до того, как это произошло.

Я успешно использовал это для процессоров PPC и AVR32. Когда вы начинаете использовать MMU, вы чувствуете, что это пустая трата времени, так как вы отлично справлялись с этим в течение многих лет, но как только вы увидите преимущества исключения в точном месте, где возникает ваша проблема с памятью, вы никогда не вернетесь. MMU также может обнаруживать образы нулевого указателя, если вы запретите доступ к памяти в нижнем парке вашего бара.

Если вы используете RTOS, ваш MMU защищает память и стеки других задач, ошибки в одной задаче не должны влиять на них. Это означает, что вы также можете легко перезапустить свою задачу, не затрагивая другие задачи.

В дополнение к этому у процессора с MMU обычно также много ловушек, ваша программа намного реже переполняет ваш стек, и вам не нужно точно настраивать все, чтобы вы могли нормально работать с небольшой памятью foot print.

Альтернативой этому было бы использование средств отладки Процессора, чтобы вызвать прерывание доступа к памяти в конец вашего стека. Это, вероятно, будет очень специфичным для процессора.