mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-30 02:37:19 +02:00
core dump update
This commit is contained in:
@ -28,8 +28,11 @@
|
||||
#define REG_SAVE_AREA_SIZE (SPECREG_OFFSET + SPECREG_SIZE)
|
||||
|
||||
.data
|
||||
.global _l4_intr_stack
|
||||
.global _l4_intr_stack_end
|
||||
_l4_intr_stack:
|
||||
.space L4_INTR_STACK_SIZE
|
||||
_l4_intr_stack_end:
|
||||
|
||||
_l4_save_ctx:
|
||||
.space REG_SAVE_AREA_SIZE
|
||||
|
File diff suppressed because it is too large
Load Diff
5
components/espcoredump/include/esp_core_dump.h
Normal file → Executable file
5
components/espcoredump/include/esp_core_dump.h
Normal file → Executable file
@ -86,9 +86,6 @@ void esp_core_dump_to_uart(XtExcFrame *frame);
|
||||
*/
|
||||
esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size);
|
||||
|
||||
typedef uint32_t (*log_dump_get_len_t)(void);
|
||||
typedef int * (*log_dump_get_ptr_t)(void);
|
||||
|
||||
bool esp_log_dump_init(log_dump_get_len_t g_len, log_dump_get_ptr_t g_ptr);
|
||||
bool esp_log_dump_init(uint32_t (*get_len)(void), int * (*get_ptr)(void));
|
||||
|
||||
#endif
|
||||
|
28
components/espcoredump/include_core_dump/esp_core_dump_priv.h
Normal file → Executable file
28
components/espcoredump/include_core_dump/esp_core_dump_priv.h
Normal file → Executable file
@ -11,12 +11,13 @@
|
||||
// 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_PRIV_H_
|
||||
#define ESP_CORE_DUMP_PRIV_H_
|
||||
#ifndef ESP_CORE_DUMP_H_
|
||||
#define ESP_CORE_DUMP_H_
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "sdkconfig.h"
|
||||
//#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
|
||||
#include "esp_log.h"
|
||||
|
||||
#define ESP_COREDUMP_LOG( level, format, ... ) if (LOG_LOCAL_LEVEL >= level) { ets_printf(DRAM_STR(format), esp_log_early_timestamp(), (const char *)TAG, ##__VA_ARGS__); }
|
||||
@ -33,7 +34,7 @@
|
||||
#endif
|
||||
|
||||
#define COREDUMP_MAX_TASK_STACK_SIZE (64*1024)
|
||||
#define COREDUMP_VERSION 2
|
||||
#define COREDUMP_VERSION 0x0002
|
||||
|
||||
typedef uint32_t core_dump_crc_t;
|
||||
|
||||
@ -69,6 +70,7 @@ typedef struct _core_dump_header_t
|
||||
uint32_t version; // core dump struct version
|
||||
uint32_t tasks_num; // number of tasks
|
||||
uint32_t tcb_sz; // size of TCB
|
||||
uint32_t mem_segs_num; // number of memory segments
|
||||
} core_dump_header_t;
|
||||
|
||||
/** core dump task data header */
|
||||
@ -79,6 +81,13 @@ typedef struct _core_dump_task_header_t
|
||||
uint32_t stack_end; // stack end address
|
||||
} core_dump_task_header_t;
|
||||
|
||||
/** core dump memory segment header */
|
||||
typedef struct _core_dump_mem_seg_header_t
|
||||
{
|
||||
uint32_t start; // memory region start address
|
||||
uint32_t size; // memory region size
|
||||
} core_dump_mem_seg_header_t;
|
||||
|
||||
typedef struct _core_dump_log_header_t
|
||||
{
|
||||
uint32_t len; //bytes
|
||||
@ -97,14 +106,21 @@ void esp_core_dump_write(void *frame, core_dump_write_config_t *write_cfg);
|
||||
|
||||
// Gets RTOS tasks snapshot
|
||||
uint32_t esp_core_dump_get_tasks_snapshot(core_dump_task_header_t* const tasks,
|
||||
const uint32_t snapshot_size, uint32_t* const tcb_sz);
|
||||
const uint32_t snapshot_size);
|
||||
|
||||
// Checks TCB consistency
|
||||
bool esp_tcb_addr_is_sane(uint32_t addr, uint32_t sz);
|
||||
bool esp_core_dump_mem_seg_is_sane(uint32_t addr, uint32_t sz);
|
||||
|
||||
bool esp_core_dump_process_tcb(void *frame, core_dump_task_header_t *task_snaphort, uint32_t tcb_sz);
|
||||
bool esp_core_dump_process_tcb(void *frame, core_dump_task_header_t *task_snaphort, bool *is_curr_task);
|
||||
|
||||
bool esp_core_dump_process_stack(core_dump_task_header_t* task_snaphort, uint32_t *length);
|
||||
uint32_t esp_core_dump_get_stack(core_dump_task_header_t *task_snapshot, uint32_t *stk_len);
|
||||
bool esp_core_dump_check_in_bt_isr(int sp);
|
||||
|
||||
#define esp_core_dump_in_isr_context() xPortInterruptedFromISRContext()
|
||||
uint32_t esp_core_dump_get_isr_stack_end(void);
|
||||
|
||||
#define COREDUMP_TCB_SIZE sizeof(StaticTask_t)
|
||||
|
||||
bool esp_core_dump_process_log(core_dump_log_header_t *log);
|
||||
|
||||
|
212
components/espcoredump/src/core_dump_common.c
Normal file → Executable file
212
components/espcoredump/src/core_dump_common.c
Normal file → Executable file
@ -22,35 +22,99 @@ const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_commo
|
||||
|
||||
#if CONFIG_ESP32_ENABLE_COREDUMP
|
||||
|
||||
static inline uint32_t esp_core_dump_get_tcb_len(void)
|
||||
{
|
||||
if (COREDUMP_TCB_SIZE % sizeof(uint32_t)) {
|
||||
return ((COREDUMP_TCB_SIZE / sizeof(uint32_t) + 1) * sizeof(uint32_t));
|
||||
}
|
||||
return COREDUMP_TCB_SIZE;
|
||||
}
|
||||
|
||||
static inline uint32_t esp_core_dump_get_stack_len(uint32_t stack_start, uint32_t stack_end)
|
||||
{
|
||||
uint32_t len = stack_end - stack_start;
|
||||
// Take stack padding into account
|
||||
return (len + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1);
|
||||
}
|
||||
|
||||
static esp_err_t esp_core_dump_save_task(core_dump_write_config_t *write_cfg,
|
||||
core_dump_task_header_t *task)
|
||||
{
|
||||
uint32_t stk_paddr, stk_len;
|
||||
|
||||
if (task->tcb_addr == 0) {
|
||||
ESP_COREDUMP_LOG_PROCESS("Skip task with bad TCB addr!");
|
||||
return ESP_OK; // skip
|
||||
}
|
||||
ESP_COREDUMP_LOG_PROCESS("Dump task %x", task->tcb_addr);
|
||||
int err = write_cfg->write(write_cfg->priv, task, sizeof(*task));
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to write task header (%d)!", err);
|
||||
return err;
|
||||
}
|
||||
// Save TCB
|
||||
err = write_cfg->write(write_cfg->priv, task->tcb_addr, esp_core_dump_get_tcb_len());
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to write TCB (%d)!", err);
|
||||
return err;
|
||||
}
|
||||
stk_paddr = esp_core_dump_get_stack(task, &stk_len);
|
||||
stk_len = esp_core_dump_get_stack_len(stk_paddr, stk_paddr+stk_len);
|
||||
// Save task stack
|
||||
err = write_cfg->write(write_cfg->priv, (void *)stk_paddr, stk_len);
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to write task stack (%d)!", err);
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_core_dump_save_mem_segment(core_dump_write_config_t* write_cfg,
|
||||
core_dump_mem_seg_header_t* seg)
|
||||
{
|
||||
esp_err_t err = ESP_FAIL;
|
||||
|
||||
if (!esp_core_dump_mem_seg_is_sane(seg->start, seg->size)) {
|
||||
ESP_COREDUMP_LOG_PROCESS("Skip invalid memory segment, (%x, %lu)!",
|
||||
seg->start, seg->size);
|
||||
return ESP_OK;
|
||||
}
|
||||
// Save mem segment header
|
||||
err = write_cfg->write(write_cfg->priv, (void*)seg, sizeof(core_dump_mem_seg_header_t));
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to write memory segment header, error=%d!", err);
|
||||
return err;
|
||||
}
|
||||
// Save memory contents
|
||||
err = write_cfg->write(write_cfg->priv, (void*)seg->start, seg->size);
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to write memory segment, (%x, %lu), error=%d!",
|
||||
seg->start, seg->size, err);
|
||||
return err;
|
||||
}
|
||||
ESP_COREDUMP_LOG_PROCESS("Memory segment (%x, %lu) is saved.",
|
||||
seg->start, seg->size);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_core_dump_write_binary(void *frame, 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];
|
||||
uint32_t tcb_sz, task_num, tcb_sz_padded;
|
||||
bool task_is_valid = false;
|
||||
uint32_t data_len = 0, i;
|
||||
union
|
||||
{
|
||||
core_dump_header_t hdr;
|
||||
core_dump_task_header_t task_hdr;
|
||||
} dump_data;
|
||||
union {
|
||||
uint32_t i32[128];
|
||||
char str[512];
|
||||
} iram_str;
|
||||
uint32_t task_num, tcb_sz_padded;
|
||||
bool task_is_valid = false, is_current_task;
|
||||
uint32_t data_len = 0, i, curr_task_idx = (uint32_t)-1, good_task_idx = (uint32_t)-1;
|
||||
core_dump_header_t hdr;
|
||||
core_dump_mem_seg_header_t interrupted_task_stack = {.start = 0, .size = 0};
|
||||
|
||||
task_num = esp_core_dump_get_tasks_snapshot(tasks, CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM, &tcb_sz);
|
||||
task_num = esp_core_dump_get_tasks_snapshot(tasks, CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM);
|
||||
ESP_COREDUMP_LOGI("Found tasks: (%d)!", task_num);
|
||||
|
||||
// Take TCB padding into account, actual TCB size will be stored in header
|
||||
if (tcb_sz % sizeof(uint32_t))
|
||||
tcb_sz_padded = (tcb_sz / sizeof(uint32_t) + 1) * sizeof(uint32_t);
|
||||
else
|
||||
tcb_sz_padded = tcb_sz;
|
||||
tcb_sz_padded = esp_core_dump_get_tcb_len();
|
||||
|
||||
// Verifies all tasks in the snapshot
|
||||
for (i = 0; i < task_num; i++) {
|
||||
task_is_valid = esp_core_dump_process_tcb(frame, &tasks[i], tcb_sz);
|
||||
task_is_valid = esp_core_dump_process_tcb(frame, &tasks[i], &is_current_task);
|
||||
// Check if task tcb is corrupted
|
||||
if (!task_is_valid) {
|
||||
write_cfg->bad_tasks_num++;
|
||||
@ -58,22 +122,54 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
|
||||
} else {
|
||||
data_len += (tcb_sz_padded + sizeof(core_dump_task_header_t));
|
||||
}
|
||||
if (is_current_task) {
|
||||
curr_task_idx = i;
|
||||
ESP_COREDUMP_LOGI("Task #%d (TCB:%x) is crashed task.",
|
||||
i, tasks[i].tcb_addr);
|
||||
}
|
||||
uint32_t len = 0;
|
||||
task_is_valid = esp_core_dump_process_stack(&tasks[i], &len);
|
||||
if (task_is_valid) {
|
||||
// Increase core dump size by task stack size
|
||||
data_len += len;
|
||||
data_len += esp_core_dump_get_stack_len(tasks[i].stack_start, tasks[i].stack_end);
|
||||
ESP_COREDUMP_LOG_PROCESS("Core dump stack,i = %d, len = %d data_len=%d", i, len, data_len);
|
||||
good_task_idx = i;
|
||||
} else {
|
||||
// If task tcb is ok but stack is corrupted
|
||||
write_cfg->bad_tasks_num++;
|
||||
data_len -= (tcb_sz_padded + sizeof(core_dump_task_header_t));
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_task_idx == (uint32_t)-1) {
|
||||
curr_task_idx = good_task_idx;
|
||||
}
|
||||
assert((curr_task_idx != (uint32_t)-1) && "No any good task in the system!");
|
||||
XtExcFrame * exc_frame =(XtExcFrame *)frame;
|
||||
if (esp_core_dump_in_isr_context() || esp_core_dump_check_in_bt_isr(exc_frame->a1)) {
|
||||
interrupted_task_stack.start = tasks[curr_task_idx].stack_start;
|
||||
interrupted_task_stack.size = esp_core_dump_get_stack_len(tasks[curr_task_idx].stack_start, tasks[curr_task_idx].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_idx].stack_start = (uint32_t)frame;
|
||||
if (esp_core_dump_check_in_bt_isr(exc_frame->a1)) {
|
||||
extern uint32_t _l4_intr_stack_end;
|
||||
tasks[curr_task_idx].stack_end = &_l4_intr_stack_end;
|
||||
} else {
|
||||
tasks[curr_task_idx].stack_end = esp_core_dump_get_isr_stack_end();
|
||||
}
|
||||
ESP_COREDUMP_LOG_PROCESS("Add ISR stack %lu bytes [%x..%x]",
|
||||
tasks[curr_task_idx].stack_end - tasks[curr_task_idx].stack_start,
|
||||
tasks[curr_task_idx].stack_start, tasks[curr_task_idx].stack_end);
|
||||
// take into account size of the ISR stack
|
||||
data_len += esp_core_dump_get_stack_len(tasks[curr_task_idx].stack_start, tasks[curr_task_idx].stack_end);
|
||||
}
|
||||
|
||||
core_dump_log_header_t logs = { 0 };
|
||||
if (esp_core_dump_process_log(&logs) == true) {
|
||||
data_len += (logs.len + sizeof(core_dump_log_header_t));
|
||||
}
|
||||
|
||||
ESP_COREDUMP_LOGI("LOG dump len = (%d %p)", logs.len, logs.start);
|
||||
// Add core dump header size
|
||||
data_len += sizeof(core_dump_header_t);
|
||||
ESP_COREDUMP_LOG_PROCESS("Core dump len = %lu (%d %d)", data_len, task_num, write_cfg->bad_tasks_num);
|
||||
@ -95,56 +191,56 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
|
||||
}
|
||||
}
|
||||
// Write header
|
||||
dump_data.hdr.data_len = data_len;
|
||||
dump_data.hdr.version = COREDUMP_VERSION;
|
||||
dump_data.hdr.tasks_num = task_num - write_cfg->bad_tasks_num;
|
||||
dump_data.hdr.tcb_sz = tcb_sz;
|
||||
err = write_cfg->write(write_cfg->priv, &dump_data, sizeof(core_dump_header_t));
|
||||
hdr.data_len = data_len;
|
||||
hdr.version = COREDUMP_VERSION;
|
||||
hdr.tasks_num = task_num - write_cfg->bad_tasks_num;
|
||||
hdr.tcb_sz = COREDUMP_TCB_SIZE;
|
||||
hdr.mem_segs_num = 0;
|
||||
if (interrupted_task_stack.size > 0) {
|
||||
hdr.mem_segs_num++; // stack of interrupted task
|
||||
}
|
||||
err = write_cfg->write(write_cfg->priv, &hdr, sizeof(hdr));
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to write core dump header (%d)!", err);
|
||||
return err;
|
||||
}
|
||||
// save crashed task as the first one
|
||||
err = esp_core_dump_save_task(write_cfg, &tasks[curr_task_idx]);
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to save crashed task #%d (TCB:%x), error=%d!",
|
||||
curr_task_idx, tasks[curr_task_idx].tcb_addr, err);
|
||||
return err;
|
||||
}
|
||||
// Write tasks
|
||||
for (i = 0; i < task_num; i++) {
|
||||
if (!esp_tcb_addr_is_sane((uint32_t)tasks[i].tcb_addr, tcb_sz)) {
|
||||
ESP_COREDUMP_LOG_PROCESS("Skip TCB with bad addr %x!", tasks[i].tcb_addr);
|
||||
if (i == curr_task_idx)
|
||||
continue;
|
||||
}
|
||||
ESP_COREDUMP_LOG_PROCESS("Dump task %x", tasks[i].tcb_addr);
|
||||
// Save TCB address, stack base and stack top addr
|
||||
dump_data.task_hdr.tcb_addr = tasks[i].tcb_addr;
|
||||
dump_data.task_hdr.stack_start = tasks[i].stack_start;
|
||||
dump_data.task_hdr.stack_end = tasks[i].stack_end;
|
||||
err = write_cfg->write(write_cfg->priv, (void*)&dump_data, sizeof(core_dump_task_header_t));
|
||||
err = esp_core_dump_save_task(write_cfg, &tasks[i]);
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to write task header (%d)!", err);
|
||||
ESP_COREDUMP_LOGE("Failed to save core dump task #%d (TCB:%x), error=%d!",
|
||||
i, tasks[i].tcb_addr, err);
|
||||
return err;
|
||||
}
|
||||
// Save TCB
|
||||
err = write_cfg->write(write_cfg->priv, tasks[i].tcb_addr, tcb_sz);
|
||||
}
|
||||
if (interrupted_task_stack.size > 0) {
|
||||
err = esp_core_dump_save_mem_segment(write_cfg, &interrupted_task_stack);
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to write TCB (%d)!", err);
|
||||
ESP_COREDUMP_LOGE("Failed to save interrupted task stack, error=%d!", err);
|
||||
return err;
|
||||
}
|
||||
// Save task stack
|
||||
if (tasks[i].stack_start != 0 && tasks[i].stack_end != 0) {
|
||||
err = write_cfg->write(write_cfg->priv, (void*)tasks[i].stack_start,
|
||||
tasks[i].stack_end - tasks[i].stack_start);
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to write task stack (%d)!", err);
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
ESP_COREDUMP_LOG_PROCESS("Skip corrupted task %x stack!", tasks[i].tcb_addr);
|
||||
}
|
||||
}
|
||||
|
||||
err = write_cfg->write(write_cfg->priv, (void*)&logs, sizeof(core_dump_log_header_t));
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to write LOG Header (%d)!", err);
|
||||
return err;
|
||||
}
|
||||
union {
|
||||
uint32_t i32[128];
|
||||
char str[512];
|
||||
} iram_str;
|
||||
|
||||
if (logs.len > 0 && logs.start != NULL) {
|
||||
err = write_cfg->write(write_cfg->priv, (void*)&logs, sizeof(core_dump_log_header_t));
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to save log, error=%d!", err);
|
||||
return err;
|
||||
}
|
||||
for (int i = 0; i < logs.len / 512; i++) {
|
||||
for (int j = 0; j < 128; j++) {
|
||||
if (i * 128 + j < logs.len / 4) {
|
||||
@ -153,12 +249,6 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_
|
||||
}
|
||||
err = write_cfg->write(write_cfg->priv, (void*)iram_str.str, 512);
|
||||
}
|
||||
|
||||
// err = write_cfg->write(write_cfg->priv, (void*)logs.start, logs.len);
|
||||
// if (err != ESP_OK) {
|
||||
// ESP_COREDUMP_LOGE("Failed to write LOG (%d)!", err);
|
||||
// return err;
|
||||
// }
|
||||
}
|
||||
|
||||
// write end
|
||||
|
168
components/espcoredump/src/core_dump_flash.c
Normal file → Executable file
168
components/espcoredump/src/core_dump_flash.c
Normal file → Executable file
@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include <string.h>
|
||||
#include "esp_ota_ops.h"
|
||||
#include "rom/crc.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_core_dump_priv.h"
|
||||
@ -19,6 +20,18 @@
|
||||
const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_flash";
|
||||
|
||||
#if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH
|
||||
#define DUER_COREDUMP_VALID_NUM 3
|
||||
#define DUER_COREDUMP_MAX_LEN 64*1024
|
||||
#define DUER_CRAB_ELF_SHA256_LEN 64
|
||||
#define DUER_CRAB_ELF_APPNAME_LEN 32
|
||||
|
||||
typedef struct _duer_crab_head_t
|
||||
{
|
||||
uint32_t magic_num;
|
||||
long crash_time;
|
||||
char app_name[DUER_CRAB_ELF_APPNAME_LEN];
|
||||
char elf_sha256[DUER_CRAB_ELF_SHA256_LEN + 1];
|
||||
} __attribute__((__packed__)) duer_crab_head_t;
|
||||
|
||||
typedef struct _core_dump_write_flash_data_t
|
||||
{
|
||||
@ -40,18 +53,51 @@ typedef struct _core_dump_flash_config_t
|
||||
core_dump_partition_t partition;
|
||||
// CRC of core dump partition config
|
||||
core_dump_crc_t partition_config_crc;
|
||||
/*add by zhangjiajie for multiple coredump*/
|
||||
uint8_t exist_coredump_num;
|
||||
/*add end*/
|
||||
} core_dump_flash_config_t;
|
||||
|
||||
// core dump flash data
|
||||
static core_dump_flash_config_t s_core_flash_config;
|
||||
duer_crab_head_t duer_crab_head;
|
||||
|
||||
static inline core_dump_crc_t esp_core_dump_calc_flash_config_crc(void)
|
||||
{
|
||||
return crc32_le(0, (uint8_t const *)&s_core_flash_config.partition, sizeof(s_core_flash_config.partition));
|
||||
}
|
||||
|
||||
static uint32_t esp_core_dump_read_coredump_num(char* valid_num) {
|
||||
esp_err_t err;
|
||||
uint32_t data32 = 0;
|
||||
uint8_t coredump_num = 0;
|
||||
|
||||
*valid_num = 0;
|
||||
do {
|
||||
err = spi_flash_read(s_core_flash_config.partition.start + coredump_num*DUER_COREDUMP_MAX_LEN, &data32, sizeof(uint32_t));
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to read coredump head (%d)!", err);
|
||||
break;
|
||||
}
|
||||
ESP_COREDUMP_LOGI("crab read head data=%x", data32);
|
||||
if ((data32 & 0xffffff00) != 0xa5a5a500) {
|
||||
break;
|
||||
}
|
||||
if ((data32 & 0xff) > DUER_COREDUMP_VALID_NUM) {
|
||||
ESP_COREDUMP_LOGE("Coredump num err[%x]", valid_num);
|
||||
break;
|
||||
}
|
||||
coredump_num ++;
|
||||
} while (coredump_num < DUER_COREDUMP_VALID_NUM);
|
||||
|
||||
*valid_num = coredump_num;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_core_dump_flash_init()
|
||||
{
|
||||
char valid_num = 0;
|
||||
const esp_partition_t *core_part;
|
||||
|
||||
ESP_COREDUMP_LOGI("Init core dump to flash");
|
||||
@ -64,6 +110,22 @@ void esp_core_dump_flash_init()
|
||||
s_core_flash_config.partition.start = core_part->address;
|
||||
s_core_flash_config.partition.size = core_part->size;
|
||||
s_core_flash_config.partition_config_crc = esp_core_dump_calc_flash_config_crc();
|
||||
|
||||
/*add by zhangjiajie for multiple coredump*/
|
||||
memset(&duer_crab_head, 0, sizeof(duer_crab_head));
|
||||
|
||||
/*若只有1个coredump,coredump_num=1 */
|
||||
s_core_flash_config.exist_coredump_num = 0;
|
||||
esp_core_dump_read_coredump_num(&valid_num);
|
||||
s_core_flash_config.exist_coredump_num = valid_num;
|
||||
|
||||
/*save current sha256,avoid access cache when crash*/
|
||||
esp_ota_get_app_elf_sha256(duer_crab_head.elf_sha256, sizeof(duer_crab_head.elf_sha256));
|
||||
ESP_COREDUMP_LOGI("crab sha256:%s", duer_crab_head.elf_sha256);
|
||||
/*save current app name,avoid access cache when crash*/
|
||||
esp_crab_get_app_name(duer_crab_head.app_name, sizeof(duer_crab_head.app_name));
|
||||
ESP_COREDUMP_LOGI("crab appname:%s", duer_crab_head.app_name);
|
||||
/*add end*/
|
||||
}
|
||||
|
||||
static uint32_t esp_core_dump_write_flash_padded(size_t off, uint8_t *data, uint32_t data_size)
|
||||
@ -110,24 +172,31 @@ static esp_err_t esp_core_dump_flash_write_prepare(void *priv, uint32_t *data_le
|
||||
{
|
||||
esp_err_t err;
|
||||
uint32_t sec_num;
|
||||
int total_len = 0;
|
||||
core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv;
|
||||
|
||||
// check for available space in partition
|
||||
if ((*data_len + sizeof(uint32_t)) > s_core_flash_config.partition.size) {
|
||||
ESP_COREDUMP_LOGE("Not enough space to save core dump!");
|
||||
if ((*data_len + sizeof(uint32_t) + sizeof(uint32_t)) > DUER_COREDUMP_MAX_LEN) {
|
||||
ESP_COREDUMP_LOGE("[%d]Not enough space to save core dump!", *data_len);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
// add space for CRC
|
||||
*data_len += sizeof(core_dump_crc_t);
|
||||
total_len = *data_len + sizeof(uint32_t);
|
||||
ESP_COREDUMP_LOGE("total_len: (0x%x)!", total_len);
|
||||
|
||||
memset(wr_data, 0, sizeof(*wr_data));
|
||||
// memset(wr_data, 0, sizeof(*wr_data));
|
||||
/*offset add duer coredump head and sha256*/
|
||||
wr_data->off = DUER_COREDUMP_MAX_LEN * s_core_flash_config.exist_coredump_num + sizeof(duer_crab_head);
|
||||
wr_data->crc = 0;
|
||||
|
||||
sec_num = *data_len / SPI_FLASH_SEC_SIZE;
|
||||
if (*data_len % SPI_FLASH_SEC_SIZE) {
|
||||
/*add coredump head len*/
|
||||
sec_num = total_len / SPI_FLASH_SEC_SIZE;
|
||||
if (total_len % SPI_FLASH_SEC_SIZE) {
|
||||
sec_num++;
|
||||
}
|
||||
assert(sec_num * SPI_FLASH_SEC_SIZE <= s_core_flash_config.partition.size);
|
||||
err = spi_flash_erase_range(s_core_flash_config.partition.start + 0, sec_num * SPI_FLASH_SEC_SIZE);
|
||||
err = spi_flash_erase_range(s_core_flash_config.partition.start + DUER_COREDUMP_MAX_LEN * s_core_flash_config.exist_coredump_num, DUER_COREDUMP_MAX_LEN);
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to erase flash (%d)!", err);
|
||||
return err;
|
||||
@ -153,20 +222,22 @@ static esp_err_t esp_core_dump_flash_write_word(core_dump_write_flash_data_t *wr
|
||||
|
||||
static esp_err_t esp_core_dump_flash_write_start(void *priv)
|
||||
{
|
||||
ets_printf(DRAM_STR("================= CORE DUMP START =================\r\n"));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_core_dump_flash_write_end(void *priv)
|
||||
{
|
||||
ets_printf(DRAM_STR("================= CORE DUMP END =================\r\n"));
|
||||
core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv;
|
||||
#if LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG
|
||||
union
|
||||
{
|
||||
uint8_t data8[16];
|
||||
uint32_t data32[4];
|
||||
uint8_t data8[20];
|
||||
uint32_t data32[5];
|
||||
} rom_data;
|
||||
|
||||
esp_err_t err = spi_flash_read(s_core_flash_config.partition.start + 0, &rom_data, sizeof(rom_data));
|
||||
esp_err_t err = spi_flash_read(s_core_flash_config.partition.start + s_core_flash_config.exist_coredump_num*DUER_COREDUMP_MAX_LEN, &rom_data, sizeof(rom_data));
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Failed to read flash (%d)!", err);
|
||||
return err;
|
||||
@ -179,9 +250,71 @@ static esp_err_t esp_core_dump_flash_write_end(void *priv)
|
||||
#endif
|
||||
// write core dump CRC
|
||||
ESP_COREDUMP_LOG_PROCESS("Dump data CRC = 0x%x", wr_data->crc);
|
||||
return esp_core_dump_flash_write_word(wr_data, wr_data->crc);
|
||||
esp_err_t ret = esp_core_dump_flash_write_word(wr_data, wr_data->crc);
|
||||
if (ESP_OK == ret) {
|
||||
|
||||
duer_crab_head.magic_num = 0xa5a5a500 | (s_core_flash_config.exist_coredump_num + 1);
|
||||
|
||||
ESP_COREDUMP_LOGI("crab magic num:0x%x", duer_crab_head.magic_num);
|
||||
ESP_COREDUMP_LOGI("crab crash time:%d", duer_crab_head.crash_time);
|
||||
ESP_COREDUMP_LOGI("crab app name:%s", duer_crab_head.app_name);
|
||||
ESP_COREDUMP_LOGI("crab sha256:%s", duer_crab_head.elf_sha256);
|
||||
|
||||
ret = spi_flash_write(s_core_flash_config.partition.start + s_core_flash_config.exist_coredump_num*DUER_COREDUMP_MAX_LEN, &duer_crab_head, sizeof(duer_crab_head));
|
||||
if (ESP_OK != ret) {
|
||||
ESP_COREDUMP_LOGE("Failed to write coredump head to flash (%d)!", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
s_core_flash_config.exist_coredump_num++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void baidu_esp_core_dump_b64_encode(const uint8_t *src, uint32_t src_len, uint8_t *dst) {
|
||||
const static char b64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int i = 0, j = 0, a = 0, b = 0, c = 0;
|
||||
|
||||
for (i = j = 0; i < src_len; i += 3) {
|
||||
a = src[i];
|
||||
b = i + 1 >= src_len ? 0 : src[i + 1];
|
||||
c = i + 2 >= src_len ? 0 : src[i + 2];
|
||||
|
||||
dst[j++] = b64[a >> 2];
|
||||
dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
|
||||
if (i + 1 < src_len) {
|
||||
dst[j++] = b64[(b & 0x0F) << 2 | (c >> 6)];
|
||||
}
|
||||
if (i + 2 < src_len) {
|
||||
dst[j++] = b64[c & 0x3F];
|
||||
}
|
||||
}
|
||||
while (j % 4 != 0) {
|
||||
dst[j++] = '=';
|
||||
}
|
||||
dst[j++] = '\0';
|
||||
}
|
||||
static esp_err_t baidu_esp_core_dump_uart_write_data(void * data, uint32_t data_len)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
char buf[64 + 4], *addr = data;
|
||||
char *end = addr + data_len;
|
||||
|
||||
while (addr < end) {
|
||||
size_t len = end - addr;
|
||||
if (len > 48) len = 48;
|
||||
/* Copy to stack to avoid alignment restrictions. */
|
||||
char *tmp = buf + (sizeof(buf) - len);
|
||||
memcpy(tmp, addr, len);
|
||||
baidu_esp_core_dump_b64_encode((const uint8_t *)tmp, len, (uint8_t *)buf);
|
||||
addr += len;
|
||||
ets_printf(DRAM_STR("%s\r\n"), buf);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
static esp_err_t esp_core_dump_flash_write_data(void *priv, void * data, uint32_t data_len)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
@ -195,6 +328,8 @@ static esp_err_t esp_core_dump_flash_write_data(void *priv, void * data, uint32_
|
||||
wr_data->off += len;
|
||||
wr_data->crc = crc32_le(wr_data->crc, data, data_len);
|
||||
|
||||
baidu_esp_core_dump_uart_write_data(data, data_len);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -229,6 +364,19 @@ void esp_core_dump_to_flash(XtExcFrame *frame)
|
||||
wr_cfg.write = esp_core_dump_flash_write_data;
|
||||
wr_cfg.priv = &wr_data;
|
||||
|
||||
duer_crab_head.crash_time = 0;
|
||||
|
||||
ESP_COREDUMP_LOGI("Exist Coredump num [%d]...", s_core_flash_config.exist_coredump_num);
|
||||
if (DUER_COREDUMP_VALID_NUM < s_core_flash_config.exist_coredump_num) {
|
||||
ESP_COREDUMP_LOGE("Coredump is full,exist_coredump_num=[%d]...", s_core_flash_config.exist_coredump_num);
|
||||
return;
|
||||
}
|
||||
/*check that partition can hold next coredump*/
|
||||
if (s_core_flash_config.partition.size < (DUER_COREDUMP_MAX_LEN*(1 + s_core_flash_config.exist_coredump_num))) {
|
||||
ESP_COREDUMP_LOGI("partition can not hold next coredump,num=[%d],flash size=[%d]...", s_core_flash_config.exist_coredump_num, s_core_flash_config.partition.size);
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_COREDUMP_LOGI("Save core dump to flash...");
|
||||
esp_core_dump_write((void*)frame, &wr_cfg);
|
||||
ESP_COREDUMP_LOGI("Core dump has been saved to flash.");
|
||||
|
116
components/espcoredump/src/core_dump_port.c
Normal file → Executable file
116
components/espcoredump/src/core_dump_port.c
Normal file → Executable file
@ -15,41 +15,91 @@
|
||||
#include <stdbool.h>
|
||||
#include "esp_panic.h"
|
||||
#include "esp_core_dump_priv.h"
|
||||
#include "esp_core_dump.h"
|
||||
|
||||
const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_port";
|
||||
|
||||
#if CONFIG_ESP32_ENABLE_COREDUMP
|
||||
|
||||
#define COREDUMP_INVALID_CAUSE_VALUE 0xFFFF
|
||||
#define COREDUMP_FAKE_STACK_START 0x20000000
|
||||
#define COREDUMP_FAKE_STACK_LIMIT 0x30000000
|
||||
|
||||
extern uint8_t port_IntStack;
|
||||
|
||||
static XtExcFrame s_fake_stack_frame = {
|
||||
.pc = (UBaseType_t) COREDUMP_FAKE_STACK_START, // task entrypoint fake_ptr
|
||||
.a0 = (UBaseType_t) 0, // to terminate GDB backtrace
|
||||
.a1 = (UBaseType_t) (COREDUMP_FAKE_STACK_START + sizeof(XtExcFrame)), // physical top of stack frame
|
||||
.exit = (UBaseType_t) 0, // user exception exit dispatcher
|
||||
.ps = (PS_UM | PS_EXCM),
|
||||
.exccause = (UBaseType_t) COREDUMP_INVALID_CAUSE_VALUE,
|
||||
};
|
||||
|
||||
uint32_t s_fake_stacks_num;
|
||||
|
||||
_Static_assert(sizeof(TaskSnapshot_t) == sizeof(core_dump_task_header_t), "FreeRTOS task snapshot binary compatibility issue!");
|
||||
|
||||
// The function creates small fake stack for task as deep as exception frame size
|
||||
// It is required for gdb to take task into account but avoid back trace of stack.
|
||||
// The espcoredump.py script is able to recognize that task is broken
|
||||
static void *esp_core_dump_get_fake_stack(uint32_t *stk_len)
|
||||
{
|
||||
*stk_len = sizeof(s_fake_stack_frame);
|
||||
return (uint8_t*)COREDUMP_FAKE_STACK_START + sizeof(s_fake_stack_frame)*s_fake_stacks_num++;
|
||||
}
|
||||
|
||||
static inline bool esp_task_stack_start_is_sane(uint32_t sp)
|
||||
{
|
||||
return esp_ptr_in_dram((const void*)sp) || esp_ptr_external_ram((const void*)sp);
|
||||
}
|
||||
|
||||
inline bool esp_tcb_addr_is_sane(uint32_t addr, uint32_t sz)
|
||||
static inline bool esp_tcb_addr_is_sane(uint32_t addr)
|
||||
{
|
||||
//TODO: currently core dump supports TCBs in DRAM only, external SRAM not supported yet
|
||||
return !(addr < 0x3ffae000UL || (addr + sz) > 0x40000000UL);
|
||||
return esp_core_dump_mem_seg_is_sane(addr, COREDUMP_TCB_SIZE);
|
||||
}
|
||||
|
||||
inline bool esp_core_dump_mem_seg_is_sane(uint32_t addr, uint32_t sz)
|
||||
{
|
||||
return (esp_ptr_in_dram((const void*)addr) && esp_ptr_in_dram((const void*)(addr + sz))) ||
|
||||
(esp_ptr_external_ram((const void*)addr) && esp_ptr_external_ram((const void*)(addr + sz)));
|
||||
}
|
||||
|
||||
inline uint32_t esp_core_dump_get_isr_stack_end(void)
|
||||
{
|
||||
return (uint32_t)((uint8_t *)&port_IntStack + (xPortGetCoreID()+1)*configISR_STACK_SIZE);
|
||||
}
|
||||
|
||||
uint32_t esp_core_dump_get_tasks_snapshot(core_dump_task_header_t* const tasks,
|
||||
const uint32_t snapshot_size, uint32_t* const tcb_sz)
|
||||
const uint32_t snapshot_size)
|
||||
{
|
||||
uint32_t task_num = (uint32_t)uxTaskGetSnapshotAll((TaskSnapshot_t*)tasks, (UBaseType_t)snapshot_size, (UBaseType_t*)tcb_sz);
|
||||
UBaseType_t tcb_sz; //unused
|
||||
uint32_t task_num = (uint32_t)uxTaskGetSnapshotAll((TaskSnapshot_t*)tasks, (UBaseType_t)snapshot_size, &tcb_sz);
|
||||
return task_num;
|
||||
}
|
||||
|
||||
bool esp_core_dump_process_tcb(void *frame, core_dump_task_header_t *task_snaphort, uint32_t tcb_sz)
|
||||
bool esp_core_dump_check_in_bt_isr(int sp)
|
||||
{
|
||||
extern uint32_t _l4_intr_stack, _l4_intr_stack_end;
|
||||
return (sp > &_l4_intr_stack && sp < &_l4_intr_stack_end) ? true : false;
|
||||
}
|
||||
|
||||
bool esp_core_dump_process_tcb(void *frame, core_dump_task_header_t *task_snaphort, bool *is_curr_task)
|
||||
{
|
||||
XtExcFrame *exc_frame = (XtExcFrame*)frame;
|
||||
|
||||
if (!esp_tcb_addr_is_sane((uint32_t)task_snaphort->tcb_addr, tcb_sz)) {
|
||||
*is_curr_task = false;
|
||||
if (!esp_tcb_addr_is_sane((uint32_t)task_snaphort->tcb_addr)) {
|
||||
ESP_COREDUMP_LOG_PROCESS("Bad TCB addr %x!", task_snaphort->tcb_addr);
|
||||
task_snaphort->tcb_addr = 0;
|
||||
return false;
|
||||
}
|
||||
if (task_snaphort->tcb_addr == xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID())) {
|
||||
// Set correct stack top for current task
|
||||
task_snaphort->stack_start = (uint32_t)exc_frame;
|
||||
*is_curr_task = true;
|
||||
// Set correct stack top for current task; only modify if we came from the task,
|
||||
// and not an ISR that crashed.
|
||||
if (!xPortInterruptedFromISRContext() && !esp_core_dump_check_in_bt_isr(exc_frame->a1)) {
|
||||
task_snaphort->stack_start = (uint32_t)exc_frame;
|
||||
}
|
||||
// This field is not initialized for crashed task, but stack frame has the structure of interrupt one,
|
||||
// so make workaround to allow espcoredump to parse it properly.
|
||||
if (exc_frame->exit == 0)
|
||||
@ -77,44 +127,52 @@ bool esp_core_dump_process_tcb(void *frame, core_dump_task_header_t *task_snapho
|
||||
bool esp_core_dump_process_stack(core_dump_task_header_t* task_snaphort, uint32_t *length)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
bool task_is_valid = false;
|
||||
|
||||
len = (uint32_t)task_snaphort->stack_end - (uint32_t)task_snaphort->stack_start;
|
||||
// Check task's stack
|
||||
if (!esp_stack_ptr_is_sane(task_snaphort->stack_start) ||
|
||||
!esp_task_stack_start_is_sane((uint32_t)task_snaphort->stack_end) ||
|
||||
(task_snaphort->stack_end < task_snaphort->stack_start) ||
|
||||
(len > COREDUMP_MAX_TASK_STACK_SIZE)) {
|
||||
// Check if current task stack corrupted
|
||||
if (task_snaphort->tcb_addr == xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID())) {
|
||||
ESP_COREDUMP_LOG_PROCESS("Crashed task will be skipped!");
|
||||
ESP_COREDUMP_LOG_PROCESS("Crashed task stack is corrupted!");
|
||||
}
|
||||
ESP_COREDUMP_LOG_PROCESS("Corrupted TCB %x: stack len %lu, top %x, end %x!",
|
||||
task_snaphort->tcb_addr, len, task_snaphort->stack_start, task_snaphort->stack_end);
|
||||
task_snaphort->tcb_addr = 0; // make TCB addr invalid to skip it in dump
|
||||
task_is_valid = false;
|
||||
} else {
|
||||
ESP_COREDUMP_LOG_PROCESS("Stack len = %lu (%x %x)", len,
|
||||
task_snaphort->stack_start, task_snaphort->stack_end);
|
||||
// Take stack padding into account
|
||||
*length = (len + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1);
|
||||
task_is_valid = true;
|
||||
task_snaphort->stack_start = (uint32_t)esp_core_dump_get_fake_stack(&len);
|
||||
task_snaphort->stack_end = (uint32_t)(task_snaphort->stack_start + len);
|
||||
}
|
||||
return task_is_valid;
|
||||
ESP_COREDUMP_LOG_PROCESS("Stack len = %lu (%x %x)", len,
|
||||
task_snaphort->stack_start, task_snaphort->stack_end);
|
||||
*length = len;
|
||||
return true;
|
||||
}
|
||||
static log_dump_get_len_t get_len = NULL;
|
||||
static log_dump_get_ptr_t get_ptr = NULL;
|
||||
|
||||
bool esp_log_dump_init(log_dump_get_len_t g_len, log_dump_get_ptr_t g_ptr)
|
||||
uint32_t esp_core_dump_get_stack(core_dump_task_header_t *task_snapshot, uint32_t *stk_len)
|
||||
{
|
||||
get_len = g_len;
|
||||
get_ptr = g_ptr;
|
||||
*stk_len = task_snapshot->stack_end - task_snapshot->stack_start;
|
||||
if (task_snapshot->stack_start >= COREDUMP_FAKE_STACK_START && task_snapshot->stack_start < COREDUMP_FAKE_STACK_LIMIT) {
|
||||
return (uint32_t)&s_fake_stack_frame;
|
||||
}
|
||||
return task_snapshot->stack_start;
|
||||
}
|
||||
|
||||
static uint32_t (*_get_len)(void) = NULL;
|
||||
static int * (*_get_ptr)(void) = NULL;
|
||||
|
||||
bool esp_log_dump_init(uint32_t (*get_len)(void), int * (*get_ptr)(void))
|
||||
{
|
||||
_get_len = get_len;
|
||||
_get_ptr = get_ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool esp_core_dump_process_log(core_dump_log_header_t *log)
|
||||
{
|
||||
if (get_len && get_ptr) {
|
||||
log->len = get_len();
|
||||
log->start = get_ptr();
|
||||
if (_get_len && _get_ptr) {
|
||||
log->len = _get_len();
|
||||
log->start = _get_ptr();
|
||||
return true;
|
||||
} else {
|
||||
log->len = 0;
|
||||
|
Reference in New Issue
Block a user