1 /*
2  * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 /*
7  * Note: Currently, the backtraces must still be checked manually. Therefore,
8  * these test cases should always pass.
9  * Todo: Automate the checking of backtrace addresses.
10  */
11 #include <stdlib.h>
12 #include "unity.h"
13 
14 #if __XTENSA__
15 
16 #include "freertos/FreeRTOS.h"
17 #include "freertos/task.h"
18 #include "freertos/xtensa_api.h"
19 #include "esp_intr_alloc.h"
20 #include "esp_rom_sys.h"
21 #include "esp_rom_uart.h"
22 
23 #define SW_ISR_LEVEL_1          7
24 #define SW_ISR_LEVEL_3          29
25 #define RECUR_DEPTH             3
26 #define ACTION_ABORT            -1
27 #define ACTION_INT_WDT          -2
28 
29 // Set to (-1) for abort(), (-2) for interrupt watchdog
30 static int backtrace_trigger_source;
31 
32 /*
33  * Recursive functions to generate a longer call stack. When the max specified
34  * recursion depth is reached, the following actions can be taken.
35  */
recursive_func(int recur_depth,int action)36 static void __attribute__((__noinline__)) recursive_func(int recur_depth, int action)
37 {
38     if (recur_depth > 1) {
39         recursive_func(recur_depth - 1, action);
40     } else if (action >= 0) {
41         xt_set_intset(1 << action);
42     } else if (action == ACTION_ABORT) {
43         abort();
44         // Todo: abort() causes problems in GDB Stub backtrace due to being 'non returning'.
45     } else if (action == ACTION_INT_WDT) {
46         portDISABLE_INTERRUPTS();
47         while (1) {
48             ;
49         }
50     }
51 }
52 
level_three_isr(void * arg)53 static void level_three_isr (void *arg)
54 {
55     xt_set_intclear(1 << SW_ISR_LEVEL_3);                           //Clear interrupt
56     recursive_func(RECUR_DEPTH, backtrace_trigger_source);         //Abort at the max recursive depth
57 }
58 
level_one_isr(void * arg)59 static void level_one_isr(void *arg)
60 {
61     xt_set_intclear(1 << SW_ISR_LEVEL_1);           //Clear interrupt
62     recursive_func(RECUR_DEPTH, SW_ISR_LEVEL_3);    //Trigger nested interrupt max recursive depth
63 }
64 
65 TEST_CASE("Test backtrace from abort", "[reset_reason][reset=abort,SW_CPU_RESET]")
66 {
67     //Allocate level one and three SW interrupts
68     esp_intr_alloc(ETS_INTERNAL_SW0_INTR_SOURCE, 0, level_one_isr, NULL, NULL);     //Level 1 SW intr
69     esp_intr_alloc(ETS_INTERNAL_SW1_INTR_SOURCE, 0, level_three_isr, NULL, NULL);   //Level 3 SW intr
70     backtrace_trigger_source = ACTION_ABORT;
71     recursive_func(RECUR_DEPTH, SW_ISR_LEVEL_1);    //Trigger lvl 1 SW interrupt at max recursive depth
72 }
73 
74 TEST_CASE("Test backtrace from interrupt watchdog timeout", "[reset_reason][reset=Interrupt wdt timeout on CPU0,SW_CPU_RESET]")
75 {
76     //Allocate level one and three SW interrupts
77     esp_intr_alloc(ETS_INTERNAL_SW0_INTR_SOURCE, 0, level_one_isr, NULL, NULL);     //Level 1 SW intr
78     esp_intr_alloc(ETS_INTERNAL_SW1_INTR_SOURCE, 0, level_three_isr, NULL, NULL);   //Level 3 SW intr
79     backtrace_trigger_source = ACTION_INT_WDT;
80     recursive_func(RECUR_DEPTH, SW_ISR_LEVEL_1);    //Trigger lvl 1 SW interrupt at max recursive depth
81 }
82 
write_char_crash(char c)83 static void write_char_crash(char c)
84 {
85     esp_rom_uart_putc(c);
86     *(char*) 0x00000001 = 0;
87 }
88 
89 TEST_CASE("Test backtrace with a ROM function", "[reset_reason][reset=StoreProhibited,SW_CPU_RESET]")
90 {
91     ets_install_putc1(&write_char_crash);
92     esp_rom_printf("foo");
93 }
94 
95 #endif
96