• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1.. _module-pw_cpu_exception_cortex_m:
2
3=========================
4pw_cpu_exception_cortex_m
5=========================
6This backend provides an implementations for the CPU exception module frontend
7for the following Cortex-M architectures:
8
9* ARMv7-M - Cortex M3
10* ARMv7-EM - Cortex M4, M7
11* ARMv8-M Mainline - Cortex M33, M33P
12
13It also includes a crash facade for a more detailed analysis of the CPU state.
14
15Backend Setup
16=============
17There are a few ways to set up the Cortex M exception handler so the
18application's exception handler is properly called during an exception.
19
201. Use existing CMSIS functions
21-------------------------------
22Inside of CMSIS fault handler functions, branch to ``pw_cpu_exception_Entry``.
23
24.. code-block:: cpp
25
26   __attribute__((naked)) void HardFault_Handler(void) {
27   asm volatile(
28       " ldr r0, =pw_cpu_exception_Entry  \n"
29       " bx r0                            \n");
30   }
31
322. Modify a startup file
33------------------------
34Assembly startup files for some microcontrollers initialize the interrupt
35vector table. The functions to call for fault handlers can be changed here.
36For ARMv7-M and ARMv8-M, the fault handlers are indexes 3 to 6 of the
37interrupt vector table. It's also may be helpful to redirect the NMI handler
38to the entry function (if it's otherwise unused in your project).
39
40Default:
41
42.. code-block:: cpp
43
44   __isr_vector_table:
45     .word  __stack_start
46     .word  Reset_Handler
47     .word  NMI_Handler
48     .word  HardFault_Handler
49     .word  MemManage_Handler
50     .word  BusFault_Handler
51     .word  UsageFault_Handler
52
53Using CPU exception module:
54
55.. code-block:: cpp
56
57   __isr_vector_table:
58     .word  __stack_start
59     .word  Reset_Handler
60     .word  pw_cpu_exception_Entry
61     .word  pw_cpu_exception_Entry
62     .word  pw_cpu_exception_Entry
63     .word  pw_cpu_exception_Entry
64     .word  pw_cpu_exception_Entry
65
66Note: ``__isr_vector_table`` and ``__stack_start`` are example names, and may
67vary by platform. See your platform's assembly startup script.
68
693. Modify interrupt vector table at runtime
70-------------------------------------------
71Some applications may choose to modify their interrupt vector tables at
72runtime. The exception handler works with this use case (see the
73exception_entry_test integration test), but keep in mind that your
74application's exception handler will not be entered if an exception occurs
75before the vector table entries are updated to point to
76``pw_cpu_exception_Entry``.
77
78.. _module-pw_cpu_exception_cortex_m-crash-facade-setup:
79
80Crash Facade Setup
81==================
82The function ``AnalyzeCpuStateAndCrash()`` creates a condensed analysis of the
83CPU state at crash time. It passes the given state along with a format string
84and its arguments to ``PW_CPU_EXCEPTION_CORTEX_M_CRASH()``. The user must
85implement the ``PW_CPU_EXCEPTION_CORTEX_M_HANDLE_CRASH()`` macro and the
86``GetCrashThreadName()`` function, which must returna a null-terminated string
87with the thread name at the time of the crash. The user can choose what to do
88with the format string and arguments in their implementation of
89``PW_CPU_EXCEPTION_CORTEX_M_HANDLE_CRASH()``. For example, the format string and
90arguments can be tokenized to reduce the size of data collected at crash time or
91a string can be composed and reported instead.
92
93The function ``AnalyzeCpuStateAndCrash()`` can be called in the
94``pw_cpu_exception_DefaultHandler()`` directly to delegate the crash handling
95to the user-provided ``PW_CPU_EXCEPTION_CORTEX_M_HANDLE_CRASH()``
96implementation.
97
98Configuration Options
99---------------------
100- ``PW_CPU_EXCEPTION_CORTEX_M_CRASH_EXTENDED_CPU_ANALYSIS``: Enable extended
101  analysis in ``AnalyzeCpuStateAndCrash()`` that collects important register
102  values depending on the fault type.
103
104Module Usage
105============
106For lightweight exception handlers that don't need to access
107architecture-specific registers, using the generic exception handler functions
108is preferred.
109
110However, some projects may need to explicitly access architecture-specific
111registers to attempt to recover from a CPU exception. ``pw_cpu_exception_State``
112provides access to the captured CPU state at the time of the fault. When the
113application-provided ``pw_cpu_exception_DefaultHandler()`` function returns, the
114CPU state is restored. This allows the exception handler to modify the captured
115state so that execution can safely continue.
116
117Expected Behavior
118-----------------
119In most cases, the CPU state captured by the exception handler will contain the
120basic register frame in addition to an extended set of registers
121(see ``cpu_state.h``).
122
123The exception to this is when the program stack pointer is in an MPU-protected
124or otherwise invalid memory region when the CPU attempts to push the exception
125register frame to it. In this situation, the PC, LR, and PSR registers will NOT
126be captured and will be marked with ``0xFFFFFFFF`` to indicate they are invalid.
127This backend will still be able to capture all the other registers though.
128
129``0xFFFFFFFF`` is an illegal LR value, which is why it was selected for this
130purpose. PC and PSR values of 0xFFFFFFFF are dubious too, so this constant is
131clear enough at suggesting that the registers weren't properly captured.
132
133In the situation where the main stack pointer is in a memory protected or
134otherwise invalid region and fails to push CPU context, behavior is undefined.
135
136Nested Exceptions
137-----------------
138To enable nested fault handling:
139
1401. Enable separate detection of usage/bus/memory faults via the SHCSR.
1412. Decrease the priority of the memory, bus, and usage fault handlers. This
142   gives headroom for escalation.
143
144While this allows some faults to nest, it doesn't guarantee all will properly
145nest.
146
147Configuration Options
148=====================
149- ``PW_CPU_EXCEPTION_CORTEX_M_EXTENDED_CFSR_DUMP``: Enable extended logging in
150  ``pw::cpu_exception::LogCpuState()`` that dumps the active CFSR fields with
151  help strings. This is disabled by default since it increases the binary size
152  by >1.5KB when using plain-text logs, or ~460 Bytes when using tokenized
153  logging. It's useful to enable this for device bringup until your application
154  has an end-to-end crash reporting solution.
155- ``PW_CPU_EXCEPTION_CORTEX_M_LOG_LEVEL``: The log level to use for this module.
156  Logs below this level are omitted.
157
158Exception Analysis
159==================
160This module provides Python tooling to analyze CPU state captured by a Cortex-M
161core during an exception. This can be useful as part of a crash report analyzer.
162
163CFSR decoder
164------------
165The ARMv7-M and ARMv8-M architectures have a Configurable Fault Status Register
166(CFSR) that explains what illegal behavior caused a fault. This module provides
167a simple command-line tool to decode CFSR contents (e.g. 0x00010000) as
168human-readable information (e.g. "Encountered invalid instruction").
169
170For example:
171
172.. code-block::
173
174   $ python -m pw_cpu_exception_cortex_m.cfsr_decoder 0x00010100
175   20210412 15:11:14 INF Exception caused by a usage fault, bus fault.
176
177   Active Crash Fault Status Register (CFSR) fields:
178   IBUSERR     Instruction bus error.
179       The processor attempted to issue an invalid instruction. It
180       detects the instruction bus error on prefecting, but this
181       flag is only set to 1 if it attempts to issue the faulting
182       instruction. When this bit is set, the processor has not
183       written a fault address to the BFAR.
184   UNDEFINSTR  Encountered invalid instruction.
185       The processor has attempted to execute an undefined
186       instruction. When this bit is set to 1, the PC value stacked
187       for the exception return points to the undefined instruction.
188       An undefined instruction is an instruction that the processor
189       cannot decode.
190
191   All registers:
192   cfsr       0x00010100
193
194.. note::
195   The CFSR is not supported on ARMv6-M CPUs (Cortex M0, M0+, M1).
196
197--------------------
198Snapshot integration
199--------------------
200This ``pw_cpu_exception`` backend provides helper functions that capture CPU
201exception state to snapshot protos.
202
203SnapshotCpuState()
204==================
205``SnapshotCpuState()`` captures the ``pw_cpu_exception_State`` to a
206``pw.cpu_exception.cortex_m.ArmV7mCpuState`` protobuf encoder.
207
208
209SnapshotMainStackThread()
210=========================
211``SnapshotMainStackThread()`` captures the main stack's execution thread state
212if active either from a given ``pw_cpu_exception_State`` or from the current
213running context. It captures the thread name depending on the processor mode,
214either ``Main Stack (Handler Mode)`` or ``Main Stack (Thread Mode)``. The stack
215limits must be provided along with a stack processing callback. All of this
216information is captured by a ``pw::thread::Thread`` protobuf encoder.
217
218.. note::
219   To minimize how much of the snapshot handling callstack is captured in the
220   stack trace, provide the ``pw_cpu_exception_State`` collected by the
221   exception entry (For example, as provided by
222   ``pw_cpu_exception_DefaultHandler()``)
223   instead of capturing the stack pointer just before calling into this
224   function.
225
226Python processor
227================
228This module's included Python exception analyzer tooling provides snapshot
229integration via a ``process_snapshot()`` function that produces a multi-line
230dump from a serialized snapshot proto, for example:
231
232.. code-block::
233
234   Exception caused by a usage fault.
235
236   Active Crash Fault Status Register (CFSR) fields:
237   UNDEFINSTR  Undefined Instruction UsageFault.
238       The processor has attempted to execute an undefined
239       instruction. When this bit is set to 1, the PC value stacked
240       for the exception return points to the undefined instruction.
241       An undefined instruction is an instruction that the processor
242       cannot decode.
243
244   All registers:
245   pc         0x0800e1c4 example::Service::Crash(_example_service_CrashRequest const&, _pw_protobuf_Empty&) (src/example_service/service.cc:131)
246   lr         0x0800e141 example::Service::Crash(_example_service_CrashRequest const&, _pw_protobuf_Empty&) (src/example_service/service.cc:128)
247   psr        0x81000000
248   msp        0x20040fd8
249   psp        0x20001488
250   exc_return 0xffffffed
251   cfsr       0x00010000
252   mmfar      0xe000ed34
253   bfar       0xe000ed38
254   icsr       0x00000803
255   hfsr       0x40000000
256   shcsr      0x00000000
257   control    0x00000000
258   r0         0xe03f7847
259   r1         0x714083dc
260   r2         0x0b36dc49
261   r3         0x7fbfbe1a
262   r4         0xc36e8efb
263   r5         0x69a14b13
264   r6         0x0ec35eaa
265   r7         0xa5df5543
266   r8         0xc892b931
267   r9         0xa2372c94
268   r10        0xbd15c968
269   r11        0x759b95ab
270   r12        0x00000000
271
272Module Configuration Options
273============================
274The following configurations can be adjusted via compile-time configuration of
275this module, see the
276:ref:`module documentation <module-structure-compile-time-configuration>` for
277more details.
278
279.. c:macro:: PW_CPU_EXCEPTION_CORTEX_M_LOG_LEVEL
280
281   The log level to use for this module. Logs below this level are omitted.
282
283   This defaults to ``PW_LOG_LEVEL_DEBUG``.
284
285.. c:macro:: PW_CPU_EXCEPTION_CORTEX_M_EXTENDED_CFSR_DUMP
286
287   Enables extended logging in pw::cpu_exception::LogCpuState() and
288   pw::cpu_exception::cortex_m::LogExceptionAnalysis() that dumps the active
289   CFSR fields with help strings. This is disabled by default since it
290   increases the binary size by >1.5KB when using plain-text logs, or ~460
291   Bytes when using tokenized logging. It's useful to enable this for device
292   bringup until your application has an end-to-end crash reporting solution.
293
294   This is disabled by default.
295