feat(esp8266): refactor ESP8266(xtensa lx106) panic backtrace function

This commit is contained in:
dongheng
2019-08-22 20:11:59 +08:00
parent 0193d06019
commit 767d995466
6 changed files with 269 additions and 156 deletions

View File

@ -23,6 +23,7 @@ else()
set(srcs set(srcs
"source/chip_boot.c" "source/chip_boot.c"
"source/backtrace.c"
"source/esp_err_to_name.c" "source/esp_err_to_name.c"
"source/esp_timer.c" "source/esp_timer.c"
"source/esp_wifi_os_adapter.c" "source/esp_wifi_os_adapter.c"

View File

@ -0,0 +1,61 @@
// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Check if PC pointer locates at code section
*
* @param pc the PC pointer
*
* @return 1 if valid or 0 if invalid
*/
int xt_pc_is_valid(const void *pc);
/**
* @brief Detected recursively and serach the previous PC and SP
*
* @param i_pc the PC address for forward recursive detection
* @param i_sp the SP address for forward recursive detection
* @param i_lr the LR address, maybe it the previous PC address
* @param o_pc the detected previous PC address
* @param o_pc the detected previous SP address
*
* @return 1 if found or 0 if not found
*/
int xt_retaddr_callee(const void *i_pc, const void *i_sp, const void *i_lr, void **o_pc, void **o_sp);
/**
* @brief These functions may be used to get information about the callers of a function.
*
* Using this API instead of "__builtin_return_address".
*
* This function returns the return address of the current function, or of one of its callers.
* The level argument is number of frames to scan up the call stack. A value of 0 yields the
* return address of the current function, a value of 1 yields the return address of the caller
* of the current function, and so forth..
*
* @param lvl caller level
*
* @return the return address of the current function
*/
void *xt_return_address(int lvl);
#ifdef __cplusplus
}
#endif

View File

@ -25,7 +25,9 @@
#ifndef _EAGLE_SOC_H_ #ifndef _EAGLE_SOC_H_
#define _EAGLE_SOC_H_ #define _EAGLE_SOC_H_
#include "sdkconfig.h"
#include <stdint.h> #include <stdint.h>
#include <stddef.h>
#include "driver/soc.h" #include "driver/soc.h"
/* IO definitions (access restrictions to peripheral registers) */ /* IO definitions (access restrictions to peripheral registers) */
@ -190,7 +192,7 @@
#define DRAM_SIZE (96 * 1024) #define DRAM_SIZE (96 * 1024)
#define IRAM_BASE (0x40100000) #define IRAM_BASE (0x40100000)
#define IRAM_SIZE (48 * 1024) #define IRAM_SIZE (CONFIG_SOC_IRAM_SIZE)
#define FLASH_BASE (0x40200000) #define FLASH_BASE (0x40200000)
#define FLASH_SIZE (1 * 1024 * 1024) #define FLASH_SIZE (1 * 1024 * 1024)

View File

@ -0,0 +1,119 @@
// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include "esp8266/eagle_soc.h"
static inline uint32_t prev_text_size(const uint32_t pc)
{
uint32_t size;
extern uint32_t _text_start, _text_end;
if (pc > (uint32_t)&_text_start && pc < (uint32_t)&_text_end) {
size = pc - (uint32_t )&_text_start;
} else if (IS_IRAM(pc)) {
size = pc - IRAM_BASE;
} else {
size = 0;
}
return size;
}
int xt_pc_is_valid(const void *pc)
{
return prev_text_size((uint32_t)pc) ? 1 : 0;
}
int xt_retaddr_callee(const void *i_pc, const void *i_sp, const void *i_lr, void **o_pc, void **o_sp)
{
uint32_t lr = (uint32_t)i_lr;
uint32_t pc = (uint32_t)i_pc;
uint32_t sp = (uint32_t)i_sp;
uint32_t off = 0;
const uint32_t text_size = prev_text_size(pc);
for (; off < text_size; off++) {
if ((*(uint8_t *)(pc - off) == 0x12) &&
(*(uint8_t *)(pc - off + 1) == 0xc1)) {
const int8_t stk_size = *(int8_t *)(pc - off + 2);
if (stk_size >= 0 || stk_size % 16 != 0) {
continue;
}
sp -= stk_size;
pc = *(uint32_t *)(sp - 4);
*o_sp = (void *)sp;
*o_pc = (void *)pc;
break;
} else if ((*(uint8_t *)(pc - off) == 0x92) &&
(((*(uint8_t *)(pc - off + 1)) & 0xf0) == 0xa0) &&
(*(uint8_t *)(pc - off + 3) == 0x90) &&
(*(uint8_t *)(pc - off + 4) == 0x11) &&
(*(uint8_t *)(pc - off + 5) == 0xc0)) {
const uint16_t stk_size = ((*(uint8_t *)(pc - off + 1)) & 0x0f) + (*(uint8_t *)(pc - off + 2));
if (!stk_size || stk_size >= 2048) {
continue;
}
sp += stk_size;
pc = *(uint32_t *)(sp - 4);
*o_sp = (void *)sp;
*o_pc = (void *)pc;
break;
} else if ((*(uint8_t *)(pc - off) == 0x0d) &&
(*(uint8_t *)(pc - off + 1) == 0xf0)) {
pc = lr;
*o_sp = (void *)sp;
*o_pc = (void *)pc;
break;
}
}
return off < text_size ? (xt_pc_is_valid(*o_pc) ? 1 : 0) : 0;
}
void *xt_return_address(int lvl)
{
void *i_sp;
void *i_lr = NULL;
void *i_pc = (void *)((uint32_t)xt_return_address + 32);
void *o_pc = NULL;
void *o_sp;
__asm__ __volatile__(
"mov %0, a1\n"
: "=a"(i_sp)
:
: "memory"
);
lvl += 2;
while(lvl-- && xt_retaddr_callee(i_pc, i_sp, i_lr, &o_pc, &o_sp)) {
i_pc = o_pc;
i_sp = o_sp;
}
return xt_pc_is_valid(o_pc) ? o_pc : NULL;
}

View File

@ -18,205 +18,138 @@
#include "esp_libc.h" #include "esp_libc.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp8266/eagle_soc.h"
#include "esp8266/rom_functions.h" #include "esp8266/rom_functions.h"
#include "esp8266/backtrace.h"
#include "rom/ets_sys.h" #include "rom/ets_sys.h"
#include "esp_err.h" #include "esp_err.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h"
#include "private/list.h"
#include "private/portable.h"
#define STACK_VOL_NUM 16 #define PANIC(_fmt, ...) ets_printf(_fmt, ##__VA_ARGS__)
#ifndef CONFIG_ESP_PANIC_SILENT_REBOOT #ifndef CONFIG_ESP_PANIC_SILENT_REBOOT
#ifndef DISABLE_FREERTOS
/* typedef struct panic_frame {
* @Note: If freeRTOS is updated, the structure must be checked. uint32_t exit;
*/
typedef struct task_info uint32_t pc;
uint32_t ps;
uint32_t a0;
uint32_t a1;
uint32_t a2;
uint32_t a3;
uint32_t a4;
uint32_t a5;
uint32_t a6;
uint32_t a7;
uint32_t a8;
uint32_t a9;
uint32_t a10;
uint32_t a11;
uint32_t a12;
uint32_t a13;
uint32_t a14;
uint32_t a15;
uint32_t sar;
uint32_t exccause;
} panic_frame_t;
static inline void panic_frame(panic_frame_t *frame)
{ {
volatile StackType_t *pxTopOfStack; static const char *sdesc[] = {
#if ( portUSING_MPU_WRAPPERS == 1 )
xMPU_SETTINGS xMPUSettings;
#endif
ListItem_t xStateListItem;
ListItem_t xEventListItem;
UBaseType_t uxPriority;
StackType_t *pxStack;
char pcTaskName[ configMAX_TASK_NAME_LEN ];
#if configRECORD_STACK_HIGH_ADDRESS != 1
#error "configRECORD_STACK_HIGH_ADDRESS must enable"
#endif
#if portSTACK_GROWTH >= 0
#error "Task stack must decrease growing."
#endif
StackType_t *pxEndOfStack;
} task_info_t;
static inline uint32_t *__get_stack_head(void *task)
{
return (uint32_t *)((task_info_t *)task)->pxStack;
}
static inline uint32_t *__get_stack_tail(void *task)
{
return (uint32_t *)((task_info_t *)task)->pxEndOfStack;
}
#else
typedef void* task_info_t;
extern uint32_t *__get_stack_head(void *task);
extern uint32_t *__get_stack_tail(void *task);
#endif
static void panic_stack(const uint32_t *reg, const uint32_t *start_stk, const uint32_t *end_stk)
{
const uint32_t *stk_ptr = (const uint32_t *)reg[4];
if (stk_ptr <= start_stk || stk_ptr >= end_stk) {
ets_printf("register map is %x error\n", stk_ptr);
} else {
#ifndef CONFIG_PANIC_FULL_STACK
start_stk = (const uint32_t *)((uint32_t)stk_ptr & (~(STACK_VOL_NUM * sizeof(const uint32_t *) - 1)));
#endif
}
size_t size = end_stk - start_stk + 1;
if (size < STACK_VOL_NUM) {
start_stk = start_stk - (STACK_VOL_NUM - size);
size = STACK_VOL_NUM;
}
ets_printf("%10s", " ");
for (int i = 0; i < STACK_VOL_NUM; i++) {
ets_printf(" %8x ", i * sizeof(void *));
}
ets_printf("\r\n\r\n");
for (int i = 0; i < size; i += STACK_VOL_NUM) {
size_t len = size > i ? size - i : STACK_VOL_NUM - (i - size);
if (len > STACK_VOL_NUM)
len = STACK_VOL_NUM;
ets_printf("%08x ", start_stk + i);
for (int j = 0; j < len; j++) {
ets_printf("0x%08x ", start_stk[i + j]);
}
ets_printf("\r\n");
}
}
/*
* @brief output xtensa register value map when crash
*
* @param frame xtensa register value map pointer
*
* @return none
*/
static __attribute__((noreturn)) void panic_info(void *frame, int wdt)
{
extern int _chip_nmi_cnt;
extern int __g_is_task_overflow;
task_info_t *task;
uint32_t *regs = (uint32_t *)frame;
int x, y;
const char *sdesc[] = {
"PC", "PS", "A0", "A1", "PC", "PS", "A0", "A1",
"A2", "A3", "A4", "A5", "A2", "A3", "A4", "A5",
"A6", "A7", "A8", "A9", "A6", "A7", "A8", "A9",
"A10", "A11", "A12", "A13", "A10", "A11", "A12", "A13",
"A14", "A15", "SAR", "EXCCAUSE" "A14", "A15", "SAR", "EXCCAUSE"
}; };
static const char *edesc[] = {
"IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
"Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue",
"Privileged", "LoadStoreAlignment", "res", "res",
"InstrPDAddrError", "LoadStorePIFDataError", "InstrPIFAddrError", "LoadStorePIFAddrError",
"InstTLBMiss", "InstTLBMultiHit", "InstFetchPrivilege", "res",
"InstrFetchProhibited", "res", "res", "res",
"LoadStoreTLBMiss", "LoadStoreTLBMultihit", "LoadStorePrivilege", "res",
"LoadProhibited", "StoreProhibited",
};
ets_printf("\r\n\r\n"); void *i_lr = (void *)frame->a0;
void *i_pc = (void *)frame->pc;
void *i_sp = (void *)frame->a1;
if (wdt) { void *o_pc;
ets_printf("Task watchdog got triggered.\r\n\r\n"); void *o_sp;
}
if (_chip_nmi_cnt) {
extern const uint32_t _chip_nmi_stk, LoadStoreErrorHandlerStack;
_chip_nmi_cnt = 0; const char *reason = frame->exccause < 30 ? edesc[frame->exccause] : "unknown";
ets_printf("Core 0 was running in NMI context:\r\n\r\n"); const uint32_t *regs = (const uint32_t *)frame;
panic_stack(regs, &_chip_nmi_stk, &LoadStoreErrorHandlerStack); PANIC("Guru Meditation Error: Core 0 panic'ed (%s). Exception was unhandled.\r\n", reason);
} else { PANIC("Core 0 register dump:\n");
if (xPortInIsrContext() && !wdt && !__g_is_task_overflow) {
extern const uint32_t _chip_interrupt_stk, _chip_interrupt_tmp;
ets_printf("Core 0 was running in ISR context:\r\n\r\n"); for (int i = 0; i < 20; i += 4) {
for (int j = 0; j < 4; j++) {
panic_stack(regs, &_chip_interrupt_stk, &_chip_interrupt_tmp); PANIC("%-8s: 0x%08x ", sdesc[i + j], regs[i + j + 1]);
} else {
if ((task = (task_info_t *)xTaskGetCurrentTaskHandle())) {
const uint32_t *pdata = __get_stack_head(task);
const uint32_t *end = __get_stack_tail(task);
ets_printf("Task stack [%s] stack from [%p] to [%p], total [%d] size\r\n\r\n", task->pcTaskName,
pdata, end, (end - pdata + 1) * sizeof(const uint32_t *));
panic_stack(regs, pdata, end);
ets_printf("\r\n\r\n");
} else {
ets_printf("No task\r\n\r\n");
}
} }
PANIC("\r\n");
} }
for (x = 0; x < 20; x += 4) { PANIC("\r\nBacktrace: %p:%p ", i_pc, i_sp);
for (y = 0; y < 4; y++) { while(xt_retaddr_callee(i_pc, i_sp, i_lr, &o_pc, &o_sp)) {
ets_printf("%10s: 0x%08x", sdesc[x + y], regs[x + y + 1]); PANIC("%p:%p ", o_pc, o_sp);
} i_pc = o_pc;
ets_printf("\r\n"); i_sp = o_sp;
} }
PANIC("\r\n");
#ifdef CONFIG_ESP_PANIC_PRINT_HALT
while (1);
#else
esp_restart();
#endif
} }
#endif /* !CONFIG_ESP_PANIC_SILENT_REBOOT */ #endif /* !CONFIG_ESP_PANIC_SILENT_REBOOT */
void __attribute__((noreturn)) panicHandler(void *frame, int wdt) void panicHandler(void *frame, int wdt)
{ {
#ifndef CONFIG_ESP_PANIC_SILENT_REBOOT #ifndef CONFIG_ESP_PANIC_SILENT_REBOOT
extern int _chip_nmi_cnt;
_chip_nmi_cnt = 0;
/* NMI can interrupt exception. */ /* NMI can interrupt exception. */
vPortEnterCritical(); vPortEnterCritical();
do { do {
REG_WRITE(INT_ENA_WDEV, 0); REG_WRITE(INT_ENA_WDEV, 0);
} while (REG_READ(INT_ENA_WDEV) != 0); } while (REG_READ(INT_ENA_WDEV) != 0);
panic_info(frame, wdt); if (wdt) {
PANIC("Task watchdog got triggered.\r\n\r\n");
}
panic_frame(frame);
#ifdef CONFIG_ESP_PANIC_PRINT_HALT
while (1);
#else #else
esp_restart(); esp_restart();
#endif
#else /* CONFIG_ESP_PANIC_SILENT_REBOOT */
esp_restart();
#endif /* !CONFIG_ESP_PANIC_SILENT_REBOOT */ #endif /* !CONFIG_ESP_PANIC_SILENT_REBOOT */
} }
static void esp_error_check_failed_print(const char *msg, esp_err_t rc, const char *file, int line, const char *function, const char *expression) static void esp_error_check_failed_print(const char *msg, esp_err_t rc, const char *file, int line, const char *function, const char *expression)
{ {
ets_printf("%s failed: esp_err_t 0x%x", msg, rc); PANIC("%s failed: esp_err_t 0x%x", msg, rc);
#ifdef CONFIG_ESP_ERR_TO_NAME_LOOKUP #ifdef CONFIG_ESP_ERR_TO_NAME_LOOKUP
ets_printf(" (%s)", esp_err_to_name(rc)); PANIC(" (%s)", esp_err_to_name(rc));
#endif //CONFIG_ESP_ERR_TO_NAME_LOOKUP #endif //CONFIG_ESP_ERR_TO_NAME_LOOKUP
ets_printf(" at 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3); PANIC(" at 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3);
// ESP8266 put main FreeRTOS code at flash // ESP8266 put main FreeRTOS code at flash
//if (spi_flash_cache_enabled()) { // strings may be in flash cache //if (spi_flash_cache_enabled()) { // strings may be in flash cache
ets_printf("file: \"%s\" line %d\nfunc: %s\nexpression: %s\n", file, line, function, expression); PANIC("file: \"%s\" line %d\nfunc: %s\nexpression: %s\n", file, line, function, expression);
//} //}
} }

View File

@ -57,8 +57,6 @@ uint32_t cpu_sr;
uint32_t _xt_tick_divisor; uint32_t _xt_tick_divisor;
int __g_is_task_overflow;
/* Each task maintains its own interrupt status in the critical nesting /* Each task maintains its own interrupt status in the critical nesting
variable. */ variable. */
static uint32_t uxCriticalNesting = 0; static uint32_t uxCriticalNesting = 0;
@ -368,7 +366,6 @@ int xPortInIsrContext(void)
void __attribute__((weak, noreturn)) vApplicationStackOverflowHook(xTaskHandle xTask, const char *pcTaskName) void __attribute__((weak, noreturn)) vApplicationStackOverflowHook(xTaskHandle xTask, const char *pcTaskName)
{ {
ets_printf("***ERROR*** A stack overflow in task %s has been detected.\r\n", pcTaskName); ets_printf("***ERROR*** A stack overflow in task %s has been detected.\r\n", pcTaskName);
__g_is_task_overflow = 1;
abort(); abort();
} }