1 // Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "sdkconfig.h"
16 #include "esp_types.h"
17 #include "esp_attr.h"
18 #include "esp_err.h"
19 #include "esp_debug_helpers.h"
20 #include "soc/soc_memory_layout.h"
21 #include "soc/cpu.h"
22
23 #include "sdkconfig.h"
24
25 #include "esp_rom_sys.h"
26
esp_backtrace_get_next_frame(esp_backtrace_frame_t * frame)27 bool IRAM_ATTR esp_backtrace_get_next_frame(esp_backtrace_frame_t *frame)
28 {
29 //Use frame(i-1)'s BS area located below frame(i)'s sp to get frame(i-1)'s sp and frame(i-2)'s pc
30 void *base_save = (void *)frame->sp; //Base save area consists of 4 words under SP
31 frame->pc = frame->next_pc;
32 frame->next_pc = *((uint32_t *)(base_save - 16)); //If next_pc = 0, indicates frame(i-1) is the last frame on the stack
33 frame->sp = *((uint32_t *)(base_save - 12));
34
35 //Return true if both sp and pc of frame(i-1) are sane, false otherwise
36 return (esp_stack_ptr_is_sane(frame->sp) && esp_ptr_executable((void*)esp_cpu_process_stack_pc(frame->pc)));
37 }
38
esp_backtrace_print(int depth)39 esp_err_t IRAM_ATTR esp_backtrace_print(int depth)
40 {
41 //Check arguments
42 if (depth <= 0) {
43 return ESP_ERR_INVALID_ARG;
44 }
45
46 //Initialize stk_frame with first frame of stack
47 esp_backtrace_frame_t stk_frame;
48 esp_backtrace_get_start(&(stk_frame.pc), &(stk_frame.sp), &(stk_frame.next_pc));
49 //esp_cpu_get_backtrace_start(&stk_frame);
50 esp_rom_printf("\r\n\r\nBacktrace:");
51 esp_rom_printf("0x%08X:0x%08X ", esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp);
52
53 //Check if first frame is valid
54 bool corrupted = (esp_stack_ptr_is_sane(stk_frame.sp) &&
55 esp_ptr_executable((void*)esp_cpu_process_stack_pc(stk_frame.pc))) ?
56 false : true;
57
58 uint32_t i = (depth <= 0) ? INT32_MAX : depth;
59 while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) {
60 if (!esp_backtrace_get_next_frame(&stk_frame)) { //Get previous stack frame
61 corrupted = true;
62 }
63 esp_rom_printf("0x%08X:0x%08X ", esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp);
64 }
65
66 //Print backtrace termination marker
67 esp_err_t ret = ESP_OK;
68 if (corrupted) {
69 esp_rom_printf(" |<-CORRUPTED");
70 ret = ESP_FAIL;
71 } else if (stk_frame.next_pc != 0) { //Backtrace continues
72 esp_rom_printf(" |<-CONTINUES");
73 }
74 esp_rom_printf("\r\n\r\n");
75 return ret;
76 }
77