core dump update

This commit is contained in:
Joseph Tang
2020-07-16 20:49:07 +08:00
committed by maojianxin
parent 1e25c373c1
commit a7840de9d8
7 changed files with 1393 additions and 335 deletions

View File

@ -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
View 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

View 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
View 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
View 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个coredumpcoredump_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
View 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;