Merge branch 'bugfix/coredump_esp_panic_reason' into 'master'

Coredump ESP panic reason

See merge request espressif/esp-idf!9072
This commit is contained in:
Ivan Grokhotkov 2020-07-28 23:49:10 +08:00
commit 8ac56e904b
15 changed files with 75 additions and 53 deletions

View File

@ -1,6 +1,5 @@
idf_component_register(SRCS "panic.c" "system_api.c" "startup.c"
INCLUDE_DIRS include
PRIV_INCLUDE_DIRS private_include
PRIV_REQUIRES spi_flash app_update
# requirements due to startup code
nvs_flash pthread app_trace

View File

@ -15,11 +15,13 @@
#pragma once
#include <stdint.h>
#include "port/panic_funcs.h"
#include <stdbool.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
extern bool g_panic_abort;
// Function to print longer amounts of information such as the details
@ -49,6 +51,7 @@ typedef struct {
panic_info_dump_fn_t state; // processor state, usually the contents of the registers
const void* addr; // instruction address that triggered the exception
const void* frame; // reference to the frame
bool pseudo_excause; // flag indicating that exception cause has special meaning
} panic_info_t;
#define PANIC_INFO_DUMP(info, dump_fn) {if ((info)->dump_fn) (*(info)->dump_fn)((info->frame));}
@ -68,3 +71,7 @@ void panic_print_hex(int h);
#endif
void __attribute__((noreturn)) panic_abort(const char *details);
#ifdef __cplusplus
}
#endif

View File

@ -43,7 +43,7 @@
#include "hal/uart_hal.h"
#endif
#include "panic_internal.h"
#include "esp_private/panic_internal.h"
#include "port/panic_funcs.h"
#include "sdkconfig.h"
@ -302,10 +302,10 @@ void esp_panic_handler(panic_info_t *info)
disable_all_wdts();
s_dumping_core = true;
#if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH
esp_core_dump_to_flash((XtExcFrame*) info->frame);
esp_core_dump_to_flash(info);
#endif
#if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART && !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
esp_core_dump_to_uart((XtExcFrame*) info->frame);
esp_core_dump_to_uart(info);
#endif
s_dumping_core = false;
reconfigure_all_wdts();

View File

@ -47,7 +47,7 @@
#include "soc/rtc_cntl_reg.h"
#endif
#include "panic_internal.h"
#include "esp_private/panic_internal.h"
extern int _invalid_pc_placeholder;
@ -384,6 +384,7 @@ static void frame_to_panic_info(XtExcFrame *frame, panic_info_t *info, bool pseu
info->exception = PANIC_EXCEPTION_FAULT;
info->details = NULL;
info->pseudo_excause = pseudo_excause;
if (pseudo_excause) {
if (frame->exccause == PANIC_RSN_INTWDT_CPU0) {
info->core = 0;

View File

@ -6,7 +6,7 @@
#include "soc/cpu.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "panic_internal.h"
#include "esp_private/panic_internal.h"
#include "esp_rom_uart.h"
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/memprot.h"

View File

@ -53,6 +53,7 @@ else:
CLOSE_FDS = True
INVALID_CAUSE_VALUE = 0xFFFF
XCHAL_EXCCAUSE_NUM = 64
# Exception cause dictionary to get translation of exccause register
# From 4.4.1.5 table 4-64 Exception Causes of Xtensa
@ -88,7 +89,17 @@ xtensa_exception_cause_dict = {
37: ("Coprocessor5Disabled", "Coprocessor 5 instruction when cp5 disabled"),
38: ("Coprocessor6Disabled", "Coprocessor 6 instruction when cp6 disabled"),
39: ("Coprocessor7Disabled", "Coprocessor 7 instruction when cp7 disabled"),
INVALID_CAUSE_VALUE: ("InvalidCauseRegister", "Invalid EXCCAUSE register value or current task is broken and was skipped")}
INVALID_CAUSE_VALUE: ("InvalidCauseRegister", "Invalid EXCCAUSE register value or current task is broken and was skipped"),
# ESP panic pseudo reasons
XCHAL_EXCCAUSE_NUM + 0: ("UnknownException", "Unknown exception"),
XCHAL_EXCCAUSE_NUM + 1: ("DebugException", "Unhandled debug exception"),
XCHAL_EXCCAUSE_NUM + 2: ("DoubleException", "Double exception"),
XCHAL_EXCCAUSE_NUM + 3: ("KernelException", "Unhandled kernel exception"),
XCHAL_EXCCAUSE_NUM + 4: ("CoprocessorException", "Coprocessor exception"),
XCHAL_EXCCAUSE_NUM + 5: ("InterruptWDTTimoutCPU0", "Interrupt wdt timeout on CPU0"),
XCHAL_EXCCAUSE_NUM + 6: ("InterruptWDTTimoutCPU1", "Interrupt wdt timeout on CPU1"),
XCHAL_EXCCAUSE_NUM + 7: ("CacheError", "Cache disabled but cached memory region accessed"),
}
class ESPCoreDumpError(RuntimeError):

View File

@ -17,6 +17,7 @@
#include <stddef.h>
#include "esp_err.h"
#include "freertos/xtensa_context.h"
#include "esp_private/panic_internal.h"
/**************************************************************************************/
/******************************** EXCEPTION MODE API **********************************/
@ -58,7 +59,7 @@ void esp_core_dump_init(void);
* 4) Task's stack is placed after TCB data. Size is (STACK_END - STACK_TOP) bytes.
* 5) CRC is placed at the end of the data.
*/
void esp_core_dump_to_flash(XtExcFrame *frame);
void esp_core_dump_to_flash(panic_info_t *info);
/**
* @brief Print base64-encoded core dump to UART.
@ -68,7 +69,7 @@ void esp_core_dump_to_flash(XtExcFrame *frame);
* 2) Since CRC is omitted TOTAL_LEN does not include its size.
* 3) Printed base64 data are surrounded with special messages to help user recognize the start and end of actual data.
*/
void esp_core_dump_to_uart(XtExcFrame *frame);
void esp_core_dump_to_uart(panic_info_t *info);
/**************************************************************************************/
/*********************************** USER MODE API ************************************/

View File

@ -16,6 +16,6 @@
#include "esp_core_dump_priv.h"
esp_err_t esp_core_dump_write_elf(void *frame, core_dump_write_config_t *write_cfg);
esp_err_t esp_core_dump_write_elf(panic_info_t *info, core_dump_write_config_t *write_cfg);
#endif

View File

@ -56,7 +56,7 @@ bool esp_core_dump_tcb_addr_is_sane(uint32_t addr);
bool esp_core_dump_task_stack_end_is_sane(uint32_t sp);
bool esp_core_dump_mem_seg_is_sane(uint32_t addr, uint32_t sz);
void *esp_core_dump_get_current_task_handle(void);
bool esp_core_dump_check_task(void *frame, core_dump_task_header_t *task_snaphort, bool* is_current, bool* stack_is_valid);
bool esp_core_dump_check_task(panic_info_t *info, core_dump_task_header_t *task_snaphort, bool* is_current, bool* stack_is_valid);
bool esp_core_dump_check_stack(uint32_t stack_start, uint32_t stack_end);
uint32_t esp_core_dump_get_stack(core_dump_task_header_t* task_snapshot, uint32_t* stk_base, uint32_t* stk_len);

View File

@ -11,8 +11,8 @@
// 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.
#ifndef ESP_CORE_DUMP_H_
#define ESP_CORE_DUMP_H_
#ifndef ESP_CORE_DUMP_PRIV_H_
#define ESP_CORE_DUMP_PRIV_H_
#ifdef __cplusplus
extern "C" {
@ -23,6 +23,7 @@ extern "C" {
#include "esp_log.h"
#include "esp_rom_sys.h"
#include "sdkconfig.h"
#include "esp_private/panic_internal.h"
#if CONFIG_ESP32_COREDUMP_CHECKSUM_SHA256
// TODO: move this to portable part of the code
#include "mbedtls/sha256.h"
@ -138,7 +139,7 @@ typedef struct _core_dump_mem_seg_header_t
void esp_core_dump_flash_init(void);
// Common core dump write function
void esp_core_dump_write(void *frame, core_dump_write_config_t *write_cfg);
void esp_core_dump_write(panic_info_t *info, core_dump_write_config_t *write_cfg);
#include "esp_core_dump_port.h"

View File

@ -14,7 +14,6 @@
#include <string.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_core_dump_priv.h"
#include "core_dump_elf.h"
const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_common";
@ -100,7 +99,7 @@ static esp_err_t esp_core_dump_save_mem_segment(core_dump_write_config_t* write_
return ESP_OK;
}
static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_t *write_cfg)
static esp_err_t esp_core_dump_write_binary(panic_info_t *info, core_dump_write_config_t *write_cfg)
{
esp_err_t err;
static core_dump_task_header_t *tasks[CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM];
@ -117,7 +116,7 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
for (task_id = 0; task_id < task_num; task_id++) {
bool is_current_task = false, stack_is_valid = false;
bool tcb_is_valid = esp_core_dump_check_task(frame, tasks[task_id], &is_current_task, &stack_is_valid);
bool tcb_is_valid = esp_core_dump_check_task(info, tasks[task_id], &is_current_task, &stack_is_valid);
// Check if task tcb or stack is corrupted
if (!tcb_is_valid || !stack_is_valid) {
// If tcb or stack for task is corrupted count task as broken
@ -142,7 +141,7 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
interrupted_task_stack.size = esp_core_dump_get_memory_len(tasks[curr_task_index]->stack_start, tasks[curr_task_index]->stack_end);
// size of the task's stack has been already taken into account, also addresses have also been checked
data_len += sizeof(core_dump_mem_seg_header_t);
tasks[curr_task_index]->stack_start = (uint32_t)frame;
tasks[curr_task_index]->stack_start = (uint32_t)info->frame;
tasks[curr_task_index]->stack_end = esp_core_dump_get_isr_stack_end();
ESP_COREDUMP_LOG_PROCESS("Add ISR stack %lu to %lu", tasks[curr_task_index]->stack_end - tasks[curr_task_index]->stack_start, data_len);
// take into account size of the ISR stack
@ -199,7 +198,7 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
hdr.version = COREDUMP_VERSION;
hdr.tasks_num = task_num; // save all the tasks in snapshot even broken
hdr.mem_segs_num = 0;
if (xPortInterruptedFromISRContext()) {
if (esp_core_dump_in_isr_context()) {
hdr.mem_segs_num++; // stack of interrupted task
}
hdr.mem_segs_num += esp_core_dump_get_user_ram_segments(); // stack of user mapped memory
@ -231,7 +230,7 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
return err;
}
}
if (xPortInterruptedFromISRContext()) {
if (esp_core_dump_in_isr_context()) {
err = esp_core_dump_save_mem_segment(write_cfg, &interrupted_task_stack);
if (err != ESP_OK) {
ESP_COREDUMP_LOGE("Failed to save interrupted task stack, error=%d!", err);
@ -279,16 +278,16 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
#endif
inline void esp_core_dump_write(void *frame, core_dump_write_config_t *write_cfg)
inline void esp_core_dump_write(panic_info_t *info, core_dump_write_config_t *write_cfg)
{
esp_core_dump_setup_stack();
#ifndef CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE
esp_err_t err = ESP_ERR_NOT_SUPPORTED;
#if CONFIG_ESP32_COREDUMP_DATA_FORMAT_BIN
err = esp_core_dump_write_binary(frame, write_cfg);
err = esp_core_dump_write_binary(info, write_cfg);
#elif CONFIG_ESP32_COREDUMP_DATA_FORMAT_ELF
err = esp_core_dump_write_elf(frame, write_cfg);
err = esp_core_dump_write_elf(info, write_cfg);
#endif
if (err != ESP_OK) {
ESP_COREDUMP_LOGE("Core dump write binary failed with error=%d", err);

View File

@ -325,7 +325,7 @@ static int elf_get_current_task_index(core_dump_task_header_t** tasks,
return curr_task_index;
}
static int elf_process_task_regdump(core_dump_elf_t *self, void *frame, core_dump_task_header_t *task)
static int elf_process_task_regdump(core_dump_elf_t *self, panic_info_t *info, core_dump_task_header_t *task)
{
bool task_is_valid = false;
bool task_is_current = false;
@ -334,7 +334,7 @@ static int elf_process_task_regdump(core_dump_elf_t *self, void *frame, core_dum
if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
// Check if task tcb is corrupted (do not update the header, save as is)
task_is_valid = esp_core_dump_check_task(frame, task, &task_is_current, NULL);
task_is_valid = esp_core_dump_check_task(info, task, &task_is_current, NULL);
if (!task_is_valid) {
if (task_is_current) {
ESP_COREDUMP_LOG_PROCESS("Task has incorrect (TCB:%x)!",
@ -417,7 +417,7 @@ static int elf_process_note_segment(core_dump_elf_t *self, int notes_size)
return (int)notes_size;
}
static int elf_process_tasks_regs(core_dump_elf_t *self, void* frame,
static int elf_process_tasks_regs(core_dump_elf_t *self, panic_info_t *info,
core_dump_task_header_t** tasks,
uint32_t task_num)
{
@ -430,7 +430,7 @@ static int elf_process_tasks_regs(core_dump_elf_t *self, void* frame,
}
// place current task dump first
int ret = elf_process_task_regdump(self, frame, tasks[curr_task_index]);
int ret = elf_process_task_regdump(self, info, tasks[curr_task_index]);
if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
// when writing segments headers this function writes nothing
ELF_CHECK_ERR((ret >= 0), ret, "Task #%d, PR_STATUS write failed, return (%d).", curr_task_index, ret);
@ -446,7 +446,7 @@ static int elf_process_tasks_regs(core_dump_elf_t *self, void* frame,
if (task_id == curr_task_index) {
continue; // skip current task (already processed)
}
ret = elf_process_task_regdump(self, frame, tasks[task_id]);
ret = elf_process_task_regdump(self, info, tasks[task_id]);
if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
// when writing segments headers this function writes nothing
ELF_CHECK_ERR((ret >= 0), ret, "Task #%d, PR_STATUS write failed, return (%d).", task_id, ret);
@ -467,8 +467,8 @@ static int elf_process_tasks_regs(core_dump_elf_t *self, void* frame,
self->interrupted_task.stack_start = tasks[curr_task_index]->stack_start;
self->interrupted_task.stack_end = tasks[curr_task_index]->stack_end;
uint32_t isr_stk_end = esp_core_dump_get_isr_stack_end();
ESP_COREDUMP_LOG_PROCESS("Add ISR stack %lu (%x - %x)", isr_stk_end - (uint32_t)frame, (uint32_t)frame, isr_stk_end);
tasks[curr_task_index]->stack_start = (uint32_t)frame;
ESP_COREDUMP_LOG_PROCESS("Add ISR stack %lu (%x - %x)", isr_stk_end - (uint32_t)info->frame, (uint32_t)info->frame, isr_stk_end);
tasks[curr_task_index]->stack_start = (uint32_t)info->frame;
tasks[curr_task_index]->stack_end = isr_stk_end;
}
@ -480,7 +480,7 @@ static int elf_process_tasks_regs(core_dump_elf_t *self, void* frame,
return ret;
}
static int elf_write_tasks_data(core_dump_elf_t *self, void* frame,
static int elf_write_tasks_data(core_dump_elf_t *self, panic_info_t *info,
core_dump_task_header_t** tasks,
uint32_t task_num)
{
@ -488,9 +488,9 @@ static int elf_write_tasks_data(core_dump_elf_t *self, void* frame,
int task_id;
int ret = ELF_PROC_ERR_OTHER;
ELF_CHECK_ERR((frame && tasks), ELF_PROC_ERR_OTHER, "Invalid input data.");
ELF_CHECK_ERR((info && tasks), ELF_PROC_ERR_OTHER, "Invalid input data.");
ret = elf_process_tasks_regs(self, frame, tasks, task_num);
ret = elf_process_tasks_regs(self, info, tasks, task_num);
ELF_CHECK_ERR((ret > 0), ret, "Tasks regs addition failed, return (%d).", ret);
elf_len += ret;
self->bad_tasks_num = 0; // reset bad task counter
@ -572,7 +572,7 @@ static int elf_write_core_dump_info(core_dump_elf_t *self)
return ret;
}
static int esp_core_dump_do_write_elf_pass(core_dump_elf_t *self, void* frame,
static int esp_core_dump_do_write_elf_pass(core_dump_elf_t *self, panic_info_t *info,
core_dump_task_header_t** tasks,
uint32_t task_num)
{
@ -586,7 +586,7 @@ static int esp_core_dump_do_write_elf_pass(core_dump_elf_t *self, void* frame,
}
tot_len += data_sz;
// Calculate whole size include headers for all tasks and main elf header
data_sz = elf_write_tasks_data(self, frame, tasks, task_num);
data_sz = elf_write_tasks_data(self, info, tasks, task_num);
ELF_CHECK_ERR((data_sz > 0), data_sz, "ELF Size writing error, returned (%d).", data_sz);
tot_len += data_sz;
@ -604,7 +604,7 @@ static int esp_core_dump_do_write_elf_pass(core_dump_elf_t *self, void* frame,
return tot_len;
}
esp_err_t esp_core_dump_write_elf(void *frame, core_dump_write_config_t *write_cfg)
esp_err_t esp_core_dump_write_elf(panic_info_t *info, core_dump_write_config_t *write_cfg)
{
esp_err_t err = ESP_OK;
static core_dump_task_header_t *tasks[CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM];
@ -614,7 +614,7 @@ esp_err_t esp_core_dump_write_elf(void *frame, core_dump_write_config_t *write_c
int tot_len = sizeof(dump_hdr);
int write_len = sizeof(dump_hdr);
ELF_CHECK_ERR((frame && write_cfg), ESP_ERR_INVALID_ARG, "Invalid input data.");
ELF_CHECK_ERR((info && write_cfg), ESP_ERR_INVALID_ARG, "Invalid input data.");
task_num = esp_core_dump_get_tasks_snapshot(tasks, CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM);
ESP_COREDUMP_LOGI("Found tasks: %d", task_num);
@ -625,7 +625,7 @@ esp_err_t esp_core_dump_write_elf(void *frame, core_dump_write_config_t *write_c
// On first pass (do not write actual data), but calculate data length needed to allocate memory
self.elf_stage = ELF_STAGE_CALC_SPACE;
ESP_COREDUMP_LOG_PROCESS("================= Calc data size ===============");
int ret = esp_core_dump_do_write_elf_pass(&self, frame, tasks, task_num);
int ret = esp_core_dump_do_write_elf_pass(&self, info, tasks, task_num);
if (ret < 0) return ret;
tot_len += ret;
ESP_COREDUMP_LOG_PROCESS("Core dump tot_len=%lu, tasks processed: %d, broken tasks: %d",
@ -671,7 +671,7 @@ esp_err_t esp_core_dump_write_elf(void *frame, core_dump_write_config_t *write_c
self.elf_stage = ELF_STAGE_PLACE_HEADERS;
// set initial offset to elf segments data area
self.elf_next_data_offset = sizeof(elfhdr) + ELF_SEG_HEADERS_COUNT(&self, task_num) * sizeof(elf_phdr);
ret = esp_core_dump_do_write_elf_pass(&self, frame, tasks, task_num);
ret = esp_core_dump_do_write_elf_pass(&self, info, tasks, task_num);
if (ret < 0) return ret;
write_len += ret;
ESP_COREDUMP_LOG_PROCESS("============== Headers size = %d bytes ============", write_len);
@ -679,7 +679,7 @@ esp_err_t esp_core_dump_write_elf(void *frame, core_dump_write_config_t *write_c
self.elf_stage = ELF_STAGE_PLACE_DATA;
// set initial offset to elf segments data area, this is not necessary in this stage, just for pretty debug output
self.elf_next_data_offset = sizeof(elfhdr) + ELF_SEG_HEADERS_COUNT(&self, task_num) * sizeof(elf_phdr);
ret = esp_core_dump_do_write_elf_pass(&self, frame, tasks, task_num);
ret = esp_core_dump_do_write_elf_pass(&self, info, tasks, task_num);
if (ret < 0) return ret;
write_len += ret;
ESP_COREDUMP_LOG_PROCESS("=========== Data written size = %d bytes ==========", write_len);

View File

@ -222,7 +222,7 @@ static esp_err_t esp_core_dump_flash_write_end(void *priv)
return err;
}
void esp_core_dump_to_flash(void *frame)
void esp_core_dump_to_flash(panic_info_t *info)
{
static core_dump_write_config_t wr_cfg;
static core_dump_write_data_t wr_data;
@ -250,7 +250,7 @@ void esp_core_dump_to_flash(void *frame)
wr_cfg.priv = &wr_data;
ESP_COREDUMP_LOGI("Save core dump to flash...");
esp_core_dump_write(frame, &wr_cfg);
esp_core_dump_write(info, &wr_cfg);
ESP_COREDUMP_LOGI("Core dump has been saved to flash.");
}

View File

@ -455,12 +455,12 @@ inline void* esp_core_dump_get_current_task_handle()
return (void*)xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID());
}
bool esp_core_dump_check_task(void *frame,
bool esp_core_dump_check_task(panic_info_t *info,
core_dump_task_header_t *task,
bool* is_current,
bool* stack_is_valid)
{
XtExcFrame *exc_frame = frame;
XtExcFrame *exc_frame = (XtExcFrame *)info->frame;
bool is_curr_task = false;
bool stack_is_sane = false;
uint32_t stk_size = 0;
@ -478,6 +478,9 @@ bool esp_core_dump_check_task(void *frame,
task->stack_start = (uint32_t)exc_frame;
}
exc_frame->exit = COREDUMP_CURR_TASK_MARKER;
if (info->pseudo_excause) {
exc_frame->exccause += XCHAL_EXCCAUSE_NUM;
}
s_extra_info.crashed_task_tcb = (uint32_t)task->tcb_addr;
}

View File

@ -129,7 +129,7 @@ static int esp_core_dump_uart_get_char(void) {
return i;
}
void esp_core_dump_to_uart(XtExcFrame *frame)
void esp_core_dump_to_uart(panic_info_t *info)
{
core_dump_write_config_t wr_cfg;
core_dump_write_data_t wr_data;
@ -162,7 +162,7 @@ void esp_core_dump_to_uart(XtExcFrame *frame)
ch = esp_core_dump_uart_get_char();
}
ESP_COREDUMP_LOGI("Print core dump to uart...");
esp_core_dump_write((void*)frame, &wr_cfg);
esp_core_dump_write(info, &wr_cfg);
ESP_COREDUMP_LOGI("Core dump has been written to uart.");
}