在某些情况下,程序的执行,没有按照定义的方式持续执行.在 ESP-IDF 中,这些情况包括:
CONFIG_TASK_WDT_PANIC
,则仅 fatal)assert
,configASSERT
和类似的宏.本指南介绍了 ESP-IDF 中用于处理这些错误的过程,并提供了有关错误故障排除的建议.
概述中列出的每个错误原因都将由 Panic 处理程序处理.
Panic 处理程序将首先将错误原因打印到控制台. 对于 CPU 异常,消息类似于:
Guru Meditation Error: Core 0 panic'ed (IllegalInstruction). Exception was unhandled.
对于某些系统级别检查(中断监视程序,缓存访问错误),该消息将类似于:
Guru Meditation Error: Core 0 panic'ed (Cache disabled but cached memory region accessed)
在所有情况下,错误原因将打印在括号中. 有关可能的错误原因列表,请参阅 Guru Meditation Errors.
可以使用 CONFIG_ESP32_PANIC
配置选项设置 Panic 处理程序的后续行为. 可用选项包括:
打印寄存器并重新启动(CONFIG_ESP32_PANIC_PRINT_REBOOT
) - 默认选项.
这将在异常点打印寄存器值,打印回溯,然后重新启动芯片.
打印寄存器并暂停(CONFIG_ESP32_PANIC_PRINT_HALT
)
与上述选项类似,但暂停而不是重新启动. 重启程序需要外部重置.
无提示重启(CONFIG_ESP32_PANIC_SILENT_REBOOT
)
不要打印寄存器或回溯,立即重启芯片.
调用 GDB 存根(CONFIG_ESP32_PANIC_GDBSTUB
)
启动 GDB 服务器,它可以通过控制台 UART 端口与 GDB 通信. 有关详细信息,请参阅 GDB 存根.
Panic 处理程序的行为受另外两个配置选项的影响.
CONFIG_ESP32_DEBUG_OCDAWARE
(这是默认设置),则 Panic 处理程序将检测 JTAG 调试器是否已连接. 如果是,则执行将暂停,控制权将传递给调试器. 在这种情况下,寄存器和回溯不会转储到控制台,并且不使用 GDBStub/Core Dump 功能.CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH
或 CONFIG_ESP32_ENABLE_COREDUMP_TO_UART
选项),则系统状态(任务堆栈和寄存器)将被转储到 Flash 或 UART,以供以后分析.下图说明了 Panic 处理程序的行为:
除非启用了 CONFIG_ESP32_PANIC_SILENT_REBOOT
选项,否则 Panic 处理程序会将一些 CPU 寄存器和回溯打印到控制台:
Core 0 register dump:PC : 0x400e14ed PS : 0x00060030 A0 : 0x800d0805 A1 : 0x3ffb5030A2 : 0x00000000 A3 : 0x00000001 A4 : 0x00000001 A5 : 0x3ffb50dcA6 : 0x00000000 A7 : 0x00000001 A8 : 0x00000000 A9 : 0x3ffb5000A10 : 0x00000000 A11 : 0x3ffb2bac A12 : 0x40082d1c A13 : 0x06ff1ff8A14 : 0x3ffb7078 A15 : 0x00000000 SAR : 0x00000014 EXCCAUSE: 0x0000001dEXCVADDR: 0x00000000 LBEG : 0x4000c46c LEND : 0x4000c477 LCOUNT : 0xffffffffBacktrace: 0x400e14ed:0x3ffb5030 0x400d0802:0x3ffb5050
打印的寄存器值是异常帧中的寄存器值,即 CPU 异常或其他严重错误发生时的值.
如果由于 abort()
调用而执行了 Panic 处理程序,则不会打印寄存器转储.
在某些情况下,例如中断看门狗超时, Panic 处理程序可能会打印额外的 CPU 寄存器 (EPC1-EPC4) 以及在另一个 CPU 上运行的代码的寄存器/回溯.
Backtrace 行包含 PC:SP 对,其中 PC 是程序计数器,SP 是堆栈指针,用于当前任务的每个堆栈帧. 如果在 ISR 内发生严重错误,则回溯可能包括来自被中断的任务和来自 ISR 的 PC:SP 对.
如果使用 IDF Monitor,程序计数器值将转换为代码位置(函数名称,文件名和行号),输出将与其他行进行注释:
Core 0 register dump:PC : 0x400e14ed PS : 0x00060030 A0 : 0x800d0805 A1 : 0x3ffb50300x400e14ed: app_main at /Users/user/esp/example/main/main.cpp:36A2 : 0x00000000 A3 : 0x00000001 A4 : 0x00000001 A5 : 0x3ffb50dcA6 : 0x00000000 A7 : 0x00000001 A8 : 0x00000000 A9 : 0x3ffb5000A10 : 0x00000000 A11 : 0x3ffb2bac A12 : 0x40082d1c A13 : 0x06ff1ff80x40082d1c: _calloc_r at /Users/user/esp/esp-idf/components/newlib/syscalls.c:51A14 : 0x3ffb7078 A15 : 0x00000000 SAR : 0x00000014 EXCCAUSE: 0x0000001dEXCVADDR: 0x00000000 LBEG : 0x4000c46c LEND : 0x4000c477 LCOUNT : 0xffffffffBacktrace: 0x400e14ed:0x3ffb5030 0x400d0802:0x3ffb50500x400e14ed: app_main at /Users/user/esp/example/main/main.cpp:360x400d0802: main_task at /Users/user/esp/esp-idf/components/esp32/cpu_start.c:470
要查找发生严重错误的位置,请查看“Backtrace”的下一行. 严重错误位置是顶行,后续行显示调用堆栈.
如果启用了 CONFIG_ESP32_PANIC_GDBSTUB
选项,则发生严重错误时, Panic 处理程序不会重置芯片. 相反,它将启动 GDB 远程协议服务器,通常称为 GDB Stub. 发生这种情况时,可以指示主机上运行的 GDB 实例连接到 ESP32 UART 端口.
如果使用 IDF Monitor,则在 UART 上检测到 GDB Stub 提示时会自动启动 GDB. 输出看起来像这样:
Entering gdb stub now.$T0b#e6GNU gdb (crosstool-NG crosstool-ng-1.22.0-80-gff1f415) 7.10Copyright (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=xtensa-esp32-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-313010x400e1b41 in app_main () at /Users/user/esp/example/main/main.cpp:3636 *((int*) 0) = 0;(gdb)
GDB 提示可用于检查 CPU 寄存器,本地和静态变量以及内存中的任意位置. 无法设置断点,更改 PC 或继续执行. 要重置程序,请退出 GDB 并执行外部重置:IDF Monitor 中的 Ctrl-T Ctrl-R
,或使用开发板上的外部重置按钮.
本节解释了不同错误原因的含义,打印在 Guru Meditation Error:Core panic'ed message
之后的括号中.
有关“Guru Meditation”的历史渊源,请参阅 Wikipedia 文章.
该 CPU 异常表示执行的指令不是有效指令. 此错误的最常见原因有:
此 CPU 异常表示 CPU 无法加载指令,因为指令的地址不属于指令 RAM 或 ROM 中的有效区域.
通常这意味着尝试调用函数指针,该指针不指向有效代码. PC (程序计数器)寄存器可用作指示器:它将为零或将包含垃圾值(不是 0x4xxxxxxx).
当应用程序尝试读取或写入无效的内存位置时,会发生此 CPU 异常. 写入/读取的地址可在寄存器转储中的 EXCVADDR
寄存器中找到. 如果此地址为零,则通常表示应用程序尝试取消引用 NULL 指针. 如果此地址接近于零,则通常意味着应用程序尝试访问结构的成员,但指向该结构的指针为 NULL. 如果该地址是别的(垃圾值,不在 0x3fxxxxxx
- 0x6xxxxxxx
范围内),则可能意味着用于访问数据的指针未初始化或已损坏.
应用程序尝试将整数除以零.
应用程序尝试读取或写入内存位置,并且地址对齐与加载/存储大小不匹配. 例如,32 位加载只能从 4 字节对齐的地址完成,而 16 位加载只能从 2 字节的对齐地址完成.
应用程序尝试从仅支持 32 位加载/存储的内存区域进行 8 位或 16 位加载/存储. 例如,取消引用指向内存存储器的 char *
指针将导致这样的错误.
通常会出现以下消息:
Debug exception reason: Stack canary watchpoint triggered (task_name)
此错误表示应用程序已写入 task_name
任务堆栈的末尾. 请注意,并非每个堆栈溢出都可以保证触发此错误. 任务可能会在堆栈 canary
位置之外写入堆栈,在这种情况下,不会触发观察点.
表示发生了中断看门狗超时. 有关详细信息,请参阅看门狗.
在某些情况下,ESP-IDF 将暂时禁止通过高速缓存访问外部 SPI Flash 和 SPI RAM. 例如,spi_flash API 用于读取/写入/擦除/mmap SPI Flash 区域. 在这些情况下,任务被挂起,并且未注册 ESP_INTR_FLAG_IRAM
的中断处理程序被禁用. 确保使用此标志注册的任何中断处理程序都具有 IRAM/DRAM 中的所有代码和数据. 有关更多详细信息,请参阅 SPI Flash API 文档.
ESP32 有一个内置的掉电检测器,默认启用. 如果电源电压低于安全水平,掉电检测器可以触发系统复位. 可以使用 CONFIG_BROWNOUT_DET
和 CONFIG_BROWNOUT_DET_LVL_SEL
选项配置掉电检测器. 当掉电检测器触发时,将打印以下消息:
Brownout detector was triggered
打印消息后,芯片将复位.
请注意,如果电源电压快速下降,则控制台上只能看到部分消息.
ESP-IDF 堆实现包含许多堆结构的运行时检查. 可以在 menuconfig 中启用其他检查(“Heap Stisoning”). 如果其中一项检查失败,将打印类似于以下内容的消息:
CORRUPT HEAP: Bad tail at 0x3ffe270a. Expected 0xbaad5678 got 0xbaac5678assertion "head != NULL" failed: file "/Users/user/esp/esp-idf/components/heap/multi_heap_poisoning.c", line 201, function: multi_heap_freeabort() was called at PC 0x400dca43 on core 0
有关详细信息,请参阅堆内存调试文档.
可以使用 CONFIG_STACK_CHECK_MODE
选项在 ESP-IDF 中启用 Stack Smashing 保护(基于 GCC -fstack-protector *
标志). 如果检测到 Stack Smashing,将打印类似于以下内容的消息:
Stack smashing protect failure!abort() was called at PC 0x400d2138 on core 0Backtrace: 0x4008e6c0:0x3ffc1780 0x4008e8b7:0x3ffc17a0 0x400d2138:0x3ffc17c0 0x400e79d5:0x3ffc17e0 0x400e79a7:0x3ffc1840 0x400e79df:0x3ffc18a0 0x400e2235:0x3ffc18c0 0x400e1916:0x3ffc18f0 0x400e19cd:0x3ffc1910 0x400e1a11:0x3ffc1930 0x400e1bb2:0x3ffc1950 0x400d2c44:0x3ffc1a800
回溯应该指向 Stack Smashing 发生的函数. 检查功能代码以获得对本地阵列的无限制访问.
联系客服