mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-07-15 08:32:42 +08:00
feat(esp8266): refactor ESP8266(xtensa lx106) panic backtrace function
This commit is contained in:
@ -23,6 +23,7 @@ else()
|
||||
|
||||
set(srcs
|
||||
"source/chip_boot.c"
|
||||
"source/backtrace.c"
|
||||
"source/esp_err_to_name.c"
|
||||
"source/esp_timer.c"
|
||||
"source/esp_wifi_os_adapter.c"
|
||||
|
61
components/esp8266/include/esp8266/backtrace.h
Normal file
61
components/esp8266/include/esp8266/backtrace.h
Normal 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
|
@ -25,7 +25,9 @@
|
||||
#ifndef _EAGLE_SOC_H_
|
||||
#define _EAGLE_SOC_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "driver/soc.h"
|
||||
|
||||
/* IO definitions (access restrictions to peripheral registers) */
|
||||
@ -190,7 +192,7 @@
|
||||
#define DRAM_SIZE (96 * 1024)
|
||||
|
||||
#define IRAM_BASE (0x40100000)
|
||||
#define IRAM_SIZE (48 * 1024)
|
||||
#define IRAM_SIZE (CONFIG_SOC_IRAM_SIZE)
|
||||
|
||||
#define FLASH_BASE (0x40200000)
|
||||
#define FLASH_SIZE (1 * 1024 * 1024)
|
||||
|
119
components/esp8266/source/backtrace.c
Normal file
119
components/esp8266/source/backtrace.c
Normal 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;
|
||||
}
|
@ -18,205 +18,138 @@
|
||||
#include "esp_libc.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
#include "esp8266/eagle_soc.h"
|
||||
#include "esp8266/rom_functions.h"
|
||||
#include "esp8266/backtrace.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_err.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 DISABLE_FREERTOS
|
||||
/*
|
||||
* @Note: If freeRTOS is updated, the structure must be checked.
|
||||
*/
|
||||
typedef struct task_info
|
||||
|
||||
typedef struct panic_frame {
|
||||
uint32_t exit;
|
||||
|
||||
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;
|
||||
|
||||
#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[] = {
|
||||
static const char *sdesc[] = {
|
||||
"PC", "PS", "A0", "A1",
|
||||
"A2", "A3", "A4", "A5",
|
||||
"A6", "A7", "A8", "A9",
|
||||
"A10", "A11", "A12", "A13",
|
||||
"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) {
|
||||
ets_printf("Task watchdog got triggered.\r\n\r\n");
|
||||
}
|
||||
void *o_pc;
|
||||
void *o_sp;
|
||||
|
||||
if (_chip_nmi_cnt) {
|
||||
extern const uint32_t _chip_nmi_stk, LoadStoreErrorHandlerStack;
|
||||
const char *reason = frame->exccause < 30 ? edesc[frame->exccause] : "unknown";
|
||||
const uint32_t *regs = (const uint32_t *)frame;
|
||||
|
||||
_chip_nmi_cnt = 0;
|
||||
ets_printf("Core 0 was running in NMI context:\r\n\r\n");
|
||||
PANIC("Guru Meditation Error: Core 0 panic'ed (%s). Exception was unhandled.\r\n", reason);
|
||||
PANIC("Core 0 register dump:\n");
|
||||
|
||||
panic_stack(regs, &_chip_nmi_stk, &LoadStoreErrorHandlerStack);
|
||||
} else {
|
||||
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");
|
||||
|
||||
panic_stack(regs, &_chip_interrupt_stk, &_chip_interrupt_tmp);
|
||||
} 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");
|
||||
}
|
||||
for (int i = 0; i < 20; i += 4) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
PANIC("%-8s: 0x%08x ", sdesc[i + j], regs[i + j + 1]);
|
||||
}
|
||||
PANIC("\r\n");
|
||||
}
|
||||
|
||||
for (x = 0; x < 20; x += 4) {
|
||||
for (y = 0; y < 4; y++) {
|
||||
ets_printf("%10s: 0x%08x", sdesc[x + y], regs[x + y + 1]);
|
||||
}
|
||||
ets_printf("\r\n");
|
||||
PANIC("\r\nBacktrace: %p:%p ", i_pc, i_sp);
|
||||
while(xt_retaddr_callee(i_pc, i_sp, i_lr, &o_pc, &o_sp)) {
|
||||
PANIC("%p:%p ", o_pc, o_sp);
|
||||
i_pc = o_pc;
|
||||
i_sp = o_sp;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_PANIC_PRINT_HALT
|
||||
while (1);
|
||||
#else
|
||||
esp_restart();
|
||||
#endif
|
||||
PANIC("\r\n");
|
||||
}
|
||||
#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
|
||||
extern int _chip_nmi_cnt;
|
||||
|
||||
_chip_nmi_cnt = 0;
|
||||
|
||||
/* NMI can interrupt exception. */
|
||||
vPortEnterCritical();
|
||||
do {
|
||||
REG_WRITE(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
|
||||
esp_restart();
|
||||
#endif
|
||||
|
||||
#else /* CONFIG_ESP_PANIC_SILENT_REBOOT */
|
||||
esp_restart();
|
||||
#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)
|
||||
{
|
||||
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
|
||||
ets_printf(" (%s)", esp_err_to_name(rc));
|
||||
PANIC(" (%s)", esp_err_to_name(rc));
|
||||
#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
|
||||
//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);
|
||||
//}
|
||||
}
|
||||
|
||||
|
@ -57,8 +57,6 @@ uint32_t cpu_sr;
|
||||
|
||||
uint32_t _xt_tick_divisor;
|
||||
|
||||
int __g_is_task_overflow;
|
||||
|
||||
/* Each task maintains its own interrupt status in the critical nesting
|
||||
variable. */
|
||||
static uint32_t uxCriticalNesting = 0;
|
||||
@ -368,7 +366,6 @@ int xPortInIsrContext(void)
|
||||
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);
|
||||
__g_is_task_overflow = 1;
|
||||
abort();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user