Программирование ARM ESP-IDF: диагностика не восстановимых ошибок Thu, April 18 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

ESP-IDF: диагностика не восстановимых ошибок Печать
Добавил(а) microsin   

В определенных ситуациях программа не может корректно продолжать выполнение. В среде разработки ESP-IDF такие ситуации включают:

· CPU Exceptions (исключения процессора):

- Недопустимая инструкция (Illegal Instruction).
- Ошибка выравнивания при доступе (Load/Store Alignment Error).
- Ошибка при запрещенном доступе (Load/Store Prohibited error).

· Проверки системного уровня (system level checks) и защитные механизмы (safeguards):

- Прерывание сторожевого таймера (interrupt watchdog timeout).
- Таймаут сторожевого таймера задачи (task watchdog timeout, эта ошибка фатальна только если установлена опция CONFIG_ESP_TASK_WDT_PANIC is set).
- Ошибка доступа кэша (cache access error).
- Срабатывание защиты памяти (memory protection fault).
- Событие сбоя по питанию (brownout detection event).
- Переполнение стека (stack overflow).
- Проверка защиты от разрушения стека (stack smashing protection check).
- Проверка целостности кучи (heap integrity check).
- Срабатывание детектора неопределенного поведения (undefined behavior sanitizer, UBSAN).
- Срабатывание assert, configASSERT и подобных макросов.

В этом руководстве показаны процедуры (перевод документации [1]), используемые в среде разработки ESP-IDF для обработки этих ошибок, и предоставлены рекомендации по решению проблем с такими ошибками.

[Panic Handler]

Каждая из перечисленных выше ошибок будет обработана кодом panic handler. Его выполнение начинается с печати в консоль UART причины ошибки. Для CPU exceptions сообщение будет примерно таким:

Guru Meditation Error: Core 0 panic'ed (Illegal instruction). Exception was unhandled.

Для некоторых system level checks (interrupt watchdog, cache access error), сообщение может быть наподобие следующего:

Guru Meditation Error: Core 0 panic'ed (Cache error). Exception was unhandled.

Во всех случаях причина ошибки будет выведена в скобках. Список таких возможных ошибок см. далее в разделе "Guru Meditation Errors".

Последующее поведение panic handler может быть установлено выбором опции конфигурации CONFIG_ESP_SYSTEM_PANIC. Доступны следующие варианты этой опции:

· Напечатать регистры и перезагрузиться (CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT) - значение по умолчанию. Будут выведены значения регистров в точке срабатывания исключения, напечатается обратная трассировка выполнения (backtrace) и произойдет рестарт чипа.
· Напечатать регистры и остановиться (CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT). Работает подобно предыдущему варианту опции, но произойдет halt вместо reboot. Для перезапуска программы понадобится внешний сброс.
· Тихая перезагрузка, silent reboot (CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT). Не печатать регистры или backtrace, не медленно перезагрузить чип.
· Вызов отладчика, Invoke GDB Stub (CONFIG_ESP_SYSTEM_PANIC_GDBSTUB). Запустит сервер GDB, который может обмениваться с отладчиком GDB через порт консоли UART. Этот вариант опции предоставляет отладку только для чтения, read-only debugging или post-mortem debugging. Подробности см. далее в разделе "GDB Stub".
· Вызов dynamic GDB Stub (ESP_SYSTEM_GDBSTUB_RUNTIME). Также запустит сервер GDB, который может обмениваться с отладчиком GDB через порт консоли UART. Эта опция позволяет отлаживать программу run time и устанавливать breakpoint-ы после выполнения, и т. п., см. далее раздел "GDB Stub".

Также на поведение panic handler влияют и другие опции конфигурации.

· Если разрешена опция CONFIG_ESP_DEBUG_OCDAWARE (что установлено по умолчанию), то panic handler будет обнаруживать подключенный отладчик JTAG. Если отладчик JTAG подключен, выполнение приостанавливается (halted), и управление передается отладчику. В этом случае регистры и backtrace не печатаются в консоль, и функции GDBStub / Core Dump не используются.

· Если фича Core Dump разрешена, то состояние системы (стеки задач и регистры) будут выведены либо во Flash, либо в UART, для последующего анализа.

· Если опция CONFIG_ESP_PANIC_HANDLER_IRAM запрещена (она запрещена по умолчанию), то код panic handler размещается в памяти flash, а не в IRAM. Это означает, что если программа ESP-IDF крашится, когда кэш flash запрещен, то panic handler автоматически заново разрешит кэширование flash перед запуском GDB Stub или Core Dump. Это добавит некоторый риск, что статус кэша flash также поврежден во время падения программы.

Если опция CONFIG_ESP_PANIC_HANDLER_IRAM разрешена, то код panic handler (включая требуемые функции UART) помещены в IRAM, что как следствие уменьшает количество доступной для использования оперативной памяти. Однако это может оказаться полезным для отладки некоторых сложных проблем, связанных с временным запретом кэша flash (например, при записи в SPI flash), или когда кэш flash поврежден при срабатывании исключения.

· Если опция CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS разрешена (она запрещена по умолчанию) и установлена в значение больше 0, то panic handler задержит перезагрузку на указанное количество секунд. Это может помочь, если инструментарий,  используемый для мониторинга последовательного вывода, не предоставляет возможности остановить и проанализировать вывод. После указанной задержки произойдет reboot устройства, reset reason сохраняется.

Следующая диаграмма иллюстрирует поведение panic handler:

ESP IDF Panic Handler flowchart fig01

[Дамп регистров и Backtrace]

Если только не разрешена опция CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT, код panic handler напечатает в консоль значения некоторых регистров CPU (register dump) и обратную трассировку вызовов (backtrace):

Core  0 register dump:
MEPC    : 0x420048b4  RA      : 0x420048b4  SP      : 0x3fc8f2f0  GP      : 0x3fc8a600
TP      : 0x3fc8a2ac  T0      : 0x40057fa6  T1      : 0x0000000f  T2      : 0x00000000
S0/FP   : 0x00000000  S1      : 0x00000000  A0      : 0x00000001  A1      : 0x00000001
A2      : 0x00000064  A3      : 0x00000004  A4      : 0x00000001  A5      : 0x00000000
A6      : 0x42001fd6  A7      : 0x00000000  S2      : 0x00000000  S3      : 0x00000000
S4      : 0x00000000  S5      : 0x00000000  S6      : 0x00000000  S7      : 0x00000000
S8      : 0x00000000  S9      : 0x00000000  S10     : 0x00000000  S11     : 0x00000000
T3      : 0x00000000  T4      : 0x00000000  T5      : 0x00000000  T6      : 0x00000000
MSTATUS : 0x00001881  MTVEC   : 0x40380001  MCAUSE  : 0x00000007  MTVAL   : 0x00000000
MHARTID : 0x00000000

Печатаемые значения регистров захвачены в момент исключения (exception frame), т. е. когда произошла ошибка CPU exception или другая фатальная ошибка.

Дамп регистров не печатается, если был выполнен panic handler как результат вызова abort().

Если используется IDF Monitor (команда idf.py monitor [2]), то Program Counter будет преобразован в понятное место кода (имя функции, имя файла и номер строки), и вывод будет с дополнительными строками:

Core  0 register dump:
MEPC    : 0x420048b4  RA      : 0x420048b4  SP      : 0x3fc8f2f0  GP      : 0x3fc8a600
0x420048b4: app_main at /Users/user/esp/example/main/hello_world_main.c:20
 
0x420048b4: app_main at /Users/user/esp/example/main/hello_world_main.c:20
 
TP      : 0x3fc8a2ac  T0      : 0x40057fa6  T1      : 0x0000000f  T2      : 0x00000000
S0/FP   : 0x00000000  S1      : 0x00000000  A0      : 0x00000001  A1      : 0x00000001
A2      : 0x00000064  A3      : 0x00000004  A4      : 0x00000001  A5      : 0x00000000
A6      : 0x42001fd6  A7      : 0x00000000  S2      : 0x00000000  S3      : 0x00000000
0x42001fd6: uart_write at /Users/user/esp/esp-idf/components/vfs/vfs_uart.c:201
 
S4      : 0x00000000  S5      : 0x00000000  S6      : 0x00000000  S7      : 0x00000000
S8      : 0x00000000  S9      : 0x00000000  S10     : 0x00000000  S11     : 0x00000000
T3      : 0x00000000  T4      : 0x00000000  T5      : 0x00000000  T6      : 0x00000000
MSTATUS : 0x00001881  MTVEC   : 0x40380001  MCAUSE  : 0x00000007  MTVAL   : 0x00000000
MHARTID : 0x00000000

Кроме того, IDF Monitor также может генерировать и печатать обратную трассировку вызовов (backtrace) благодаря содержимому дампа стека (stack dump), предоставленного платой в panic handler. Этот вывод может выглядеть следующим образом:

Backtrace:
 
0x42006686 in bar (ptr=ptr@entry=0x0) at ../main/hello_world_main.c:18
18          *ptr = 0x42424242;
#0  0x42006686 in bar (ptr=ptr@entry=0x0) at ../main/hello_world_main.c:18
#1  0x42006692 in foo () at ../main/hello_world_main.c:22
#2  0x420066ac in app_main () at ../main/hello_world_main.c:28
#3  0x42015ece in main_task (args=< optimized out>) at /Users/user/esp/components/freertos/port/port_common.c:142
#4  0x403859b8 in vPortEnterCritical () at /Users/user/esp/components/freertos/port/riscv/port.c:130
#5  0x00000000 in ?? ()
Backtrace stopped: frame did not save the PC

Хотя показанная выше трассировка очень полезна, она требует использования IDF Monitor. Чтобы генерировать и печатать backtrace при использовании другой программы монитора (например putty), можно активировать в menuconfig опцию CONFIG_ESP_SYSTEM_USE_EH_FRAME.

Эта опция позволит компилятору генерировать DWARF-информацию для каждой функции проекта. Тогда, когда произойдет CPU exception, код panic handler будет парсить эти данные и определять backtrace задачи (task), в которой произошел сбой. Вывод выглядит примерно так:

Backtrace: 0x42009e9a:0x3fc92120 0x42009ea6:0x3fc92120 0x42009ec2:0x3fc92130 0x42024620:0x3fc92150
 0x40387d7c:0x3fc92160 0xfffffffe:0x3fc92170

Здесь выведены пары PC:SP, представляющие PC (Program Counter) и SP (Stack Pointer) для каждого stack frame текущей задачи.

Основное достоинство опции CONFIG_ESP_SYSTEM_USE_EH_FRAME в том, что backtrace генерируется самой платой (без необходимости применения IDF Monitor). Однако недостаток опции в том, что она увеличит размер скомпилированного бинарника (от 20% до 100%). Кроме того, эта опция приведет к подключению отладочной информации в скомпилированный бинарник. Поэтому при выпуске конечного продукта следует запретить эту опцию в сборке.

Чтобы найти место, где произошла фатальная ошибка, просмотрите строки после "Backtrace". Место фатальной ошибки будет в верхней строке, и последующие строки покажут стек истории вызовов (call stack).

[GDB Stub]

Если разрешена опция CONFIG_ESP_SYSTEM_PANIC_GDBSTUB, то panic handler не будет сбрасывать чип при возникновении фатальной ошибки. Вместо этого будет запущен сервер сетевого протокола отладки (GDB remote protocol server), который принято называть GDB Stub. Когда это произошло, экземпляр GDB, работающий на компьютере хоста отладки, может быть инструктирован для подключения к порту UART чипа ESP32-C3.

Если используется IDF Monitor, то GDB запустится автоматически, когда в выводе UART обнаружится приглашение отладчика (GDB Stub prompt). Этот вывод выглядит следующим образом:

Entering gdb stub now.
$T0b#e6GNU gdb (crosstool-NG crosstool-ng-1.22.0-80-gff1f415) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later < http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-build_apple-darwin16.3.0 --target=riscv32-esp-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
< http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
< http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /Users/user/esp/example/build/example.elf...done.
Remote debugging using /dev/cu.usbserial-31301
0x400e1b41 in app_main ()
    at /Users/user/esp/example/main/main.cpp:36
36      *((int*) 0) = 0;
(gdb)

GDB prompt может использоваться для инспекции регистров CPU, локальных и статических переменных, а также произвольных областей памяти. Здесь нельзя установить точки останова (breakpoint), менять PC или продолжить выполнение. Чтобы сбросить программу выйдите из GDB и выполните внешний сброс: клавишами Ctrl+T Ctrl+R в IDF Monitor [2], или внешней кнопкой на отлаживаемой плате (подачей импульса лог. 0 на вывод CHIP_EN, вывод 7 корпуса чипа ESP32-C3).

[RTC Watchdog Timeout]

Сторожевой таймер RTC (RTC watchdog) используется в коде startup для запуска отслеживания допустимого времени выполнения кода, что также помогает избавиться от зависаний, вызванных нестабильным питанием. Эта фича разрешена по умолчанию (см. CONFIG_BOOTLOADER_WDT_ENABLE). Если превышено допустимое время выполнения какого-либо участка кода (задается опцией CONFIG_BOOTLOADER_WDT_TIME_MS), то RTC watchdog перезапустит систему. В этом случае ROM bootloader напечатает сообщение, указывающее на перезагрузку из-за таймаута сторожевого таймера RTC (RTC Watchdog Timeout reason).

rst:0x10 (RTCWDT_RTC_RST)

RTC watchdog отслеживает время выполнения кода загрузчика первой стадии (first stage bootloader или ROM bootloader) до момента запуска приложения (application startup). Это изначально установлено в ROM bootloader, затем конфигурируется в bootloader опцией CONFIG_BOOTLOADER_WDT_TIME_MS (по умолчанию 9000 мс). Во время стадии инициализации приложения это переконфигурируется, потому что может поменяться источник низкой частоты тактирования (source slow clock), и в конце запрещено сразу перед вызовом app_main(). Здесь имеется опция CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE, которая предотвращает запрет RTC watchdog перед входом в app_main. Вместо этого RTC watchdog остается активным, и должен быть периодически обнуляться в коде вашего приложения.

[Guru Meditation Errors]

В этой секции объясняется смысл различных случаев ошибок, печатаемых в круглых скобках сообщения паники "Guru Meditation Error".

Примечание: см. статью Википедии [3], объясняющую происхождение странного термина "Guru Meditation".

Illegal instruction. Это исключение процессора (CPU exception) показывает, что была выполнена недопустимая инструкция. Основные причины этой ошибки следующие:

· Произошел возврат из функции задачи FreeRTOS (task function). Во FreeRTOS, если функция задачи должна быть завершена, она должна вызвать vTaskDelete(NULL) и удалить саму себя вместо выхода из тела функции задачи.

· Сбой чтения следующей инструкции из SPI flash. Это обычно происходит, если:

- Приложение переконфигурировало ножки SPI flash для другой функции (GPIO, UART, и т. д.). Проконсультируйтесь с рекомендациями по разработке (Hardware Design Guidelines) и даташитом на используемый микроконтроллер или его модуль для получения подробного описания выводов для подключения чипов SPI flash.
- К выводам SPI flash случайно подключилось внешнее устройство и повлияло на процесс обмена между ESP32-C3 и SPI flash.

· В коде C++, если произошел выход из non-void функции без возврата значения, то это считается неопределенным поведением программы (undefined behavior). Когда в программе разрешены оптимизации, компилятор будет часто опускать эпилог в таких функциях. Чаще всего это является причиной исключения "Illegal instruction". По умолчанию система сборки ESP-IDF разрешает -Werror=return-type, что означает, что опущенные операторы return обрабатываются как ошибка компиляции. Однако если проект приложения запрещает предупреждения компилятора, то эта проблема не будет обнаружена, и во время выполнения кода произойдет Illegal instruction exception.

Важное замечание по поводу vTaskDelete(NULL): этот вызов применяется для того, чтобы задача могла удалить саму себя, и он обязательно должен стоять в конце тела функции задачи. Если это условие не выполнить, то состояние задачи навсегда останется eRunning и не перейдет в состояние eDeleted.

Instruction address misaligned. Это CPU exception показывает, что адрес инструкции для выполнения не выровнен на 2 байта (байтовый адрес инструкции не делится нацело на 2).

Instruction access fault, Load access fault, Store access fault. Это CPU exception происходит, когда приложение пытается выполнить, прочитать или записать недопустимый регион памяти. Адрес, который был записан или прочитан, находится в регистре MTVAL дампа регистров сообщения паники. Если этот адрес 0, то это обычно означает, попытку приложения обратиться по нулевому адресу (dereference NULL pointer). Если такой адрес близок к 0, то это обычно означает, что приложение пытается обратиться к полу структуры, но указатель на структуру был при этом NULL. Если адрес какой-то другой (имеет мусорное значение, не находится в диапазоне 0x3fxxxxxx .. 0x6xxxxxxx), то это обычно означает, что используется указатель для доступа к не инициализированным данным или поврежденным данным.

Breakpoint. Это CPU exception происходит при выполнении инструкции EBREAK.

Load address misaligned, Store address misaligned. Приложение попыталось прочитать или записать область памяти, и выравнивание адреса не соответствует с размером загрузки/сохранения (load/store). Например, 32-разрядная load может быть выполнена только по адресу, выровненному на 4 байта, а 16-битная load может осуществляться только по выровненному на 2 байта адресу.

Interrupt Watchdog Timeout on CPU0/CPU1. Показывает, что произошло прерывание таймаута сторожевого таймера (interrupt watchdog timeout). Для дополнительной информации см. документацию [4].

Cache error. В некоторых ситуациях библиотеки ESP-IDF будут временно запрещать доступ через кэш к внешней SPI Flash и SPI RAM. Например это произойдет, когда используется API-функция spi_flash для операций с регионами SPI Flash (read/write/erase/mmap). В этих ситуациях задачи приостанавливаются, и запрещаются обработчики прерываний, которые не зарегистрированы с флагом ESP_INTR_FLAG_IRAM. Убедитесь, что любые обработчики прерывания, зарегистрированные с этим флагом, полностью размещают свой код и свои данные в IRAM/DRAM (и не вызывают при этом внешние функции, которые находятся в памяти SPI). За подробностями обратитесь к разделу "IRAM-Safe Interrupt Handlers" врезки "Конкурентные ограничения для FLASH на SPI1" документации SPI flash API [6].

Memory protection fault. Фича управления разрешениями на регионы памяти (ESP32-C3 Permission Control) используется в ESP-IDF для защиты от следующих типов доступа к памяти:

· Запись в память инструкций (IRAM) после того, как программа была загружена и запущена.
· Выполнение кода из памяти данных (DRAM), т. е. из областей для кучи, секций статических данных .data и .bss.

Подобные операции для большинства программ не требуются. Запрет таких операций обычно делает приложения устойчивее к эксплуатации уязвимостей с целью взлома. Приложения, где требуется динамическая загрузка кода или самомодификация кода, могут запретить это с помощью Kconfig-опции CONFIG_ESP_SYSTEM_MEMPROT_FEATURE.

Когда произошла ошибка защиты памяти, код panic handler сообщит об этом типе отказа и о типе доступа к памяти, который привел к ошибке.

[Другие фатальные ошибки Fatal Errors]

Brownout. В чип ESP32-C3 встроена аппаратура определения провала напряжения питания (brownout detector), который по умолчанию разрешен. Этот brownout detector может вызвать системный сброс, если напряжение питания снизилось ниже безопасного уровня. Brownout detector может быть сконфигурирован опциями CONFIG_ESP_BROWNOUT_DET и CONFIG_ESP_BROWNOUT_DET_LVL_SEL.

Когда сработал brownout detector, в лог будет напечатано следующее сообщение:

Brownout detector was triggered

После печати этого сообщения произойдет сброс чипа.

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

Corrupt Heap. Реализация кучи в ESP-IDF содержит несколько run-time проверок структуры кучи. Опциями menuconfig можно разрешить дополнительные проверки ("Heap Poisoning"). Если одна из этих проверок не прошла, то будет напечатано примерно такое сообщение:

CORRUPT HEAP: Bad tail at 0x3ffe270a. Expected 0xbaad5678 got 0xbaac5678
assertion "head != NULL" failed: file "/Users/user/esp/esp-idf/components/heap/multi_heap_poisoning.c",
 line 201, function: multi_heap_free
abort() was called at PC 0x400dca43 on core 0

Для дополнительной информации по отладке проблем с кучей см. документацию [7].

Stack Smashing. Может быть разрешена защита от разрушения стека stack smashing (она основана на флагах -fstack-protector* компилятора GCC), если в ESP-IDF используется опция CONFIG_COMPILER_STACK_CHECK_MODE. Если определено stack smashing, то будет напечатано сообщение наподобие следующего:

Stack smashing protect failure!
 
abort() was called at PC 0x400d2138 on core 0
 
Backtrace: 0x4008e6c0:0x3ffc1780 0x4008e8b7:0x3ffc17a0 0x400d2138:0x3ffc17c0 0x400e79d5:0x3ffc17e0
 0x400e79a7:0x3ffc1840 0x400e79df:0x3ffc18a0 0x400e2235:0x3ffc18c0 0x400e1916:0x3ffc18f0
 0x400e19cd:0x3ffc1910 0x400e1a11:0x3ffc1930 0x400e1bb2:0x3ffc1950 0x400d2c44:0x3ffc1a80
0

Адреса backtrace должны указать на функцию, где произошло разрушение стека (stack smashing). Проверьте работу кода на предмет не ограниченного доступа к локальным массивам.

[Проверки "Undefined Behavior Sanitizer (UBSAN)"]

Undefined behavior sanitizer (UBSAN) это фича компилятора, которая добавляет в код run-time проверки на потенциально некорректные операции, такие как:

· Переполнения (multiplication overflow, signed integer overflow).
· Ошибки сдвига или экспоненты (shift base or exponent errors), например сдвиг больше чем на 32 разряда.
· Ошибки преобразования целых чисел.

Полный список поддерживаемых проверок опции -fsanitize=undefined см. в документации GCC.

Разрешение UBSAN. Фича UBSAN по умолчанию запрещена. Её можно разрешить на уровне файла, компонента или проекта целиком путем добавления в систему сборки опции компилятора -fsanitize=undefined.

Когда разрешена фича UBSAN для кода, который используется заголовочные файлы регистров аппаратуры SOC (soc/xxx_reg.h), рекомендуется запретить shift-base sanitizer с помощью опции -fno-sanitize=shift-base. Это связано с тем, что файлы заголовков регистров ESP-IDF в настоящее время содержат шаблоны, которые приводят к ложным срабатываниям для этой конкретной sanitizer-опции.

Для разрешения UBSAN на уровне проекта добавьте следующий код в конец файла CMakeLists.txt проекта:

idf_build_set_property(COMPILE_OPTIONS "-fsanitize=undefined" "-fno-sanitize=shift-base" APPEND)

Альтернативно передавайте эти опции через переменные окружения EXTRA_CFLAGS и EXTRA_CXXFLAGS.

Добавление UBSAN приведет к значительному увеличению размера кода и данных. Большинство приложений, за исключением тривиальных, не будут укладываться в ограниченный объем доступной RAM микроконтроллера, когда UBSAN разрешена для всего приложения целиком. Поэтому рекомендуется вместо этого разрешать UBSAN только для отдельных тестируемых компонентов.

Чтобы разрешить UBSAN для определенного компонента (component_name) из файла CMakeLists.txt проекта, добавьте в конец этого файла следующий код:

idf_component_get_property(lib component_name COMPONENT_LIB)
target_compile_options(${lib} PRIVATE "-fsanitize=undefined" "-fno-sanitize=shift-base")

Для дополнительной информации см. врезку "idf-build-properties" в разделе "API системы сборки ESP-IDF]" документации по системе сборки и свойствам компонента [5].

Чтобы разрешить UBSAN для определенного компонента (component_name) из CMakeLists.txt того же компонента, добавьте в конец этого файла следующий код:

target_compile_options(${COMPONENT_LIB} PRIVATE "-fsanitize=undefined" "-fno-sanitize=shift-base")

UBSAN Output. Когда UBSAN обнаружил ошибку, напечатается соответствующее сообщение и backtrace, например:

Undefined behavior of type out_of_bounds
 
Backtrace:0x4008b383:0x3ffcd8b0 0x4008c791:0x3ffcd8d0 0x4008c587:0x3ffcd8f0 0x4008c6be:0x3ffcd950
 0x400db74f:0x3ffcd970 0x400db99c:0x3ffcd9a0

Когда используется IDF Monitor, текст backtrace будет декодирован в имена функций и место в исходном коде, указывая не место возникшей проблемы (в следующем примере это main.c:, строка 128):

0x4008b383: panic_abort at /path/to/esp-idf/components/esp_system/panic.c:367
0x4008c791: esp_system_abort at /path/to/esp-idf/components/esp_system/system_api.c:106
0x4008c587: __ubsan_default_handler at /path/to/esp-idf/components/esp_system/ubsan.c:152
0x4008c6be: __ubsan_handle_out_of_bounds at /path/to/esp-idf/components/esp_system/ubsan.c:223
0x400db74f: test_ub at main.c:128
0x400db99c: app_main at main.c:56 (discriminator 1)

Типы ошибок, о которых сообщает UBSAN, могут быть следующими:

Имя Описание
type_mismatch, type_mismatch_v1 Некорректное значение указателя: null, unaligned, не совместимый с имеющимся типом.
add_overflow, sub_overflow, mul_overflow, negate_overflow Целочисленное переполнение в операциях добавления (addition), вычитания (subtraction), умножения (multiplication), смены знака (отрицание, negation).
divrem_overflow Переполнение при делении на 0 или INT_MIN.
shift_out_of_bounds Переполнение в левой или правой части операторов сдвига.
out_of_bounds Доступ вне границ массива.
unreachable Выполнен недостижимый код.
missing_return Функция non-void дошла до своего завершения без возвращаемого значения (относится только к C++).
vla_bound_not_positive Размер массива переменной длины не является положительным.
load_invalid_value Недопустимое значение переменной bool или enum (относится только к C++), т. е. значение вышло за ожидаемые пределы.
nonnull_arg Null-аргумент был передан в функцию, которая была декларирована с атрибутом nonnull.
nonnull_return Возвращено значение Null из функции, которая была декларирована с атрибутом returns_nonnull.
builtin_unreachable Была вызвана функция __builtin_unreachable.
pointer_overflow Переполнение в арифметике указателей.

[Ссылки]

1. ESP-IDF Fatal Errors site:docs.espressif.com.
2. ESP-IDF Monitor site:docs.espressif.com.
3. Guru Meditation site:wikipedia.org.
4. ESP-IDF Watchdogs site:docs.espressif.com.
5. ESP-IDF Build System.
6. ESP32-C3: выделение прерывания.
7. ESP-IDF Heap Memory Debugging site:docs.espressif.com.

 

Добавить комментарий


Защитный код
Обновить

Top of Page