1Title: A common fatal error and assert fail handler
2
3Description:
4
5These two common handlers are developed in order to reduce the redundancy
6code writing for fatal and assert handler for error case testing. They can
7be used both in kernel and userspace, and they are also SMP safe.
8
9
10Why doing this
11==============
12
13When writing error testing case (or we call it negative test case), we might
14have to write self-defined k_sys_fatal_handler or post_assert_handler to deal
15with the errors we caught, in order to make the test continue. This means much
16identical code would be written. So we try to move the error handler definition
17into a common part and let other test suites or applications reuse it, instead
18of defining their own.
19
20And when error happens, we sometimes need a special action to make our testing
21program return back to normal, such as releasing some resource hold before the
22error happened. This is why we add a hook on it, in order to achieve that goal.
23
24
25How to use it in you app
26========================
27
28(a) Usage for dealing with fatal error:
29
30Step1: Add CONFIG_ZTEST_FATAL_HOOK=y into prj.conf
31
32Step2: Include <ztest_fatal_hook.h> in C source file.
33
34Step3: (optional) Define a hook function call ztest_post_fatal_error_hook().
35
36Step4: Call ztest_set_fault_valid(true) before where your target function
37       call.
38
39
40(b) Usage for dealing with assert fail:
41
42Step1: Add CONFIG_ZTEST_ASSERT_HOOK=y into prj.conf
43
44Step2: Include <zephyr/ztest_error_hook.h> in your C code.
45
46Step3: (optional) Define a hook function call ztest_post_assert_fail_hook().
47
48Step4: call ztest_set_assert_valid(true) before where your target function
49       call.
50
51
52You can choose to use one or both of them, depending on your needs.
53If you use none of them, you can still define your own fatal or assert handler
54as usual.
55
56
57Test example in this test set
58=============================
59
60This test verifies if the common fatal error and assert fail handler works.
61If the expected error was caught, the test case will pass.
62
63test_catch_assert_fail
64  - To call a function then giving the condition to trigger the assert fail,
65    then catch it by the assert handler.
66
67test_catch_fatal_error
68  - start a thread to test triggering a null address dereferencing, then catch
69    the (expected) fatal error.
70  - start a thread to test triggering an illegal instruction, then catch
71    the (expected) fatal error.
72  - start a thread to test triggering a divide-by-zero error, then catch
73    the (expected) fatal error.
74  - start a thread to call k_oops() then catch the (expected) fatal error.
75  - start a thread to call k_panel() then catch the (expected) fatal error.
76
77test_catch_assert_in_isr
78  - start a thread to enter ISR context by calling irq_offload(), then trigger
79    an assert fail then catch it.
80
81test_catch_z_oops
82  - Pass illegal address by syscall, then inside the syscall handler, the
83    K_OOPS macro will trigger a fatal error that will get caught (as expected).
84
85
86
87Limitation of this usage
88========================
89
90Trigger a fatal error in ISR context, that will cause problem due to
91the interrupt stack is already abnormal when we want to continue other
92test case, we do not recover it so far.
93
94
95---------------------------------------------------------------------------
96
97Sample Output:
98
99Running test suite error_hook_tests
100===================================================================
101START - test_catch_assert_fail
102ASSERTION FAIL [a != ((void *)0)] @ WEST_TOPDIR/zephyr/tests/ztest/error_hook/src/main.c:41
103        parameter a should not be NULL!
104Caught assert failed
105Assert error expected as part of test case.
106 PASS - test_catch_assert_fail
107===================================================================
108START - test_catch_fatal_error
109case type is 0
110E: Page fault at address (nil) (error code 0x4)
111E: Linear address not present in page tables
112E: Access violation: user thread not allowed to read
113E: PTE: not present
114E: EAX: 0x00000000, EBX: 0x00000000, ECX: 0x00000000, EDX: 0x0010fe51
115E: ESI: 0x00000000, EDI: 0x0012dfe8, EBP: 0x0012dfcc, ESP: 0x0012dfc4
116E: EFLAGS: 0x00000246 CS: 0x002b CR3: 0x001142c0
117E: call trace:
118E: EIP: 0x00100439
119E:      0x001010ea (0x113068)
120E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
121E: Current thread: 0x114000 (unknown)
122Caught system error -- reason 0 1
123Fatal error expected as part of test case.
124case type is 1
125E: Page fault at address 0x12dfc4 (error code 0x15)
126E: Access violation: user thread not allowed to execute
127E: PTE: 0x12d000 -> 0x000000000012d000: RW US A D XD
128E: EAX: 0x0012dfc4, EBX: 0x00000001, ECX: 0x00000001, EDX: 0x0010fe51
129E: ESI: 0x00000000, EDI: 0x0012dfe8, EBP: 0x0012dfcc, ESP: 0x0012dfc0
130E: EFLAGS: 0x00000246 CS: 0x002b CR3: 0x001142c0
131E: call trace:
132E: EIP: 0x0012dfc4
133E:      0x001010ea (0x113068)
134E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
135E: Current thread: 0x114000 (unknown)
136Caught system error -- reason 0 1
137Fatal error expected as part of test case.
138case type is 2
139E: Invalid opcode
140E: EAX: 0x00000000, EBX: 0x00000002, ECX: 0x00000002, EDX: 0x0010fe51
141E: ESI: 0x00000000, EDI: 0x0012dfe8, EBP: 0x0012dfcc, ESP: 0x0012dfc4
142E: EFLAGS: 0x00000246 CS: 0x002b CR3: 0x001142c0
143E: call trace:
144E: EIP: 0x00100451
145E:      0x001010ea (0x113068)
146E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
147E: Current thread: 0x114000 (unknown)
148Caught system error -- reason 0 1
149Fatal error expected as part of test case.
150case type is 3
151E: EAX: 0x00000000, EBX: 0x00000003, ECX: 0x00000003, EDX: 0x0010fe51
152E: ESI: 0x00000000, EDI: 0x0012dfe8, EBP: 0x0012dfcc, ESP: 0x0012dfc0
153E: EFLAGS: 0x00000246 CS: 0x002b CR3: 0x001142c0
154E: call trace:
155E: EIP: 0x0010045c
156E:      0x001010ea (0x113068)
157E: >>> ZEPHYR FATAL ERROR 3: Kernel oops on CPU 0
158E: Current thread: 0x114000 (unknown)
159Caught system error -- reason 3 1
160Fatal error expected as part of test case.
161case type is 4
162E: EAX: 0x00000000, EBX: 0x00000004, ECX: 0x00000004, EDX: 0x0010fe51
163E: ESI: 0x00000000, EDI: 0x0012dfe8, EBP: 0x0012dfcc, ESP: 0x0012dfc0
164E: EFLAGS: 0x00000246 CS: 0x002b CR3: 0x001142c0
165E: call trace:
166E: EIP: 0x00100465
167E:      0x001010ea (0x113068)
168E: >>> ZEPHYR FATAL ERROR 3: Kernel oops on CPU 0
169E: Current thread: 0x114000 (unknown)
170Caught system error -- reason 3 1
171Fatal error expected as part of test case.
172 PASS - test_catch_fatal_error
173===================================================================
174START - test_catch_assert_in_isr
175ASSERTION FAIL [a != ((void *)0)] @ WEST_TOPDIR/zephyr/tests/ztest/error_hook/src/main.c:41
176        parameter a should not be NULL!
177Caught assert failed
178Assert error expected as part of test case.
179 PASS - test_catch_assert_in_isr
180===================================================================
181START - test_catch_z_oops
182E: EAX: 0x00000000, EBX: 0x00000000, ECX: 0x00000000, EDX: 0x00000000
183E: ESI: 0x00000000, EDI: 0x00000000, EBP: 0x00000000, ESP: 0x00000000
184E: EFLAGS: 0x001003c4 CS: 0x0511 CR3: 0x00115740
185E: call trace:
186E: EIP: 0x0010ff9e
187E: NULL base ptr
188E: >>> ZEPHYR FATAL ERROR 3: Kernel oops on CPU 0
189E: Current thread: 0x114120 (unknown)
190Caught system error -- reason 3 1
191Fatal error expected as part of test case.
192 PASS - test_catch_z_oops
193===================================================================
194Test suite error_hook_tests succeeded
195===================================================================
196PROJECT EXECUTION SUCCESSFUL
197