1严重错误
2========
3:link_to_translation:`en:[English]`
4
5.. _Overview:
6
7概述
8----
9
10在某些情况下,程序并不会按照我们的预期运行,在 ESP-IDF 中,这些情况包括:
11
12- CPU 异常:|CPU_EXCEPTIONS_LIST|
13- 系统级检查错误:
14
15  - :doc:`中断看门狗 <../api-reference/system/wdts>` 超时
16  - :doc:`任务看门狗 <../api-reference/system/wdts>` 超时(只有开启 :ref:`CONFIG_ESP_TASK_WDT_PANIC` 后才会触发严重错误)
17  - 高速缓存访问错误
18  - 掉电检测事件
19  - 堆栈溢出
20  - Stack 粉碎保护检查
21  - Heap 完整性检查
22  - 未定义行为清理器(UBSAN)检查
23
24- 使用 ``assert``、``configASSERT`` 等类似的宏断言失败。
25
26本指南会介绍 ESP-IDF 中这类错误的处理流程,并给出对应的解决建议。
27
28紧急处理程序
29------------
30
31:ref:`Overview` 中列举的所有错误都会由 *紧急处理程序(Panic Handler)* 负责处理。
32
33紧急处理程序首先会将出错原因打印到控制台,例如 CPU 异常的错误信息通常会类似于
34
35.. parsed-literal::
36
37    Guru Meditation Error: Core 0 panic'ed (|ILLEGAL_INSTR_MSG|). Exception was unhandled.
38
39对于一些系统级检查错误(如中断看门狗超时,高速缓存访问错误等),错误信息会类似于
40
41.. parsed-literal::
42
43    Guru Meditation Error: Core 0 panic'ed (|CACHE_ERR_MSG|). Exception was unhandled.
44
45不管哪种情况,错误原因都会被打印在括号中。请参阅 :ref:`Guru-Meditation-Errors` 以查看所有可能的出错原因。
46
47紧急处理程序接下来的行为将取决于 :ref:`CONFIG_ESP_SYSTEM_PANIC` 的设置,支持的选项包括:
48
49- 打印 CPU 寄存器,然后重启(``CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT``)- 默认选项
50
51  打印系统发生异常时 CPU 寄存器的值,打印回溯,最后重启芯片。
52
53- 打印 CPU 寄存器,然后暂停(``CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT``)
54
55  与上一个选项类似,但不会重启,而是选择暂停程序的运行。重启程序需要外部执行复位操作。
56
57- 静默重启(``CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT``)
58
59  不打印 CPU 寄存器的值,也不打印回溯,立即重启芯片。
60
61- 调用 GDB Stub(``CONFIG_ESP_SYSTEM_PANIC_GDBSTUB``)
62
63  启动 GDB 服务器,通过控制台 UART 接口与 GDB 进行通信。详细信息请参阅 :ref:`GDB-Stub`。
64
65紧急处理程序的行为还受到另外两个配置项的影响:
66
67- 如果使能了 :ref:`CONFIG_{IDF_TARGET_CFG_PREFIX}_DEBUG_OCDAWARE` (默认),紧急处理程序会检测 {IDF_TARGET_NAME} 是否已经连接 JTAG 调试器。如果检测成功,程序会暂停运行,并将控制权交给调试器。在这种情况下,寄存器和回溯不会被打印到控制台,并且也不会使用 GDB Stub 和 Core Dump 的功能。
68
69- 如果使能了 :doc:`内核转储 <core_dump>` 功能,系统状态(任务堆栈和寄存器)会被转储到 Flash 或者 UART 以供后续分析。
70
71- 如果 :ref:`CONFIG_ESP_PANIC_HANDLER_IRAM` 被禁用(默认情况下禁用),紧急处理程序的代码会放置在 Flash 而不是 IRAM 中。这意味着,如果 ESP-IDF 在 Flash 高速缓存禁用时崩溃,在运行 GDB Stub 和内核转储之前紧急处理程序会自动重新使能 Flash 高速缓存。如果 Flash 高速缓存也崩溃了,这样做会增加一些小风险。
72
73  如果使能了该选项,紧急处理程序的代码(包括所需的 UART 函数)会放置在 IRAM 中。当禁用 Flash 高速缓存(如写入 SPI flash)时或触发异常导致 Flash 高速缓存崩溃时,可用此选项调试一些复杂的崩溃问题。
74
75下图展示了紧急处理程序的行为:
76
77.. blockdiag::
78    :scale: 100%
79    :caption: 紧急处理程序流程图(点击放大)
80    :align: center
81
82    blockdiag panic-handler {
83        orientation = portrait;
84        edge_layout = flowchart;
85        default_group_color = white;
86        node_width = 160;
87        node_height = 60;
88
89        cpu_exception [label = "CPU 异常", shape=roundedbox];
90        sys_check [label = "Cache 错误,\nInterrupt WDT,\nabort()", shape=roundedbox];
91        check_ocd [label = "JTAG 调试器\n已连接?", shape=diamond, height=80];
92        print_error_cause [label = "打印出错原因"];
93        use_jtag [label = "发送信号给 JTAG 调试器", shape=roundedbox];
94        dump_registers [label = "打印寄存器\n和回溯"];
95        check_coredump [label = "Core dump\n使能?", shape=diamond, height=80];
96        do_coredump [label = "Core dump 至 UART 或者 Flash"];
97        check_gdbstub [label = "GDB Stub\n使能?", shape=diamond, height=80];
98        do_gdbstub [label = "启动 GDB Stub", shape=roundedbox];
99        halt [label = "暂停", shape=roundedbox];
100        reboot [label = "重启", shape=roundedbox];
101        check_halt [label = "暂停?", shape=diamond, height=80];
102
103        group {cpu_exception, sys_check};
104
105        cpu_exception -> print_error_cause;
106        sys_check -> print_error_cause;
107        print_error_cause -> check_ocd;
108        check_ocd -> use_jtag [label = "Yes"];
109        check_ocd -> dump_registers [label = "No"];
110        dump_registers -> check_coredump
111        check_coredump -> do_coredump [label = "Yes"];
112        do_coredump -> check_gdbstub;
113        check_coredump -> check_gdbstub [label = "No"];
114        check_gdbstub -> check_halt [label = "No"];
115        check_gdbstub -> do_gdbstub [label = "Yes"];
116        check_halt -> halt [label = "Yes"];
117        check_halt -> reboot [label = "No"];
118    }
119
120寄存器转储与回溯
121----------------
122
123除非启用了 ``CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT`` 否则紧急处理程序会将 CPU 寄存器和回溯打印到控制台
124
125.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
126
127    ::
128
129        Core 0 register dump:
130        PC      : 0x400e14ed  PS      : 0x00060030  A0      : 0x800d0805  A1      : 0x3ffb5030
131        A2      : 0x00000000  A3      : 0x00000001  A4      : 0x00000001  A5      : 0x3ffb50dc
132        A6      : 0x00000000  A7      : 0x00000001  A8      : 0x00000000  A9      : 0x3ffb5000
133        A10     : 0x00000000  A11     : 0x3ffb2bac  A12     : 0x40082d1c  A13     : 0x06ff1ff8
134        A14     : 0x3ffb7078  A15     : 0x00000000  SAR     : 0x00000014  EXCCAUSE: 0x0000001d
135        EXCVADDR: 0x00000000  LBEG    : 0x4000c46c  LEND    : 0x4000c477  LCOUNT  : 0xffffffff
136
137        Backtrace: 0x400e14ed:0x3ffb5030 0x400d0802:0x3ffb5050
138
139.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
140
141    ::
142
143        Core  0 register dump:
144        MEPC    : 0x420048b4  RA      : 0x420048b4  SP      : 0x3fc8f2f0  GP      : 0x3fc8a600
145        TP      : 0x3fc8a2ac  T0      : 0x40057fa6  T1      : 0x0000000f  T2      : 0x00000000
146        S0/FP   : 0x00000000  S1      : 0x00000000  A0      : 0x00000001  A1      : 0x00000001
147        A2      : 0x00000064  A3      : 0x00000004  A4      : 0x00000001  A5      : 0x00000000
148        A6      : 0x42001fd6  A7      : 0x00000000  S2      : 0x00000000  S3      : 0x00000000
149        S4      : 0x00000000  S5      : 0x00000000  S6      : 0x00000000  S7      : 0x00000000
150        S8      : 0x00000000  S9      : 0x00000000  S10     : 0x00000000  S11     : 0x00000000
151        T3      : 0x00000000  T4      : 0x00000000  T5      : 0x00000000  T6      : 0x00000000
152        MSTATUS : 0x00001881  MTVEC   : 0x40380001  MCAUSE  : 0x00000007  MTVAL   : 0x00000000
153        MHARTID : 0x00000000
154
155仅会打印异常帧中 CPU 寄存器的值,即引发 CPU 异常或者其它严重错误时刻的值。
156
157紧急处理程序如果是因 abort() 而调用,则不会打印寄存器转储。
158
159.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
160
161    在某些情况下,例如中断看门狗超时,紧急处理程序会额外打印 CPU 寄存器(EPC1-EPC4)的值,以及另一个 CPU 的寄存器值和代码回溯。
162
163    回溯行包含了当前任务中每个堆栈帧的 PC:SP 对(PC 是程序计数器,SP 是堆栈指针)。如果在 ISR 中发生了严重错误,回溯会同时包括被中断任务的 PC:SP 对,以及 ISR 中的 PC:SP 对。
164
165如果使用了 :doc:`IDF 监视器 <tools/idf-monitor>`,该工具会将程序计数器的值转换为对应的代码位置(函数名,文件名,行号),并加以注释
166
167.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
168
169    ::
170
171        Core 0 register dump:
172        PC      : 0x400e14ed  PS      : 0x00060030  A0      : 0x800d0805  A1      : 0x3ffb5030
173        0x400e14ed: app_main at /Users/user/esp/example/main/main.cpp:36
174
175        A2      : 0x00000000  A3      : 0x00000001  A4      : 0x00000001  A5      : 0x3ffb50dc
176        A6      : 0x00000000  A7      : 0x00000001  A8      : 0x00000000  A9      : 0x3ffb5000
177        A10     : 0x00000000  A11     : 0x3ffb2bac  A12     : 0x40082d1c  A13     : 0x06ff1ff8
178        0x40082d1c: _calloc_r at /Users/user/esp/esp-idf/components/newlib/syscalls.c:51
179
180        A14     : 0x3ffb7078  A15     : 0x00000000  SAR     : 0x00000014  EXCCAUSE: 0x0000001d
181        EXCVADDR: 0x00000000  LBEG    : 0x4000c46c  LEND    : 0x4000c477  LCOUNT  : 0xffffffff
182
183        Backtrace: 0x400e14ed:0x3ffb5030 0x400d0802:0x3ffb5050
184        0x400e14ed: app_main at /Users/user/esp/example/main/main.cpp:36
185
186        0x400d0802: main_task at /Users/user/esp/esp-idf/components/{IDF_TARGET_PATH_NAME}/cpu_start.c:470
187
188.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
189
190    ::
191
192        Core  0 register dump:
193        MEPC    : 0x420048b4  RA      : 0x420048b4  SP      : 0x3fc8f2f0  GP      : 0x3fc8a600
194        0x420048b4: app_main at /Users/user/esp/example/main/hello_world_main.c:20
195
196        0x420048b4: app_main at /Users/user/esp/example/main/hello_world_main.c:20
197
198        TP      : 0x3fc8a2ac  T0      : 0x40057fa6  T1      : 0x0000000f  T2      : 0x00000000
199        S0/FP   : 0x00000000  S1      : 0x00000000  A0      : 0x00000001  A1      : 0x00000001
200        A2      : 0x00000064  A3      : 0x00000004  A4      : 0x00000001  A5      : 0x00000000
201        A6      : 0x42001fd6  A7      : 0x00000000  S2      : 0x00000000  S3      : 0x00000000
202        0x42001fd6: uart_write at /Users/user/esp/esp-idf/components/vfs/vfs_uart.c:201
203
204        S4      : 0x00000000  S5      : 0x00000000  S6      : 0x00000000  S7      : 0x00000000
205        S8      : 0x00000000  S9      : 0x00000000  S10     : 0x00000000  S11     : 0x00000000
206        T3      : 0x00000000  T4      : 0x00000000  T5      : 0x00000000  T6      : 0x00000000
207        MSTATUS : 0x00001881  MTVEC   : 0x40380001  MCAUSE  : 0x00000007  MTVAL   : 0x00000000
208        MHARTID : 0x00000000
209
210    此外,由于紧急处理程序中提供了堆栈转储,因此 :doc:`IDF 监视器 <tools/idf-monitor>` 也可以生成并打印回溯。
211    输出结果如下:
212
213    ::
214
215        Backtrace:
216
217        0x42006686 in bar (ptr=ptr@entry=0x0) at ../main/hello_world_main.c:18
218        18	    *ptr = 0x42424242;
219        #0  0x42006686 in bar (ptr=ptr@entry=0x0) at ../main/hello_world_main.c:18
220        #1  0x42006692 in foo () at ../main/hello_world_main.c:22
221        #2  0x420066ac in app_main () at ../main/hello_world_main.c:28
222        #3  0x42015ece in main_task (args=<optimized out>) at /Users/user/esp/components/freertos/port/port_common.c:142
223        #4  0x403859b8 in vPortEnterCritical () at /Users/user/esp/components/freertos/port/riscv/port.c:130
224        #5  0x00000000 in ?? ()
225        Backtrace stopped: frame did not save the PC
226
227    虽然以上的回溯信息非常方便,但要求用户使用 :doc:`IDF 监视器 <tools/idf-monitor>`。因此,如果用户希望使用其它的串口监控软件也能显示堆栈回溯信息,则需要在 menuconfig 中启用 :ref:`CONFIG_ESP_SYSTEM_USE_EH_FRAME` 选项。
228
229    该选项会让编译器为项目的每个函数生成 DWARF 信息。然后,当 CPU 异常发生时,紧急处理程序将解析这些数据并生成出错任务的堆栈回溯信息。输出结果如下:
230
231    ::
232
233        Backtrace: 0x42009e9a:0x3fc92120 0x42009ea6:0x3fc92120 0x42009ec2:0x3fc92130 0x42024620:0x3fc92150 0x40387d7c:0x3fc92160 0xfffffffe:0x3fc92170
234
235    这些 ``PC:SP`` 对代表当前任务每一个栈帧的程序计数器值(Program Counter)和栈顶地址(Stack Pointer)。
236
237
238    :ref:`CONFIG_ESP_SYSTEM_USE_EH_FRAME` 选项的主要优点是,回溯信息可以由程序自己解析生成并打印 (而不依靠 :doc:`IDF 监视器 <tools/idf-monitor>`)。但是该选项会导致编译后的二进制文件更大(增幅可达 20% 甚至 100%)。此外,该选项会将调试信息也保存在二进制文件里。因此,强烈不建议用户在量产/生产版本中启用该选项。
239
240若要查找发生严重错误的代码位置,请查看 "Backtrace" 的后面几行,发生严重错误的代码显示在顶行,后续几行显示的是调用堆栈。
241
242.. _GDB-Stub:
243
244GDB Stub
245--------
246
247如果启用了 ``CONFIG_ESP_SYSTEM_PANIC_GDBSTUB`` 选项,在发生严重错误时,紧急处理程序不会复位芯片,相反,它将启动 GDB 远程协议服务器,通常称为 GDB Stub。发生这种情况时,可以让主机上运行的 GDB 实例通过 UART 端口连接到 ESP32。
248
249如果使用了 :doc:`IDF 监视器 <tools/idf-monitor>`,该工具会在 UART 端口检测到 GDB Stub 提示符后自动启动 GDB,输出会类似于::
250
251    Entering gdb stub now.
252    $T0b#e6GNU gdb (crosstool-NG crosstool-ng-1.22.0-80-gff1f415) 7.10
253    Copyright (C) 2015 Free Software Foundation, Inc.
254    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
255    This is free software: you are free to change and redistribute it.
256    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
257    and "show warranty" for details.
258    This GDB was configured as "--host=x86_64-build_apple-darwin16.3.0 --target={IDF_TARGET_TOOLCHAIN_PREFIX}".
259    Type "show configuration" for configuration details.
260    For bug reporting instructions, please see:
261    <http://www.gnu.org/software/gdb/bugs/>.
262    Find the GDB manual and other documentation resources online at:
263    <http://www.gnu.org/software/gdb/documentation/>.
264    For help, type "help".
265    Type "apropos word" to search for commands related to "word"...
266    Reading symbols from /Users/user/esp/example/build/example.elf...done.
267    Remote debugging using /dev/cu.usbserial-31301
268    0x400e1b41 in app_main ()
269        at /Users/user/esp/example/main/main.cpp:36
270    36      *((int*) 0) = 0;
271    (gdb)
272
273在 GDB 会话中,我们可以检查 CPU 寄存器,本地和静态变量以及内存中任意位置的值。但是不支持设置断点,改变 PC 值或者恢复程序的运行。若要复位程序,请退出 GDB 会话,在 IDF 监视器 中连续输入 Ctrl-T Ctrl-R,或者按下开发板上的复位按键也可以重新运行程序。
274
275.. _Guru-Meditation-Errors:
276
277Guru Meditation 错误
278--------------------
279
280.. Note to editor: titles of the following section need to match exception causes printed by the panic handler. Do not change the titles (insert spaces, reword, etc.) unless panic handler messages are also changed.
281
282.. Note to translator: When translating this section, avoid translating the following section titles. "Guru Meditation" in the title of this section should also not be translated. Keep these two notes when translating.
283
284本节将对打印在 ``Guru Meditation Error: Core panic'ed`` 后面括号中的致错原因进行逐一解释。
285
286.. note:: 想要了解 "Guru Meditation" 的历史渊源,请参阅 `维基百科 <https://en.wikipedia.org/wiki/Guru_Meditation>`_ 。
287
288
289|ILLEGAL_INSTR_MSG|
290^^^^^^^^^^^^^^^^^^^
291
292此 CPU 异常表示当前执行的指令不是有效指令,引起此错误的常见原因包括:
293
294- FreeRTOS 中的任务函数已返回。在 FreeRTOS 中,如果想终止任务函数,需要调用 :cpp:func:`vTaskDelete` 函数释放当前任务的资源,而不是直接返回。
295
296- 无法从 SPI Flash 中加载下一条指令,这通常发生在:
297
298  - 应用程序将 SPI Flash 的引脚重新配置为其它功能(如 GPIO,UART 等等)。有关 SPI Flash 引脚的详细信息,请参阅硬件设计指南和芯片/模组的数据手册。
299
300  - 某些外部设备意外连接到 SPI Flash 的引脚上,干扰了 {IDF_TARGET_NAME} 和 SPI Flash 之间的通信。
301
302.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
303
304    InstrFetchProhibited
305    ^^^^^^^^^^^^^^^^^^^^
306
307    此 CPU 异常表示 CPU 无法加载指令,因为指令的地址不在 IRAM 或者 IROM 中的有效区域中。
308
309    通常这意味着代码中调用了并不指向有效代码块的函数指针。这种情况下,可以查看 ``PC`` (程序计数器)寄存器的值并做进一步判断:若为 0 或者其它非法值(即只要不是 ``0x4xxxxxxx`` 的情况),则证实确实是该原因。
310
311    LoadProhibited, StoreProhibited
312    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
313
314    当应用程序尝试读取或写入无效的内存位置时,会发生此类 CPU 异常。此类无效内存地址可以在寄存器转储的 ``EXCVADDR`` 中找到。如果该地址为零,通常意味着应用程序正尝试解引用一个 NULL 指针。如果该地址接近于零,则通常意味着应用程序尝试访问某个结构体的成员,但是该结构体的指针为 NULL。如果该地址是其它非法值(不在 ``0x3fxxxxxx`` - ``0x6xxxxxxx`` 的范围内),则可能意味着用于访问数据的指针未初始化或者已经损坏。
315
316    IntegerDivideByZero
317    ^^^^^^^^^^^^^^^^^^^
318
319    应用程序尝试将整数除以零。
320
321    LoadStoreAlignment
322    ^^^^^^^^^^^^^^^^^^
323
324    应用程序尝试读取/写入的内存位置不符合加载/存储指令对字节对齐大小的要求,例如,32 位加载指令只能访问 4 字节对齐的内存地址,而 16 位加载指令只能访问 2 字节对齐的内存地址。
325
326    LoadStoreError
327    ^^^^^^^^^^^^^^
328
329    这类异常通常发生于以下几种场合:
330
331    - 应用程序尝试从仅支持 32 位加载/存储的内存区域执行 8 位或 16 位加载/存储操作,例如,解引用一个指向指令内存区域(比如 IRAM 或者 IROM)的 char* 指针就会触发这个错误。
332
333    - 应用程序尝试保存数据到只读的内存区域(比如 IROM 或者 DROM)也会触发这个错误。
334
335    Unhandled debug exception
336    ^^^^^^^^^^^^^^^^^^^^^^^^^
337
338    这后面通常会再跟一条消息::
339
340        Debug exception reason: Stack canary watchpoint triggered (task_name)
341
342    此错误表示应用程序写入的位置越过了 ``task_name`` 任务堆栈的末尾,请注意,并非每次堆栈溢出都会触发此错误。任务有可能会绕过堆栈金丝雀(stack canary)的位置访问堆栈,在这种情况下,监视点就不会被触发。
343
344.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
345
346    Instruction address misaligned
347    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
348
349    此 CPU 异常表示要执行的指令地址非 2 字节对齐。
350
351    Instruction access fault, Load access fault, Store access fault
352    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
353
354    当应用程序尝试读取或写入无效的内存位置时,会发生此类 CPU 异常。此类无效内存地址可以在寄存器转储的 ``MTVAL`` 中找到。如果该地址为零,通常意味着应用程序正尝试解引用一个 NULL 指针。如果该地址接近于零,则通常意味着应用程序尝试访问某个结构体的成员,但是该结构体的指针为 NULL。如果该地址是其它非法值(不在 ``0x3fxxxxxx`` - ``0x6xxxxxxx`` 的范围内),则可能意味着用于访问数据的指针未初始化或者已经损坏。
355
356    Breakpoint
357    ^^^^^^^^^^
358
359    当执行 ``EBREAK`` 指令时,会发生此 CPU 异常。
360
361    Load address misaligned, Store address misaligned
362    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
363
364    应用程序尝试读取/写入的内存位置不符合加载/存储指令对字节对齐大小的要求,例如,32 位加载指令只能访问 4 字节对齐的内存地址,而 16 位加载指令只能访问 2 字节对齐的内存地址。
365
366Interrupt wdt timeout on CPU0 / CPU1
367^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
368
369这表示发生了中断看门狗超时,详细信息请查阅 :doc:`看门狗 <../api-reference/system/wdts>` 文档。
370
371|CACHE_ERR_MSG|
372^^^^^^^^^^^^^^^
373
374在某些情况下,ESP-IDF 会暂时禁止通过高速缓存访问外部 SPI Flash 和 SPI RAM,例如在使用 spi_flash API 读取/写入/擦除/映射 SPI Flash 的时候。在这些情况下,任务会被挂起,并且未使用 ``ESP_INTR_FLAG_IRAM`` 注册的中断处理程序会被禁用。请确保任何使用此标志注册的中断处理程序所访问的代码和数据分别位于 IRAM 和 DRAM 中。更多详细信息请参阅 :ref:`SPI Flash API 文档 <iram-safe-interrupt-handlers>`。
375
376其它严重错误
377------------
378
379欠压
380^^^^
381
382{IDF_TARGET_NAME} 内部集成掉电检测电路,并且会默认启用。如果电源电压低于安全值,掉电检测器可以触发系统复位。掉电检测器可以使用 :ref:`CONFIG_{IDF_TARGET_CFG_PREFIX}_BROWNOUT_DET` 和 :ref:`CONFIG_{IDF_TARGET_CFG_PREFIX}_BROWNOUT_DET_LVL_SEL` 这两个选项进行设置。
383
384当掉电检测器被触发时,会打印如下信息::
385
386    Brownout detector was triggered
387
388芯片会在该打印信息结束后复位。
389
390请注意,如果电源电压快速下降,则只能在控制台上看到部分打印信息。
391
392Heap 不完整
393^^^^^^^^^^^
394
395ESP-IDF 堆的实现包含许多运行时的堆结构检查,可以在 menuconfig 中开启额外的检查(“Heap Poisoning”)。如果其中的某项检查失败,则会打印类似如下信息::
396
397    CORRUPT HEAP: Bad tail at 0x3ffe270a. Expected 0xbaad5678 got 0xbaac5678
398    assertion "head != NULL" failed: file "/Users/user/esp/esp-idf/components/heap/multi_heap_poisoning.c", line 201, function: multi_heap_free
399    abort() was called at PC 0x400dca43 on core 0
400
401更多详细信息,请查阅 :doc:`堆内存调试 <../api-reference/system/heap_debug>` 文档。
402
403Stack 粉碎
404^^^^^^^^^^
405
406Stack 粉碎保护(基于 GCC ``-fstack-protector*`` 标志)可以通过 ESP-IDF 中的 :ref:`CONFIG_COMPILER_STACK_CHECK_MODE` 选项来开启。如果检测到 Stack 粉碎,则会打印类似如下的信息::
407
408    Stack smashing protect failure!
409
410    abort() was called at PC 0x400d2138 on core 0
411
412    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
413    0
414
415回溯信息会指明发生 Stack 粉碎的函数,建议检查函数中是否有代码访问局部数组时发生了越界。
416
417.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
418
419    .. |CPU_EXCEPTIONS_LIST| replace:: 非法指令,加载/存储时的内存对齐错误,加载/存储时的访问权限错误,双重异常。
420    .. |ILLEGAL_INSTR_MSG| replace:: IllegalInstruction
421    .. |CACHE_ERR_MSG| replace:: Cache disabled but cached memory region accessed
422
423.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
424
425    .. |CPU_EXCEPTIONS_LIST| replace:: 非法指令,加载/存储时的内存对齐错误,加载/存储时的访问权限错误。
426    .. |ILLEGAL_INSTR_MSG| replace:: Illegal instruction
427    .. |CACHE_ERR_MSG| replace:: Cache error
428
429未定义行为清理器(UBSAN)检查
430^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
431
432未定义行为清理器 (UBSAN) 是一种编译器功能,它会为可能不正确的操作添加运行时检查,例如:
433
434- 溢出(乘法溢出、有符号整数溢出)
435- 移位基数或指数错误(如移位超过 32 位)
436- 整数转换错误
437
438请参考 `GCC 文档 <https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html>`_ 中的``-fsanitize=undefined`` 选项,查看支持检查的完整列表。
439
440使能 UBSAN
441""""""""""""""
442
443默认情况下未启用 UBSAN。可以通过在构建系统中添加编译器选项 ``-fsanitize=undefined`` 在文件、组件或项目级别上使能 UBSAN。
444
445在对使用硬件寄存器头文件(``soc/xxx_reg.h``)的代码使能 UBSAN 时,建议使用 ``-fno-sanitize=shift-base`` 选项禁用移位基数清理器。这是由于 ESP-IDF 寄存器头文件目前包含的模式会对这个特定的清理器选项造成误报。
446
447要在项目级使能 UBSAN,请在项目 CMakeLists.txt 文件的末尾添加以下内容::
448
449    idf_build_set_property(COMPILE_OPTIONS "-fsanitize=undefined" "-fno-sanitize=shift-base" APPEND)
450
451或者,通过 ``EXTRA_CFLAGS`` 和 ``EXTRA_CXXFLAGS`` 环境变量来传递这些选项。
452
453使能 UBSAN 会明显增加代码量和数据大小。当为整个应用程序使能 UBSAN 时,微控制器的可用 RAM 无法容纳大多数应用程序(除了一些微小程序)。因此,建议为特定的待测组件使能 UBSAN。
454
455要为项目 CMakeLists.txt 文件中的特定组件(``component_name``)启用 UBSAN,请在文件末尾添加以下内容::
456
457    idf_component_get_property(lib component_name COMPONENT_LIB)
458    target_compile_options(${lib} PRIVATE "-fsanitize=undefined" "-fno-sanitize=shift-base")
459
460.. 注意:: 关于 :ref:`构建属性 <cmake-build-properties>` 和 :ref:`组件属性 <cmake-component-properties>` 的更多信息,请查看构建系统文档。
461
462要为同一组件的 CMakeLists.txt 中的特定组件(``component_name``)使能 UBSAN,在文件末尾添加以下内容::
463
464    target_compile_options(${COMPONENT_LIB} PRIVATE "-fsanitize=undefined" "-fno-sanitize=shift-base")
465
466UBSAN 输出
467""""""""""""""""
468
469当 UBSAN 检测到一个错误时,会打印一个信息和回溯,例如::
470
471    Undefined behavior of type out_of_bounds
472
473    Backtrace:0x4008b383:0x3ffcd8b0 0x4008c791:0x3ffcd8d0 0x4008c587:0x3ffcd8f0 0x4008c6be:0x3ffcd950 0x400db74f:0x3ffcd970 0x400db99c:0x3ffcd9a0
474
475当使用 :doc:`IDF 监视器 <tools/idf-monitor>` 时,回溯会被解码为函数名以及源代码位置,并指向问题发生的位置(这里是 ``main.c:128``)::
476
477    0x4008b383: panic_abort at /path/to/esp-idf/components/esp_system/panic.c:367
478
479    0x4008c791: esp_system_abort at /path/to/esp-idf/components/esp_system/system_api.c:106
480
481    0x4008c587: __ubsan_default_handler at /path/to/esp-idf/components/esp_system/ubsan.c:152
482
483    0x4008c6be: __ubsan_handle_out_of_bounds at /path/to/esp-idf/components/esp_system/ubsan.c:223
484
485    0x400db74f: test_ub at main.c:128
486
487    0x400db99c: app_main at main.c:56 (discriminator 1)
488
489UBSAN 报告的错误类型为以下几种:
490
491.. list-table::
492  :widths: 40 60
493  :header-rows: 1
494
495  * - 名称
496    - 含义
497  * - ``type_mismatch``、``type_mismatch_v1``
498    - 指针值不正确:空、未对齐、或与给定类型不兼容
499  * - ``add_overflow``、``sub_overflow``、``mul_overflow``、``negate_overflow``
500    - 加法、减法、乘法、求反过程中的整数溢出
501  * - ``divrem_overflow``
502    - 整数除以 0 或 ``INT_MIN``
503  * - ``shift_out_of_bounds``
504    - 左移或右移运算符导致的溢出
505  * - ``out_of_bounds``
506    - 访问超出数组范围
507  * - ``unreachable``
508    - 执行无法访问的代码
509  * - ``missing_return``
510    - Non-void 函数已结束而没有返回值(仅限 C++)
511  * - ``vla_bound_not_positive``
512    - 可变长度数组的大小不是正数
513  * - ``load_invalid_value``
514    - bool 或 enum(仅 C++)变量的值无效(超出范围)
515  * - ``nonnull_arg``
516    - 对于 ``nonnull`` 属性的函数,传递给函数的参数为空
517  * - ``nonnull_return``
518    - 对于 ``returns_nonnull`` 属性的函数,函数返回值为空
519  * - ``builtin_unreachable``
520    - 调用 ``__builtin_unreachable`` 函数
521  * - ``pointer_overflow``
522    - 指针运算过程中的溢出
523