| Title: A common fatal error and assert fail handler |
| |
| Description: |
| |
| These two common handler is in order to reduce the redundancy code writing |
| for fatal and assert handler for error case testing. They can be used both |
| in kernel and userspace, and are also SMP safe. |
| |
| |
| Why doing this |
| ============== |
| |
| When writing error testing case (or we call it negative test case), we might |
| have to write self-defined k_sys_fatal_handler or post_assert_handler to deal |
| with the errors we caught, in order to make test going on. This mean much |
| identical code would be written. So we try to make it as a common part and |
| let other test case or app can reuse it. |
| |
| And when error happened, it sometimes need a special action to make our testing |
| program back to normal, such as release some resource hold before error |
| happened. This is why we add a hook on it, in order to achieve that goal. |
| |
| |
| How to use it in you app |
| ======================== |
| |
| (a) Usage for dealing with fatal error: |
| |
| Step1: Add CONFIG_ZTEST_FATAL_HOOK=y into prj.conf |
| |
| Step2: Include <ztest_fatal_hook.h> in C source file. |
| |
| Step3: (optional) Define a hook function call ztest_post_fatal_error_hook(). |
| |
| Step4: Call ztest_set_fault_valid(true) before where your target function |
| call. |
| |
| |
| (b) Usage for dealing with assert fail: |
| |
| Step1: Add CONFIG_ZTEST_ASSERT_HOOK=y into prj.conf |
| |
| Step2: Include <ztest_assert_hook.h> in your C code. |
| |
| Step3: (optional) Define a hook function call ztest_post_assert_fail_hook(). |
| |
| Step4: call ztest_set_assert_valid(true) before where your target function |
| call. |
| |
| |
| You can choose to use one or both of them, depneds on your need. |
| If you use none of them, you can still defined your own fatal or assert handler |
| as usual. |
| |
| |
| Test example in this test set |
| ============================= |
| |
| This test verifies if the common fatal error and assert fail handler works. |
| If the expected error got caught, the test case pass. |
| |
| test_catch_assert_fail |
| - To call a function then giving the condition to trigger the assert fail, |
| then catch it by the assert handler. |
| |
| test_catch_fatal_error |
| - start a thread to test trigger a null address then catch fatal error. |
| - start a thread to test trigger a illegal instruction then catch fatal |
| error. |
| - start a thread to test trigger a divide zero error then catch fatal error. |
| - start a thread to call k_oops() then catch fatal error. |
| - start a thread to call k_panel() then catch fatal error. |
| |
| test_catch_assert_in_isr |
| - start a thread to enter ISR context by calling irq_offload(), then trigger |
| an assert fail then catch it. |
| |
| test_catch_z_oops |
| - Pass illegal address by syscall, then inside the syscall handler, the |
| Z_OOPS macro will trigger a fatal error then got caught. |
| |
| |
| |
| Limitation of this usage |
| ======================== |
| |
| Trigger an fatal error in ISR context, that will cause problem due to |
| the interrupt stack is already abnormal when we want to continue other |
| test case, we do not recover it so far. |
| |
| |
| --------------------------------------------------------------------------- |
| |
| Sample Output: |
| |
| Running test suite error_hook_tests |
| =================================================================== |
| START - test_catch_assert_fail |
| ASSERTION FAIL [a != ((void *)0)] @ WEST_TOPDIR/zephyr/tests/ztest/error_hook/src/main.c:41 |
| parameter a should not be NULL! |
| Caught assert failed |
| Assert error expected as part of test case. |
| PASS - test_catch_assert_fail |
| =================================================================== |
| START - test_catch_fatal_error |
| case type is 0 |
| E: Page fault at address (nil) (error code 0x4) |
| E: Linear address not present in page tables |
| E: Access violation: user thread not allowed to read |
| E: PTE: not present |
| E: EAX: 0x00000000, EBX: 0x00000000, ECX: 0x00000000, EDX: 0x0010fe51 |
| E: ESI: 0x00000000, EDI: 0x0012dfe8, EBP: 0x0012dfcc, ESP: 0x0012dfc4 |
| E: EFLAGS: 0x00000246 CS: 0x002b CR3: 0x001142c0 |
| E: call trace: |
| E: EIP: 0x00100439 |
| E: 0x001010ea (0x113068) |
| E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0 |
| E: Current thread: 0x114000 (unknown) |
| Caught system error -- reason 0 1 |
| Fatal error expected as part of test case. |
| case type is 1 |
| E: Page fault at address 0x12dfc4 (error code 0x15) |
| E: Access violation: user thread not allowed to execute |
| E: PTE: 0x12d000 -> 0x000000000012d000: RW US A D XD |
| E: EAX: 0x0012dfc4, EBX: 0x00000001, ECX: 0x00000001, EDX: 0x0010fe51 |
| E: ESI: 0x00000000, EDI: 0x0012dfe8, EBP: 0x0012dfcc, ESP: 0x0012dfc0 |
| E: EFLAGS: 0x00000246 CS: 0x002b CR3: 0x001142c0 |
| E: call trace: |
| E: EIP: 0x0012dfc4 |
| E: 0x001010ea (0x113068) |
| E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0 |
| E: Current thread: 0x114000 (unknown) |
| Caught system error -- reason 0 1 |
| Fatal error expected as part of test case. |
| case type is 2 |
| E: Invalid opcode |
| E: EAX: 0x00000000, EBX: 0x00000002, ECX: 0x00000002, EDX: 0x0010fe51 |
| E: ESI: 0x00000000, EDI: 0x0012dfe8, EBP: 0x0012dfcc, ESP: 0x0012dfc4 |
| E: EFLAGS: 0x00000246 CS: 0x002b CR3: 0x001142c0 |
| E: call trace: |
| E: EIP: 0x00100451 |
| E: 0x001010ea (0x113068) |
| E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0 |
| E: Current thread: 0x114000 (unknown) |
| Caught system error -- reason 0 1 |
| Fatal error expected as part of test case. |
| case type is 3 |
| E: EAX: 0x00000000, EBX: 0x00000003, ECX: 0x00000003, EDX: 0x0010fe51 |
| E: ESI: 0x00000000, EDI: 0x0012dfe8, EBP: 0x0012dfcc, ESP: 0x0012dfc0 |
| E: EFLAGS: 0x00000246 CS: 0x002b CR3: 0x001142c0 |
| E: call trace: |
| E: EIP: 0x0010045c |
| E: 0x001010ea (0x113068) |
| E: >>> ZEPHYR FATAL ERROR 3: Kernel oops on CPU 0 |
| E: Current thread: 0x114000 (unknown) |
| Caught system error -- reason 3 1 |
| Fatal error expected as part of test case. |
| case type is 4 |
| E: EAX: 0x00000000, EBX: 0x00000004, ECX: 0x00000004, EDX: 0x0010fe51 |
| E: ESI: 0x00000000, EDI: 0x0012dfe8, EBP: 0x0012dfcc, ESP: 0x0012dfc0 |
| E: EFLAGS: 0x00000246 CS: 0x002b CR3: 0x001142c0 |
| E: call trace: |
| E: EIP: 0x00100465 |
| E: 0x001010ea (0x113068) |
| E: >>> ZEPHYR FATAL ERROR 3: Kernel oops on CPU 0 |
| E: Current thread: 0x114000 (unknown) |
| Caught system error -- reason 3 1 |
| Fatal error expected as part of test case. |
| PASS - test_catch_fatal_error |
| =================================================================== |
| START - test_catch_assert_in_isr |
| ASSERTION FAIL [a != ((void *)0)] @ WEST_TOPDIR/zephyr/tests/ztest/error_hook/src/main.c:41 |
| parameter a should not be NULL! |
| Caught assert failed |
| Assert error expected as part of test case. |
| PASS - test_catch_assert_in_isr |
| =================================================================== |
| START - test_catch_z_oops |
| E: Page fault at address (nil) (error code 0x4) |
| E: Linear address not present in page tables |
| E: Access violation: user thread not allowed to read |
| E: PTE: not present |
| E: EAX: 0x00000000, EBX: 0x0011303c, ECX: 0x00000000, EDX: 0x0011303c |
| E: ESI: 0x00000000, EDI: 0x00130fe8, EBP: 0x00130fc0, ESP: 0x00130fc0 |
| E: EFLAGS: 0x00000246 CS: 0x002b CR3: 0x001142c0 |
| E: call trace: |
| E: EIP: 0x00100544 |
| E: 0x00104808 (0x130033) |
| E: 0x001010ea (0x11303c) |
| E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0 |
| E: Current thread: 0x1140a0 (unknown) |
| Caught system error -- reason 0 1 |
| Fatal error expected as part of test case. |
| PASS - test_catch_z_oops |
| =================================================================== |
| Test suite error_hook_tests succeeded |
| =================================================================== |
| PROJECT EXECUTION SUCCESSFUL |