mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/core_dump_walk_over_tasks_list' into 'master'
coredump: Adds RTOS snapshot API to walk over tasks lists Closes IDF-541 See merge request espressif/esp-idf!8594
This commit is contained in:
commit
cfe8172e12
@ -16,6 +16,6 @@
|
|||||||
|
|
||||||
#include "esp_core_dump_priv.h"
|
#include "esp_core_dump_priv.h"
|
||||||
|
|
||||||
esp_err_t esp_core_dump_write_elf(panic_info_t *info, core_dump_write_config_t *write_cfg);
|
esp_err_t esp_core_dump_write_elf(core_dump_write_config_t *write_cfg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -35,8 +35,6 @@ extern "C" {
|
|||||||
#define COREDUMP_VERSION_CHIP ESP_CHIP_ID_ESP32S2
|
#define COREDUMP_VERSION_CHIP ESP_CHIP_ID_ESP32S2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define COREDUMP_TCB_SIZE sizeof(StaticTask_t)
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
COREDUMP_MEMORY_DRAM,
|
COREDUMP_MEMORY_DRAM,
|
||||||
COREDUMP_MEMORY_IRAM,
|
COREDUMP_MEMORY_IRAM,
|
||||||
@ -46,20 +44,31 @@ typedef enum {
|
|||||||
COREDUMP_MEMORY_START = COREDUMP_MEMORY_DRAM
|
COREDUMP_MEMORY_START = COREDUMP_MEMORY_DRAM
|
||||||
} coredump_region_t;
|
} coredump_region_t;
|
||||||
|
|
||||||
// Gets RTOS tasks snapshot
|
// RTOS tasks snapshots walk API
|
||||||
uint32_t esp_core_dump_get_tasks_snapshot(core_dump_task_header_t** const tasks,
|
void esp_core_dump_reset_tasks_snapshots_iter(void);
|
||||||
const uint32_t snapshot_size);
|
void *esp_core_dump_get_next_task(void *handle);
|
||||||
|
bool esp_core_dump_get_task_snapshot(void *handle, core_dump_task_header_t *task,
|
||||||
|
core_dump_mem_seg_header_t *interrupted_stack);
|
||||||
|
|
||||||
// Checks TCB consistency
|
|
||||||
bool esp_core_dump_tcb_addr_is_sane(uint32_t addr);
|
|
||||||
// Checks stack address
|
|
||||||
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);
|
bool esp_core_dump_mem_seg_is_sane(uint32_t addr, uint32_t sz);
|
||||||
void *esp_core_dump_get_current_task_handle(void);
|
void *esp_core_dump_get_current_task_handle(void);
|
||||||
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);
|
uint32_t esp_core_dump_get_stack(core_dump_task_header_t* task_snapshot, uint32_t* stk_base, uint32_t* stk_len);
|
||||||
|
|
||||||
|
static inline uint32_t esp_core_dump_get_tcb_len(void)
|
||||||
|
{
|
||||||
|
if (sizeof(StaticTask_t) % sizeof(uint32_t)) {
|
||||||
|
return ((sizeof(StaticTask_t) / sizeof(uint32_t) + 1) * sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
return sizeof(StaticTask_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t esp_core_dump_get_memory_len(uint32_t start, uint32_t end)
|
||||||
|
{
|
||||||
|
uint32_t len = end - start;
|
||||||
|
// Take stack padding into account
|
||||||
|
return (len + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t esp_core_dump_get_arch_id(void);
|
uint16_t esp_core_dump_get_arch_id(void);
|
||||||
uint32_t esp_core_dump_get_task_regs_dump(core_dump_task_header_t *task, void **reg_dump);
|
uint32_t esp_core_dump_get_task_regs_dump(core_dump_task_header_t *task, void **reg_dump);
|
||||||
void esp_core_dump_init_extra_info(void);
|
void esp_core_dump_init_extra_info(void);
|
||||||
@ -82,8 +91,7 @@ int esp_core_dump_sha(mbedtls_sha256_context *ctx,
|
|||||||
#endif
|
#endif
|
||||||
void esp_core_dump_print_checksum(const char* msg, const void* checksum);
|
void esp_core_dump_print_checksum(const char* msg, const void* checksum);
|
||||||
|
|
||||||
#define esp_core_dump_in_isr_context() xPortInterruptedFromISRContext()
|
void esp_core_dump_port_init(panic_info_t *info);
|
||||||
uint32_t esp_core_dump_get_isr_stack_end(void);
|
|
||||||
|
|
||||||
#if CONFIG_ESP_COREDUMP_STACK_SIZE > 0
|
#if CONFIG_ESP_COREDUMP_STACK_SIZE > 0
|
||||||
#if LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG
|
#if LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG
|
||||||
|
@ -113,8 +113,6 @@ typedef struct _core_dump_write_config_t
|
|||||||
esp_core_dump_write_end_t end;
|
esp_core_dump_write_end_t end;
|
||||||
// this function is called to write data chunk
|
// this function is called to write data chunk
|
||||||
esp_core_dump_flash_write_data_t write;
|
esp_core_dump_flash_write_data_t write;
|
||||||
// number of tasks with corrupted TCBs
|
|
||||||
uint32_t bad_tasks_num;
|
|
||||||
// pointer to data which are specific for particular core dump emitter
|
// pointer to data which are specific for particular core dump emitter
|
||||||
void * priv;
|
void * priv;
|
||||||
} core_dump_write_config_t;
|
} core_dump_write_config_t;
|
||||||
|
@ -20,21 +20,6 @@ const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_commo
|
|||||||
|
|
||||||
#if CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN
|
#if CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN
|
||||||
|
|
||||||
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_memory_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,
|
static esp_err_t esp_core_dump_save_task(core_dump_write_config_t *write_cfg,
|
||||||
core_dump_task_header_t *task)
|
core_dump_task_header_t *task)
|
||||||
{
|
{
|
||||||
@ -99,74 +84,67 @@ static esp_err_t esp_core_dump_save_mem_segment(core_dump_write_config_t* write_
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t esp_core_dump_write_binary(panic_info_t *info, core_dump_write_config_t *write_cfg)
|
static esp_err_t esp_core_dump_write_binary(core_dump_write_config_t *write_cfg)
|
||||||
{
|
{
|
||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
static core_dump_task_header_t *tasks[CONFIG_ESP_COREDUMP_MAX_TASKS_NUM];
|
uint32_t tcb_sz = esp_core_dump_get_tcb_len();
|
||||||
uint32_t task_num, tcb_sz = esp_core_dump_get_tcb_len();
|
uint32_t data_len = 0, bad_tasks_num = 0;
|
||||||
uint32_t data_len = 0, task_id;
|
core_dump_header_t hdr = {0};
|
||||||
int curr_task_index = COREDUMP_CURR_TASK_NOT_FOUND;
|
core_dump_task_header_t task_hdr;
|
||||||
core_dump_header_t hdr;
|
core_dump_mem_seg_header_t mem_seg;
|
||||||
core_dump_mem_seg_header_t interrupted_task_stack;
|
void *task = NULL, *cur_task = NULL;
|
||||||
|
|
||||||
task_num = esp_core_dump_get_tasks_snapshot(tasks, CONFIG_ESP_COREDUMP_MAX_TASKS_NUM);
|
|
||||||
ESP_COREDUMP_LOGI("Found tasks: %d!", task_num);
|
|
||||||
|
|
||||||
// Verifies all tasks in the snapshot
|
// Verifies all tasks in the snapshot
|
||||||
|
esp_core_dump_reset_tasks_snapshots_iter();
|
||||||
for (task_id = 0; task_id < task_num; task_id++) {
|
while ((task = esp_core_dump_get_next_task(task))) {
|
||||||
bool is_current_task = false, stack_is_valid = false;
|
if (!esp_core_dump_get_task_snapshot(task, &task_hdr, &mem_seg)) {
|
||||||
bool tcb_is_valid = esp_core_dump_check_task(info, tasks[task_id], &is_current_task, &stack_is_valid);
|
bad_tasks_num++;
|
||||||
// Check if task tcb or stack is corrupted
|
continue;
|
||||||
if (!tcb_is_valid || !stack_is_valid) {
|
|
||||||
// If tcb or stack for task is corrupted count task as broken
|
|
||||||
write_cfg->bad_tasks_num++;
|
|
||||||
}
|
}
|
||||||
if (is_current_task) {
|
hdr.tasks_num++;
|
||||||
curr_task_index = task_id; // save current crashed task index in the snapshot
|
if (task == esp_core_dump_get_current_task_handle()) {
|
||||||
ESP_COREDUMP_LOG_PROCESS("Task #%d (TCB:%x) is first crashed task.",
|
cur_task = task;
|
||||||
task_id,
|
ESP_COREDUMP_LOG_PROCESS("Task %x %x is first crashed task.", cur_task, task_hdr.tcb_addr);
|
||||||
tasks[task_id]->tcb_addr);
|
|
||||||
}
|
}
|
||||||
|
ESP_COREDUMP_LOG_PROCESS("Stack len = %lu (%x %x)", task_hdr.stack_end-task_hdr.stack_start,
|
||||||
|
task_hdr.stack_start, task_hdr.stack_end);
|
||||||
// Increase core dump size by task stack size
|
// Increase core dump size by task stack size
|
||||||
uint32_t stk_vaddr, stk_len;
|
uint32_t stk_vaddr, stk_len;
|
||||||
esp_core_dump_get_stack(tasks[task_id], &stk_vaddr, &stk_len);
|
esp_core_dump_get_stack(&task_hdr, &stk_vaddr, &stk_len);
|
||||||
data_len += esp_core_dump_get_memory_len(stk_vaddr, stk_vaddr+stk_len);
|
data_len += esp_core_dump_get_memory_len(stk_vaddr, stk_vaddr+stk_len);
|
||||||
// Add tcb size
|
// Add tcb size
|
||||||
data_len += (tcb_sz + sizeof(core_dump_task_header_t));
|
data_len += (tcb_sz + sizeof(core_dump_task_header_t));
|
||||||
|
if (mem_seg.size > 0) {
|
||||||
|
ESP_COREDUMP_LOG_PROCESS("Add interrupted task stack %lu bytes @ %x",
|
||||||
|
mem_seg.size, mem_seg.start);
|
||||||
|
data_len += esp_core_dump_get_memory_len(mem_seg.start, mem_seg.start+mem_seg.size);
|
||||||
|
data_len += sizeof(core_dump_mem_seg_header_t);
|
||||||
|
hdr.mem_segs_num++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ESP_COREDUMP_LOGI("Found tasks: good %d, bad %d, mem segs %d", hdr.tasks_num, bad_tasks_num, hdr.mem_segs_num);
|
||||||
if (esp_core_dump_in_isr_context()) {
|
|
||||||
interrupted_task_stack.start = tasks[curr_task_index]->stack_start;
|
|
||||||
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)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
|
|
||||||
data_len += esp_core_dump_get_memory_len(tasks[curr_task_index]->stack_start, tasks[curr_task_index]->stack_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if current task TCB is broken
|
// Check if current task TCB is broken
|
||||||
if (curr_task_index == COREDUMP_CURR_TASK_NOT_FOUND) {
|
if (cur_task == NULL) {
|
||||||
ESP_COREDUMP_LOG_PROCESS("The current crashed task is broken.");
|
ESP_COREDUMP_LOG_PROCESS("The current crashed task is broken.");
|
||||||
curr_task_index = 0;
|
cur_task = esp_core_dump_get_next_task(NULL);
|
||||||
|
if (cur_task == NULL) {
|
||||||
|
ESP_COREDUMP_LOGE("No valid tasks in the system!");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add user memory region header size
|
// Add user memory regions data size
|
||||||
data_len += esp_core_dump_get_user_ram_segments() * sizeof(core_dump_mem_seg_header_t);
|
|
||||||
for (coredump_region_t i = COREDUMP_MEMORY_START; i < COREDUMP_MEMORY_MAX; i++) {
|
for (coredump_region_t i = COREDUMP_MEMORY_START; i < COREDUMP_MEMORY_MAX; i++) {
|
||||||
uint32_t start = 0;
|
uint32_t start = 0;
|
||||||
int data_sz = esp_core_dump_get_user_ram_info(i, &start);
|
int data_sz = esp_core_dump_get_user_ram_info(i, &start);
|
||||||
|
|
||||||
if (data_sz < 0) {
|
if (data_sz < 0) {
|
||||||
ESP_COREDUMP_LOGE("Invalid memory segment size");
|
ESP_COREDUMP_LOGE("Invalid memory segment size!");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data_sz > 0) {
|
if (data_sz > 0) {
|
||||||
data_len += esp_core_dump_get_memory_len(start, start + data_sz);
|
hdr.mem_segs_num++;
|
||||||
|
data_len += sizeof(core_dump_mem_seg_header_t) + esp_core_dump_get_memory_len(start, start + data_sz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +152,7 @@ static esp_err_t esp_core_dump_write_binary(panic_info_t *info, core_dump_write_
|
|||||||
data_len += sizeof(core_dump_header_t);
|
data_len += sizeof(core_dump_header_t);
|
||||||
|
|
||||||
ESP_COREDUMP_LOG_PROCESS("Core dump length=%lu, tasks processed: %d, broken tasks: %d",
|
ESP_COREDUMP_LOG_PROCESS("Core dump length=%lu, tasks processed: %d, broken tasks: %d",
|
||||||
data_len, task_num, write_cfg->bad_tasks_num);
|
data_len, hdr.tasks_num, bad_tasks_num);
|
||||||
// Prepare write
|
// Prepare write
|
||||||
if (write_cfg->prepare) {
|
if (write_cfg->prepare) {
|
||||||
err = write_cfg->prepare(write_cfg->priv, &data_len);
|
err = write_cfg->prepare(write_cfg->priv, &data_len);
|
||||||
@ -196,12 +174,6 @@ static esp_err_t esp_core_dump_write_binary(panic_info_t *info, core_dump_write_
|
|||||||
// Write header
|
// Write header
|
||||||
hdr.data_len = data_len;
|
hdr.data_len = data_len;
|
||||||
hdr.version = COREDUMP_VERSION;
|
hdr.version = COREDUMP_VERSION;
|
||||||
hdr.tasks_num = task_num; // save all the tasks in snapshot even broken
|
|
||||||
hdr.mem_segs_num = 0;
|
|
||||||
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
|
|
||||||
hdr.tcb_sz = tcb_sz;
|
hdr.tcb_sz = tcb_sz;
|
||||||
err = write_cfg->write(write_cfg->priv, &hdr, sizeof(core_dump_header_t));
|
err = write_cfg->write(write_cfg->priv, &hdr, sizeof(core_dump_header_t));
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
@ -209,38 +181,56 @@ static esp_err_t esp_core_dump_write_binary(panic_info_t *info, core_dump_write_
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save tasks
|
||||||
|
esp_core_dump_reset_tasks_snapshots_iter();
|
||||||
// Write first crashed task data first (not always first task in the snapshot)
|
// Write first crashed task data first (not always first task in the snapshot)
|
||||||
err = esp_core_dump_save_task(write_cfg, tasks[curr_task_index]);
|
ESP_COREDUMP_LOGD("Save first crashed task %x", cur_task);
|
||||||
if (err != ESP_OK) {
|
if (esp_core_dump_get_task_snapshot(cur_task, &task_hdr, NULL)) {
|
||||||
ESP_COREDUMP_LOGE("Failed to save first crashed task #%d (TCB:%x), error=%d!",
|
err = esp_core_dump_save_task(write_cfg, &task_hdr);
|
||||||
curr_task_index, tasks[curr_task_index]->tcb_addr, err);
|
if (err != ESP_OK) {
|
||||||
return err;
|
ESP_COREDUMP_LOGE("Failed to save first crashed task %x, error=%d!",
|
||||||
|
task_hdr.tcb_addr, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write all other tasks in the snapshot
|
// Write all other tasks in the snapshot
|
||||||
for (task_id = 0; task_id < task_num; task_id++) {
|
task = NULL;
|
||||||
|
while ((task = esp_core_dump_get_next_task(task))) {
|
||||||
|
if (!esp_core_dump_get_task_snapshot(task, &task_hdr, NULL))
|
||||||
|
continue;
|
||||||
// Skip first crashed task
|
// Skip first crashed task
|
||||||
if (task_id == curr_task_index) {
|
if (task == cur_task) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
err = esp_core_dump_save_task(write_cfg, tasks[task_id]);
|
ESP_COREDUMP_LOGD("Save task %x (TCB:%x, stack:%x..%x)", task, task_hdr.tcb_addr, task_hdr.stack_start, task_hdr.stack_end);
|
||||||
|
err = esp_core_dump_save_task(write_cfg, &task_hdr);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_COREDUMP_LOGE("Failed to save core dump task #%d (TCB:%x), error=%d!",
|
ESP_COREDUMP_LOGE("Failed to save core dump task %x, error=%d!",
|
||||||
task_id, tasks[curr_task_index]->tcb_addr, err);
|
task_hdr.tcb_addr, err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (esp_core_dump_in_isr_context()) {
|
|
||||||
err = esp_core_dump_save_mem_segment(write_cfg, &interrupted_task_stack);
|
// Save interrupted stacks of the tasks
|
||||||
if (err != ESP_OK) {
|
// Actually there can be tasks interrupted at the same time, one on every core including the crashed one.
|
||||||
ESP_COREDUMP_LOGE("Failed to save interrupted task stack, error=%d!", err);
|
task = NULL;
|
||||||
return err;
|
esp_core_dump_reset_tasks_snapshots_iter();
|
||||||
|
while ((task = esp_core_dump_get_next_task(task))) {
|
||||||
|
if (!esp_core_dump_get_task_snapshot(task, &task_hdr, &mem_seg))
|
||||||
|
continue;
|
||||||
|
if (mem_seg.size > 0) {
|
||||||
|
ESP_COREDUMP_LOG_PROCESS("Save interrupted task stack %lu bytes @ %x",
|
||||||
|
mem_seg.size, mem_seg.start);
|
||||||
|
err = esp_core_dump_save_mem_segment(write_cfg, &mem_seg);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_COREDUMP_LOGE("Failed to save interrupted task stack, error=%d!", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// save user memory regions
|
// save user memory regions
|
||||||
if (esp_core_dump_get_user_ram_segments() > 0) {
|
if (esp_core_dump_get_user_ram_segments() > 0) {
|
||||||
core_dump_mem_seg_header_t user_ram_stack_size;
|
|
||||||
for (coredump_region_t i = COREDUMP_MEMORY_START; i < COREDUMP_MEMORY_MAX; i++) {
|
for (coredump_region_t i = COREDUMP_MEMORY_START; i < COREDUMP_MEMORY_MAX; i++) {
|
||||||
uint32_t start = 0;
|
uint32_t start = 0;
|
||||||
int data_sz = esp_core_dump_get_user_ram_info(i, &start);
|
int data_sz = esp_core_dump_get_user_ram_info(i, &start);
|
||||||
@ -251,11 +241,13 @@ static esp_err_t esp_core_dump_write_binary(panic_info_t *info, core_dump_write_
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data_sz > 0) {
|
if (data_sz > 0) {
|
||||||
user_ram_stack_size.start = start;
|
mem_seg.start = start;
|
||||||
user_ram_stack_size.size = esp_core_dump_get_memory_len(start, start + data_sz);;
|
mem_seg.size = esp_core_dump_get_memory_len(start, start + data_sz);;
|
||||||
err = esp_core_dump_save_mem_segment(write_cfg, &user_ram_stack_size);
|
ESP_COREDUMP_LOG_PROCESS("Save user memory region %lu bytes @ %x",
|
||||||
|
mem_seg.size, mem_seg.start);
|
||||||
|
err = esp_core_dump_save_mem_segment(write_cfg, &mem_seg);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_COREDUMP_LOGE("Failed to save user memory data, error=%d!", err);
|
ESP_COREDUMP_LOGE("Failed to save user memory region, error=%d!", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,8 +262,8 @@ static esp_err_t esp_core_dump_write_binary(panic_info_t *info, core_dump_write_
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (write_cfg->bad_tasks_num) {
|
if (bad_tasks_num) {
|
||||||
ESP_COREDUMP_LOGE("Found %d broken tasks!", write_cfg->bad_tasks_num);
|
ESP_COREDUMP_LOGE("Found %d broken tasks!", bad_tasks_num);
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -280,21 +272,21 @@ static esp_err_t esp_core_dump_write_binary(panic_info_t *info, core_dump_write_
|
|||||||
|
|
||||||
inline void esp_core_dump_write(panic_info_t *info, 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_ESP_ENABLE_COREDUMP_TO_NONE
|
||||||
|
|
||||||
#ifndef CONFIG_ESP_COREDUMP_ENABLE_TO_NONE
|
|
||||||
esp_err_t err = ESP_ERR_NOT_SUPPORTED;
|
esp_err_t err = ESP_ERR_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
esp_core_dump_setup_stack();
|
||||||
|
esp_core_dump_port_init(info);
|
||||||
#if CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN
|
#if CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN
|
||||||
err = esp_core_dump_write_binary(info, write_cfg);
|
err = esp_core_dump_write_binary(write_cfg);
|
||||||
#elif CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
|
#elif CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF
|
||||||
err = esp_core_dump_write_elf(info, write_cfg);
|
err = esp_core_dump_write_elf(write_cfg);
|
||||||
#endif
|
#endif
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_COREDUMP_LOGE("Core dump write binary failed with error=%d", err);
|
ESP_COREDUMP_LOGE("Core dump write binary failed with error=%d", err);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
esp_core_dump_report_stack_usage();
|
esp_core_dump_report_stack_usage();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void __attribute__((weak)) esp_core_dump_init(void)
|
void __attribute__((weak)) esp_core_dump_init(void)
|
||||||
|
@ -22,10 +22,7 @@
|
|||||||
|
|
||||||
#include "elf.h" // for ELF file types
|
#include "elf.h" // for ELF file types
|
||||||
|
|
||||||
#define ELF_SEG_HEADERS_COUNT(_self_, _task_num_) (uint32_t)((_task_num_) * 2/*stack + tcb*/ \
|
#define ELF_SEG_HEADERS_COUNT(_self_) ((_self_)->segs_count)
|
||||||
+ 1/* regs notes */ + 1/* ver info + extra note */ + ((_self_)->interrupted_task.stack_start ? 1 : 0) \
|
|
||||||
+ /* user mapped variables */ esp_core_dump_get_user_ram_segments())
|
|
||||||
|
|
||||||
|
|
||||||
#define ELF_HLEN 52
|
#define ELF_HLEN 52
|
||||||
#define ELF_CORE_SEC_TYPE 1
|
#define ELF_CORE_SEC_TYPE 1
|
||||||
@ -80,8 +77,7 @@ typedef struct _core_dump_elf_t
|
|||||||
core_dump_elf_version_info_t elf_version_info;
|
core_dump_elf_version_info_t elf_version_info;
|
||||||
uint16_t elf_stage;
|
uint16_t elf_stage;
|
||||||
uint32_t elf_next_data_offset;
|
uint32_t elf_next_data_offset;
|
||||||
uint32_t bad_tasks_num;
|
uint16_t segs_count;
|
||||||
core_dump_task_header_t interrupted_task;
|
|
||||||
core_dump_write_config_t * write_cfg;
|
core_dump_write_config_t * write_cfg;
|
||||||
} core_dump_elf_t;
|
} core_dump_elf_t;
|
||||||
|
|
||||||
@ -167,6 +163,7 @@ static int elf_add_segment(core_dump_elf_t *self,
|
|||||||
ALIGN(4, data_len);
|
ALIGN(4, data_len);
|
||||||
|
|
||||||
if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
|
if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
|
||||||
|
self->segs_count++;
|
||||||
return data_len + sizeof(elf_phdr);
|
return data_len + sizeof(elf_phdr);
|
||||||
}
|
}
|
||||||
if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
|
if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
|
||||||
@ -295,61 +292,15 @@ static int elf_add_tcb(core_dump_elf_t *self, core_dump_task_header_t *task)
|
|||||||
ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid task pointer.");
|
ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid task pointer.");
|
||||||
// add task tcb data into program segment of ELF
|
// add task tcb data into program segment of ELF
|
||||||
ESP_COREDUMP_LOG_PROCESS("Add TCB for task 0x%x: addr 0x%x, sz %u",
|
ESP_COREDUMP_LOG_PROCESS("Add TCB for task 0x%x: addr 0x%x, sz %u",
|
||||||
task->tcb_addr, task->tcb_addr, COREDUMP_TCB_SIZE);
|
task->tcb_addr, task->tcb_addr,
|
||||||
|
esp_core_dump_get_tcb_len());
|
||||||
int ret = elf_add_segment(self, PT_LOAD,
|
int ret = elf_add_segment(self, PT_LOAD,
|
||||||
(uint32_t)task->tcb_addr,
|
(uint32_t)task->tcb_addr,
|
||||||
(void*)task->tcb_addr,
|
(void*)task->tcb_addr,
|
||||||
COREDUMP_TCB_SIZE);
|
esp_core_dump_get_tcb_len());
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get index of current crashed task (not always first task in the snapshot)
|
|
||||||
static int elf_get_current_task_index(core_dump_task_header_t** tasks,
|
|
||||||
uint32_t task_num)
|
|
||||||
{
|
|
||||||
int task_id;
|
|
||||||
int curr_task_index = COREDUMP_CURR_TASK_NOT_FOUND;
|
|
||||||
void* curr_task_handle = esp_core_dump_get_current_task_handle();
|
|
||||||
|
|
||||||
// get index of current crashed task (not always first task in the snapshot)
|
|
||||||
for (task_id = 0; task_id < task_num; task_id++) {
|
|
||||||
bool tcb_is_valid = esp_core_dump_tcb_addr_is_sane((uint32_t)tasks[task_id]->tcb_addr);
|
|
||||||
bool stack_is_valid = esp_core_dump_check_stack(tasks[task_id]->stack_start, tasks[task_id]->stack_end);
|
|
||||||
if (stack_is_valid && tcb_is_valid && curr_task_handle == tasks[task_id]->tcb_addr) {
|
|
||||||
curr_task_index = task_id; // save current crashed task index in the snapshot
|
|
||||||
ESP_COREDUMP_LOG_PROCESS("Task #%d, (TCB:%x) is current crashed task.",
|
|
||||||
task_id,
|
|
||||||
tasks[task_id]->tcb_addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return curr_task_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid input data.");
|
|
||||||
|
|
||||||
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(info, task, &task_is_current, NULL);
|
|
||||||
if (!task_is_valid) {
|
|
||||||
if (task_is_current) {
|
|
||||||
ESP_COREDUMP_LOG_PROCESS("Task has incorrect (TCB:%x)!",
|
|
||||||
task->tcb_addr);
|
|
||||||
} else {
|
|
||||||
ESP_COREDUMP_LOG_PROCESS("The current crashed task has broken (TCB:%x)!",
|
|
||||||
task->tcb_addr);
|
|
||||||
}
|
|
||||||
self->bad_tasks_num++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// extract registers from stack and apply elf data size for stack section
|
|
||||||
return elf_add_regs(self, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int elf_process_task_tcb(core_dump_elf_t *self, core_dump_task_header_t *task)
|
static int elf_process_task_tcb(core_dump_elf_t *self, core_dump_task_header_t *task)
|
||||||
{
|
{
|
||||||
int ret = ELF_PROC_ERR_OTHER;
|
int ret = ELF_PROC_ERR_OTHER;
|
||||||
@ -358,10 +309,7 @@ static int elf_process_task_tcb(core_dump_elf_t *self, core_dump_task_header_t *
|
|||||||
|
|
||||||
// save tcb of the task as is and apply segment size
|
// save tcb of the task as is and apply segment size
|
||||||
ret = elf_add_tcb(self, task);
|
ret = elf_add_tcb(self, task);
|
||||||
if (ret > 0) {
|
if (ret <= 0) {
|
||||||
ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x) processing completed.",
|
|
||||||
task->tcb_addr);
|
|
||||||
} else {
|
|
||||||
ESP_COREDUMP_LOGE("Task (TCB:%x) processing failure = %d",
|
ESP_COREDUMP_LOGE("Task (TCB:%x) processing failure = %d",
|
||||||
task->tcb_addr,
|
task->tcb_addr,
|
||||||
ret);
|
ret);
|
||||||
@ -376,11 +324,7 @@ static int elf_process_task_stack(core_dump_elf_t *self, core_dump_task_header_t
|
|||||||
ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid input data.");
|
ELF_CHECK_ERR((task), ELF_PROC_ERR_OTHER, "Invalid input data.");
|
||||||
|
|
||||||
ret = elf_add_stack(self, task);
|
ret = elf_add_stack(self, task);
|
||||||
if (ret > 0) {
|
if (ret <= 0) {
|
||||||
ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x), (Stack:%x) stack is processed.",
|
|
||||||
task->tcb_addr,
|
|
||||||
task->stack_start);
|
|
||||||
} else {
|
|
||||||
ESP_COREDUMP_LOGE("Task (TCB:%x), (Stack:%x), stack processing failure = %d.",
|
ESP_COREDUMP_LOGE("Task (TCB:%x), (Stack:%x), stack processing failure = %d.",
|
||||||
task->tcb_addr,
|
task->tcb_addr,
|
||||||
task->stack_start,
|
task->stack_start,
|
||||||
@ -407,6 +351,7 @@ static int elf_process_note_segment(core_dump_elf_t *self, int notes_size)
|
|||||||
self->elf_next_data_offset += notes_size;
|
self->elf_next_data_offset += notes_size;
|
||||||
return sizeof(seg_hdr);
|
return sizeof(seg_hdr);
|
||||||
} else if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
|
} else if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
|
||||||
|
self->segs_count++;
|
||||||
notes_size += sizeof(seg_hdr);
|
notes_size += sizeof(seg_hdr);
|
||||||
} else {
|
} else {
|
||||||
// in "Place Data" phase segment body is been already filled by other functions
|
// in "Place Data" phase segment body is been already filled by other functions
|
||||||
@ -417,96 +362,107 @@ static int elf_process_note_segment(core_dump_elf_t *self, int notes_size)
|
|||||||
return (int)notes_size;
|
return (int)notes_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int elf_process_tasks_regs(core_dump_elf_t *self, panic_info_t *info,
|
static int elf_process_tasks_regs(core_dump_elf_t *self)
|
||||||
core_dump_task_header_t** tasks,
|
|
||||||
uint32_t task_num)
|
|
||||||
{
|
{
|
||||||
int len = 0;
|
void *task;
|
||||||
|
int len = 0, ret;
|
||||||
|
core_dump_task_header_t task_hdr;
|
||||||
|
|
||||||
uint32_t curr_task_index = elf_get_current_task_index(tasks, task_num);
|
esp_core_dump_reset_tasks_snapshots_iter();
|
||||||
if (curr_task_index == COREDUMP_CURR_TASK_NOT_FOUND) {
|
task = esp_core_dump_get_current_task_handle();
|
||||||
ESP_COREDUMP_LOG_PROCESS("The current crashed task is broken.");
|
if (esp_core_dump_get_task_snapshot(task, &task_hdr, NULL)) {
|
||||||
curr_task_index = 0;
|
// place current task dump first
|
||||||
}
|
ret = elf_add_regs(self, &task_hdr);
|
||||||
|
|
||||||
// place current task dump first
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
ELF_CHECK_ERR((ret > 0), ret, "Task #%d, PR_STATUS write failed, return (%d).", curr_task_index, ret);
|
|
||||||
}
|
|
||||||
len += ret;
|
|
||||||
|
|
||||||
// processes PR_STATUS and register dump for each task
|
|
||||||
// each call to the processing function appends PR_STATUS note into note segment
|
|
||||||
// and writes data or updates the segment note header accordingly (if phdr is set)
|
|
||||||
for (int task_id = 0; task_id < task_num; task_id++) {
|
|
||||||
if (task_id == curr_task_index) {
|
|
||||||
continue; // skip current task (already processed)
|
|
||||||
}
|
|
||||||
ret = elf_process_task_regdump(self, info, tasks[task_id]);
|
|
||||||
if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
|
if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
|
||||||
// when writing segments headers this function writes nothing
|
// 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);
|
ELF_CHECK_ERR((ret >= 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret);
|
||||||
} else {
|
} else {
|
||||||
ELF_CHECK_ERR((ret > 0), ret, "Task #%d, PR_STATUS write failed, return (%d).", task_id, ret);
|
ELF_CHECK_ERR((ret > 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret);
|
||||||
}
|
}
|
||||||
len += ret;
|
len += ret;
|
||||||
}
|
}
|
||||||
ret = elf_process_note_segment(self, len);
|
// processes PR_STATUS and register dump for each task
|
||||||
|
// each call to the processing function appends PR_STATUS note into note segment
|
||||||
|
// and writes data or updates the segment note header accordingly (if phdr is set)
|
||||||
|
task = NULL;
|
||||||
|
while ((task = esp_core_dump_get_next_task(task))) {
|
||||||
|
if (task == esp_core_dump_get_current_task_handle()) {
|
||||||
|
continue; // skip current task (already processed)
|
||||||
|
}
|
||||||
|
if (esp_core_dump_get_task_snapshot(task, &task_hdr, NULL)) {
|
||||||
|
ret = elf_add_regs(self, &task_hdr);
|
||||||
|
if (self->elf_stage == ELF_STAGE_PLACE_HEADERS) {
|
||||||
|
// when writing segments headers this function writes nothing
|
||||||
|
ELF_CHECK_ERR((ret >= 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret);
|
||||||
|
} else {
|
||||||
|
ELF_CHECK_ERR((ret > 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret);
|
||||||
|
}
|
||||||
|
len += ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = elf_process_note_segment(self, len); // tasks regs note
|
||||||
ELF_CHECK_ERR((ret > 0), ret,
|
ELF_CHECK_ERR((ret > 0), ret,
|
||||||
"PR_STATUS note segment processing failure, returned(%d).", ret);
|
"PR_STATUS note segment processing failure, returned(%d).", ret);
|
||||||
|
|
||||||
if (esp_core_dump_in_isr_context()) {
|
|
||||||
if (self->elf_stage == ELF_STAGE_CALC_SPACE) {
|
|
||||||
// in this stage we can safely replace task's stack with IRQ's one
|
|
||||||
// if task had corrupted stack it was replaced with fake one in HW dependent code called by elf_process_task_regdump()
|
|
||||||
// in the "write data" stage registers from ISR's stack will be saved in PR_STATUS
|
|
||||||
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)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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// actually we write current task's stack here which was replaced by ISR's
|
|
||||||
len = elf_add_stack(self, &self->interrupted_task);
|
|
||||||
ELF_CHECK_ERR((len > 0), len, "Interrupted task stack write failed, return (%d).", len);
|
|
||||||
ret += len;
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int elf_write_tasks_data(core_dump_elf_t *self, panic_info_t *info,
|
static int elf_save_task(core_dump_elf_t *self, core_dump_task_header_t *task)
|
||||||
core_dump_task_header_t** tasks,
|
|
||||||
uint32_t task_num)
|
|
||||||
{
|
{
|
||||||
int elf_len = 0;
|
int elf_len = 0;
|
||||||
int task_id;
|
|
||||||
|
int ret = elf_process_task_tcb(self, task);
|
||||||
|
ELF_CHECK_ERR((ret > 0), ret,
|
||||||
|
"Task %x, TCB write failed, return (%d).", task->tcb_addr, ret);
|
||||||
|
elf_len += ret;
|
||||||
|
ret = elf_process_task_stack(self, task);
|
||||||
|
ELF_CHECK_ERR((ret != ELF_PROC_ERR_WRITE_FAIL), ELF_PROC_ERR_WRITE_FAIL,
|
||||||
|
"Task %x, stack write failed, return (%d).", task->tcb_addr, ret);
|
||||||
|
elf_len += ret;
|
||||||
|
return elf_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int elf_write_tasks_data(core_dump_elf_t *self)
|
||||||
|
{
|
||||||
|
int elf_len = 0;
|
||||||
|
void *task;
|
||||||
|
core_dump_task_header_t task_hdr;
|
||||||
|
core_dump_mem_seg_header_t interrupted_stack;
|
||||||
int ret = ELF_PROC_ERR_OTHER;
|
int ret = ELF_PROC_ERR_OTHER;
|
||||||
|
uint16_t tasks_num = 0, bad_tasks_num = 0;
|
||||||
|
|
||||||
ELF_CHECK_ERR((info && tasks), ELF_PROC_ERR_OTHER, "Invalid input data.");
|
bad_tasks_num = 0;
|
||||||
|
ESP_COREDUMP_LOG_PROCESS("================ Processing task registers ================");
|
||||||
ret = elf_process_tasks_regs(self, info, tasks, task_num);
|
ret = elf_process_tasks_regs(self);
|
||||||
ELF_CHECK_ERR((ret > 0), ret, "Tasks regs addition failed, return (%d).", ret);
|
ELF_CHECK_ERR((ret > 0), ret, "Tasks regs addition failed, return (%d).", ret);
|
||||||
elf_len += ret;
|
elf_len += ret;
|
||||||
self->bad_tasks_num = 0; // reset bad task counter
|
|
||||||
|
|
||||||
|
ESP_COREDUMP_LOG_PROCESS("================ Processing task data ================");
|
||||||
// processes all task's stack data and writes segment data into partition
|
// processes all task's stack data and writes segment data into partition
|
||||||
// if flash configuration is set
|
// if flash configuration is set
|
||||||
for (task_id = 0; task_id < task_num; task_id++) {
|
task = NULL;
|
||||||
ret = elf_process_task_tcb(self, tasks[task_id]);
|
esp_core_dump_reset_tasks_snapshots_iter();
|
||||||
|
while ((task = esp_core_dump_get_next_task(task))) {
|
||||||
|
tasks_num++;
|
||||||
|
if (!esp_core_dump_get_task_snapshot(task, &task_hdr, &interrupted_stack)) {
|
||||||
|
bad_tasks_num++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ret = elf_save_task(self, &task_hdr);
|
||||||
ELF_CHECK_ERR((ret > 0), ret,
|
ELF_CHECK_ERR((ret > 0), ret,
|
||||||
"Task #%d, TCB write failed, return (%d).", task_id, ret);
|
"Task %x, TCB write failed, return (%d).", task, ret);
|
||||||
elf_len += ret;
|
|
||||||
ret = elf_process_task_stack(self, tasks[task_id]);
|
|
||||||
ELF_CHECK_ERR((ret != ELF_PROC_ERR_WRITE_FAIL), ELF_PROC_ERR_WRITE_FAIL,
|
|
||||||
"Task #%d, stack write failed, return (%d).", task_id, ret);
|
|
||||||
elf_len += ret;
|
elf_len += ret;
|
||||||
|
if (interrupted_stack.size > 0) {
|
||||||
|
ESP_COREDUMP_LOG_PROCESS("Add interrupted task stack %lu bytes @ %x",
|
||||||
|
interrupted_stack.size, interrupted_stack.start);
|
||||||
|
ret = elf_add_segment(self, PT_LOAD,
|
||||||
|
(uint32_t)interrupted_stack.start,
|
||||||
|
(void*)interrupted_stack.start,
|
||||||
|
(uint32_t)interrupted_stack.size);
|
||||||
|
ELF_CHECK_ERR((ret > 0), ret, "Interrupted task stack write failed, return (%d).", ret);
|
||||||
|
elf_len += ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ESP_COREDUMP_LOG_PROCESS("Found %d bad task out of %d", bad_tasks_num, tasks_num);
|
||||||
return elf_len;
|
return elf_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,6 +495,7 @@ static int elf_write_core_dump_info(core_dump_elf_t *self)
|
|||||||
{
|
{
|
||||||
void *extra_info;
|
void *extra_info;
|
||||||
|
|
||||||
|
ESP_COREDUMP_LOG_PROCESS("================ Processing coredump info ================");
|
||||||
int data_len = (int)sizeof(self->elf_version_info.app_elf_sha256);
|
int data_len = (int)sizeof(self->elf_version_info.app_elf_sha256);
|
||||||
data_len = esp_ota_get_app_elf_sha256((char*)self->elf_version_info.app_elf_sha256, (size_t)data_len);
|
data_len = esp_ota_get_app_elf_sha256((char*)self->elf_version_info.app_elf_sha256, (size_t)data_len);
|
||||||
ESP_COREDUMP_LOG_PROCESS("Application SHA256='%s', length=%d.",
|
ESP_COREDUMP_LOG_PROCESS("Application SHA256='%s', length=%d.",
|
||||||
@ -572,13 +529,11 @@ static int elf_write_core_dump_info(core_dump_elf_t *self)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int esp_core_dump_do_write_elf_pass(core_dump_elf_t *self, panic_info_t *info,
|
static int esp_core_dump_do_write_elf_pass(core_dump_elf_t *self)
|
||||||
core_dump_task_header_t** tasks,
|
|
||||||
uint32_t task_num)
|
|
||||||
{
|
{
|
||||||
int tot_len = 0;
|
int tot_len = 0;
|
||||||
|
|
||||||
int data_sz = elf_write_file_header(self, ELF_SEG_HEADERS_COUNT(self, task_num));
|
int data_sz = elf_write_file_header(self, ELF_SEG_HEADERS_COUNT(self));
|
||||||
if (self->elf_stage == ELF_STAGE_PLACE_DATA) {
|
if (self->elf_stage == ELF_STAGE_PLACE_DATA) {
|
||||||
ELF_CHECK_ERR((data_sz >= 0), data_sz, "ELF header writing error, returned (%d).", data_sz);
|
ELF_CHECK_ERR((data_sz >= 0), data_sz, "ELF header writing error, returned (%d).", data_sz);
|
||||||
} else {
|
} else {
|
||||||
@ -586,7 +541,7 @@ static int esp_core_dump_do_write_elf_pass(core_dump_elf_t *self, panic_info_t *
|
|||||||
}
|
}
|
||||||
tot_len += data_sz;
|
tot_len += data_sz;
|
||||||
// Calculate whole size include headers for all tasks and main elf header
|
// Calculate whole size include headers for all tasks and main elf header
|
||||||
data_sz = elf_write_tasks_data(self, info, tasks, task_num);
|
data_sz = elf_write_tasks_data(self);
|
||||||
ELF_CHECK_ERR((data_sz > 0), data_sz, "ELF Size writing error, returned (%d).", data_sz);
|
ELF_CHECK_ERR((data_sz > 0), data_sz, "ELF Size writing error, returned (%d).", data_sz);
|
||||||
tot_len += data_sz;
|
tot_len += data_sz;
|
||||||
|
|
||||||
@ -604,32 +559,25 @@ static int esp_core_dump_do_write_elf_pass(core_dump_elf_t *self, panic_info_t *
|
|||||||
return tot_len;
|
return tot_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t esp_core_dump_write_elf(panic_info_t *info, core_dump_write_config_t *write_cfg)
|
esp_err_t esp_core_dump_write_elf(core_dump_write_config_t *write_cfg)
|
||||||
{
|
{
|
||||||
esp_err_t err = ESP_OK;
|
esp_err_t err = ESP_OK;
|
||||||
static core_dump_task_header_t *tasks[CONFIG_ESP_COREDUMP_MAX_TASKS_NUM];
|
|
||||||
static core_dump_elf_t self;
|
static core_dump_elf_t self;
|
||||||
core_dump_header_t dump_hdr;
|
static core_dump_header_t dump_hdr;
|
||||||
uint32_t tcb_sz = COREDUMP_TCB_SIZE, task_num;
|
|
||||||
int tot_len = sizeof(dump_hdr);
|
int tot_len = sizeof(dump_hdr);
|
||||||
int write_len = sizeof(dump_hdr);
|
int write_len = sizeof(dump_hdr);
|
||||||
|
|
||||||
ELF_CHECK_ERR((info && write_cfg), ESP_ERR_INVALID_ARG, "Invalid input data.");
|
ELF_CHECK_ERR((write_cfg), ESP_ERR_INVALID_ARG, "Invalid input data.");
|
||||||
|
|
||||||
task_num = esp_core_dump_get_tasks_snapshot(tasks, CONFIG_ESP_COREDUMP_MAX_TASKS_NUM);
|
|
||||||
ESP_COREDUMP_LOGI("Found tasks: %d", task_num);
|
|
||||||
|
|
||||||
self.write_cfg = write_cfg;
|
self.write_cfg = write_cfg;
|
||||||
|
|
||||||
esp_core_dump_init_extra_info();
|
|
||||||
// On first pass (do not write actual data), but calculate data length needed to allocate memory
|
// On first pass (do not write actual data), but calculate data length needed to allocate memory
|
||||||
self.elf_stage = ELF_STAGE_CALC_SPACE;
|
self.elf_stage = ELF_STAGE_CALC_SPACE;
|
||||||
ESP_COREDUMP_LOG_PROCESS("================= Calc data size ===============");
|
ESP_COREDUMP_LOG_PROCESS("================= Calc data size ===============");
|
||||||
int ret = esp_core_dump_do_write_elf_pass(&self, info, tasks, task_num);
|
int ret = esp_core_dump_do_write_elf_pass(&self);
|
||||||
if (ret < 0) return ret;
|
if (ret < 0) return ret;
|
||||||
tot_len += ret;
|
tot_len += ret;
|
||||||
ESP_COREDUMP_LOG_PROCESS("Core dump tot_len=%lu, tasks processed: %d, broken tasks: %d",
|
ESP_COREDUMP_LOG_PROCESS("Core dump tot_len=%lu", tot_len);
|
||||||
tot_len, task_num, self.bad_tasks_num);
|
|
||||||
ESP_COREDUMP_LOG_PROCESS("============== Data size = %d bytes ============", tot_len);
|
ESP_COREDUMP_LOG_PROCESS("============== Data size = %d bytes ============", tot_len);
|
||||||
|
|
||||||
// Prepare write elf
|
// Prepare write elf
|
||||||
@ -650,16 +598,12 @@ esp_err_t esp_core_dump_write_elf(panic_info_t *info, core_dump_write_config_t *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write_cfg->bad_tasks_num = self.bad_tasks_num;
|
|
||||||
|
|
||||||
// Write core dump header
|
// Write core dump header
|
||||||
ALIGN(4, tot_len);
|
|
||||||
ALIGN(4, tcb_sz);
|
|
||||||
dump_hdr.data_len = tot_len;
|
dump_hdr.data_len = tot_len;
|
||||||
dump_hdr.version = COREDUMP_VERSION;
|
dump_hdr.version = COREDUMP_VERSION;
|
||||||
dump_hdr.tasks_num = task_num; // broken tasks are repaired
|
dump_hdr.tasks_num = 0; // unused in ELF format
|
||||||
dump_hdr.tcb_sz = tcb_sz;
|
dump_hdr.tcb_sz = 0; // unused in ELF format
|
||||||
dump_hdr.mem_segs_num = 0;
|
dump_hdr.mem_segs_num = 0; // unused in ELF format
|
||||||
err = write_cfg->write(write_cfg->priv,
|
err = write_cfg->write(write_cfg->priv,
|
||||||
(void*)&dump_hdr,
|
(void*)&dump_hdr,
|
||||||
sizeof(core_dump_header_t));
|
sizeof(core_dump_header_t));
|
||||||
@ -670,16 +614,16 @@ esp_err_t esp_core_dump_write_elf(panic_info_t *info, core_dump_write_config_t *
|
|||||||
|
|
||||||
self.elf_stage = ELF_STAGE_PLACE_HEADERS;
|
self.elf_stage = ELF_STAGE_PLACE_HEADERS;
|
||||||
// set initial offset to elf segments data area
|
// 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);
|
self.elf_next_data_offset = sizeof(elfhdr) + ELF_SEG_HEADERS_COUNT(&self) * sizeof(elf_phdr);
|
||||||
ret = esp_core_dump_do_write_elf_pass(&self, info, tasks, task_num);
|
ret = esp_core_dump_do_write_elf_pass(&self);
|
||||||
if (ret < 0) return ret;
|
if (ret < 0) return ret;
|
||||||
write_len += ret;
|
write_len += ret;
|
||||||
ESP_COREDUMP_LOG_PROCESS("============== Headers size = %d bytes ============", write_len);
|
ESP_COREDUMP_LOG_PROCESS("============== Headers size = %d bytes ============", write_len);
|
||||||
|
|
||||||
self.elf_stage = ELF_STAGE_PLACE_DATA;
|
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
|
// 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);
|
self.elf_next_data_offset = sizeof(elfhdr) + ELF_SEG_HEADERS_COUNT(&self) * sizeof(elf_phdr);
|
||||||
ret = esp_core_dump_do_write_elf_pass(&self, info, tasks, task_num);
|
ret = esp_core_dump_do_write_elf_pass(&self);
|
||||||
if (ret < 0) return ret;
|
if (ret < 0) return ret;
|
||||||
write_len += ret;
|
write_len += ret;
|
||||||
ESP_COREDUMP_LOG_PROCESS("=========== Data written size = %d bytes ==========", write_len);
|
ESP_COREDUMP_LOG_PROCESS("=========== Data written size = %d bytes ==========", write_len);
|
||||||
|
@ -134,6 +134,10 @@ extern uint8_t port_IntStack;
|
|||||||
|
|
||||||
#if CONFIG_ESP_COREDUMP_ENABLE
|
#if CONFIG_ESP_COREDUMP_ENABLE
|
||||||
|
|
||||||
|
#if !(CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2)
|
||||||
|
#error Coredump functionality is not implemented for this target!
|
||||||
|
#endif
|
||||||
|
|
||||||
static uint32_t s_total_length = 0;
|
static uint32_t s_total_length = 0;
|
||||||
|
|
||||||
static XtExcFrame s_fake_stack_frame = {
|
static XtExcFrame s_fake_stack_frame = {
|
||||||
@ -148,6 +152,14 @@ static uint32_t s_fake_stacks_num;
|
|||||||
|
|
||||||
static xtensa_extra_info_t s_extra_info;
|
static xtensa_extra_info_t s_extra_info;
|
||||||
|
|
||||||
|
static XtExcFrame *s_exc_frame;
|
||||||
|
|
||||||
|
static bool esp_core_dump_check_task(core_dump_task_header_t *task);
|
||||||
|
static bool esp_core_dump_check_stack(core_dump_task_header_t *task);
|
||||||
|
static void esp_core_dump_switch_task_stack_to_isr(core_dump_task_header_t *task,
|
||||||
|
core_dump_mem_seg_header_t *stack);
|
||||||
|
|
||||||
|
|
||||||
#if ESP_COREDUMP_STACK_SIZE > 0
|
#if ESP_COREDUMP_STACK_SIZE > 0
|
||||||
uint8_t s_coredump_stack[ESP_COREDUMP_STACK_SIZE];
|
uint8_t s_coredump_stack[ESP_COREDUMP_STACK_SIZE];
|
||||||
uint8_t *s_core_dump_sp;
|
uint8_t *s_core_dump_sp;
|
||||||
@ -290,6 +302,20 @@ uint32_t esp_core_dump_checksum_finish(core_dump_write_data_t* wr_data, void** c
|
|||||||
return chs_len;
|
return chs_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void esp_core_dump_port_init(panic_info_t *info)
|
||||||
|
{
|
||||||
|
s_extra_info.crashed_task_tcb = COREDUMP_CURR_TASK_MARKER;
|
||||||
|
// Initialize exccause register to default value (required if current task corrupted)
|
||||||
|
s_extra_info.exccause.reg_val = COREDUMP_INVALID_CAUSE_VALUE;
|
||||||
|
s_extra_info.exccause.reg_index = EXCCAUSE;
|
||||||
|
|
||||||
|
s_exc_frame = (void *)info->frame;
|
||||||
|
s_exc_frame->exit = COREDUMP_CURR_TASK_MARKER;
|
||||||
|
if (info->pseudo_excause) {
|
||||||
|
s_exc_frame->exccause += XCHAL_EXCCAUSE_NUM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline uint16_t esp_core_dump_get_arch_id()
|
inline uint16_t esp_core_dump_get_arch_id()
|
||||||
{
|
{
|
||||||
return COREDUMP_EM_XTENSA;
|
return COREDUMP_EM_XTENSA;
|
||||||
@ -307,50 +333,65 @@ inline bool esp_core_dump_mem_seg_is_sane(uint32_t addr, uint32_t sz)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool esp_core_dump_task_stack_end_is_sane(uint32_t sp)
|
static inline bool esp_core_dump_task_stack_end_is_sane(uint32_t sp)
|
||||||
{
|
{
|
||||||
//TODO: currently core dump supports stacks in DRAM only, external SRAM not supported yet
|
//TODO: currently core dump supports stacks in DRAM only, external SRAM not supported yet
|
||||||
return esp_ptr_in_dram((void *)sp);
|
return esp_ptr_in_dram((void *)sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool esp_core_dump_tcb_addr_is_sane(uint32_t addr)
|
static inline bool esp_core_dump_tcb_addr_is_sane(uint32_t addr)
|
||||||
{
|
{
|
||||||
return esp_core_dump_mem_seg_is_sane(addr, COREDUMP_TCB_SIZE);
|
return esp_core_dump_mem_seg_is_sane(addr, esp_core_dump_get_tcb_len());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t esp_core_dump_get_tasks_snapshot(core_dump_task_header_t** const tasks,
|
inline void esp_core_dump_reset_tasks_snapshots_iter(void)
|
||||||
const uint32_t snapshot_size)
|
|
||||||
{
|
{
|
||||||
static TaskSnapshot_t s_tasks_snapshots[CONFIG_ESP_COREDUMP_MAX_TASKS_NUM];
|
s_fake_stacks_num = 0;
|
||||||
uint32_t tcb_sz; // unused
|
}
|
||||||
|
|
||||||
/* implying that TaskSnapshot_t extends core_dump_task_header_t by adding extra fields */
|
inline void *esp_core_dump_get_next_task(void *handle)
|
||||||
_Static_assert(sizeof(TaskSnapshot_t) >= sizeof(core_dump_task_header_t), "FreeRTOS task snapshot binary compatibility issue!");
|
{
|
||||||
|
return pxTaskGetNext(handle);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t task_num = (uint32_t)uxTaskGetSnapshotAll(s_tasks_snapshots,
|
bool esp_core_dump_get_task_snapshot(void *handle, core_dump_task_header_t *task,
|
||||||
(UBaseType_t)snapshot_size,
|
core_dump_mem_seg_header_t *interrupted_stack)
|
||||||
(UBaseType_t*)&tcb_sz);
|
{
|
||||||
for (uint32_t i = 0; i < task_num; i++) {
|
TaskSnapshot_t rtos_snapshot;
|
||||||
tasks[i] = (core_dump_task_header_t *)&s_tasks_snapshots[i];
|
|
||||||
|
if (interrupted_stack != NULL) {
|
||||||
|
interrupted_stack->size = 0;
|
||||||
}
|
}
|
||||||
return task_num;
|
|
||||||
|
vTaskGetSnapshot(handle, &rtos_snapshot);
|
||||||
|
task->tcb_addr = handle;
|
||||||
|
task->stack_start = (uint32_t)rtos_snapshot.pxTopOfStack;
|
||||||
|
task->stack_end = (uint32_t)rtos_snapshot.pxEndOfStack;
|
||||||
|
|
||||||
|
if (!xPortInterruptedFromISRContext() && handle == esp_core_dump_get_current_task_handle()) {
|
||||||
|
// Set correct stack top for current task; only modify if we came from the task,
|
||||||
|
// and not an ISR that crashed.
|
||||||
|
task->stack_start = (uint32_t)s_exc_frame;
|
||||||
|
}
|
||||||
|
if (!esp_core_dump_check_task(task)) {
|
||||||
|
ESP_COREDUMP_LOG_PROCESS("Task %x is broken!", handle);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (handle == esp_core_dump_get_current_task_handle()) {
|
||||||
|
ESP_COREDUMP_LOG_PROCESS("Crashed task %x", handle);
|
||||||
|
s_extra_info.crashed_task_tcb = (uint32_t)handle;
|
||||||
|
if (xPortInterruptedFromISRContext()) {
|
||||||
|
esp_core_dump_switch_task_stack_to_isr(task, interrupted_stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t esp_core_dump_get_isr_stack_end(void)
|
inline uint32_t esp_core_dump_get_stack(core_dump_task_header_t *task,
|
||||||
{
|
|
||||||
return (uint32_t)((uint8_t *)&port_IntStack + (xPortGetCoreID()+1)*configISR_STACK_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t esp_core_dump_get_stack(core_dump_task_header_t *task_snapshot,
|
|
||||||
uint32_t *stk_vaddr, uint32_t *stk_len)
|
uint32_t *stk_vaddr, uint32_t *stk_len)
|
||||||
{
|
{
|
||||||
if (task_snapshot->stack_end > task_snapshot->stack_start) {
|
*stk_len = task->stack_end - task->stack_start;
|
||||||
*stk_len = task_snapshot->stack_end - task_snapshot->stack_start;
|
*stk_vaddr = task->stack_start;
|
||||||
*stk_vaddr = task_snapshot->stack_start;
|
|
||||||
} else {
|
|
||||||
*stk_len = task_snapshot->stack_start - task_snapshot->stack_end;
|
|
||||||
*stk_vaddr = task_snapshot->stack_end;
|
|
||||||
}
|
|
||||||
if (*stk_vaddr >= COREDUMP_FAKE_STACK_START && *stk_vaddr < COREDUMP_FAKE_STACK_LIMIT) {
|
if (*stk_vaddr >= COREDUMP_FAKE_STACK_START && *stk_vaddr < COREDUMP_FAKE_STACK_LIMIT) {
|
||||||
return (uint32_t)&s_fake_stack_frame;
|
return (uint32_t)&s_fake_stack_frame;
|
||||||
}
|
}
|
||||||
@ -366,6 +407,18 @@ static void *esp_core_dump_get_fake_stack(uint32_t *stk_len)
|
|||||||
return (uint8_t*)COREDUMP_FAKE_STACK_START + sizeof(s_fake_stack_frame)*s_fake_stacks_num++;
|
return (uint8_t*)COREDUMP_FAKE_STACK_START + sizeof(s_fake_stack_frame)*s_fake_stacks_num++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void esp_core_dump_switch_task_stack_to_isr(core_dump_task_header_t *task, core_dump_mem_seg_header_t *stack)
|
||||||
|
{
|
||||||
|
if (stack != NULL) {
|
||||||
|
stack->start = task->stack_start;
|
||||||
|
stack->size = esp_core_dump_get_memory_len(task->stack_start, task->stack_end);
|
||||||
|
}
|
||||||
|
uint32_t isr_stk_end = (uint32_t)((uint8_t *)&port_IntStack + (xPortGetCoreID()+1)*configISR_STACK_SIZE);
|
||||||
|
task->stack_start = (uint32_t)s_exc_frame;
|
||||||
|
task->stack_end = isr_stk_end;
|
||||||
|
ESP_COREDUMP_LOG_PROCESS("Switched task %x to ISR stack [%x...%x]", task->tcb_addr, task->stack_start, task->stack_end);
|
||||||
|
}
|
||||||
|
|
||||||
static core_dump_reg_pair_t *esp_core_dump_get_epc_regs(core_dump_reg_pair_t* src)
|
static core_dump_reg_pair_t *esp_core_dump_get_epc_regs(core_dump_reg_pair_t* src)
|
||||||
{
|
{
|
||||||
uint32_t* reg_ptr = (uint32_t*)src;
|
uint32_t* reg_ptr = (uint32_t*)src;
|
||||||
@ -489,37 +542,18 @@ inline void* esp_core_dump_get_current_task_handle()
|
|||||||
return (void*)xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID());
|
return (void*)xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool esp_core_dump_check_task(panic_info_t *info,
|
static bool esp_core_dump_check_task(core_dump_task_header_t *task)
|
||||||
core_dump_task_header_t *task,
|
|
||||||
bool* is_current,
|
|
||||||
bool* stack_is_valid)
|
|
||||||
{
|
{
|
||||||
XtExcFrame *exc_frame = (XtExcFrame *)info->frame;
|
|
||||||
bool is_curr_task = false;
|
|
||||||
bool stack_is_sane = false;
|
|
||||||
uint32_t stk_size = 0;
|
uint32_t stk_size = 0;
|
||||||
|
bool stack_is_valid = false;
|
||||||
|
|
||||||
if (!esp_core_dump_tcb_addr_is_sane((uint32_t)task->tcb_addr)) {
|
if (!esp_core_dump_tcb_addr_is_sane((uint32_t)task->tcb_addr)) {
|
||||||
ESP_COREDUMP_LOG_PROCESS("Bad TCB addr=%x!", task->tcb_addr);
|
ESP_COREDUMP_LOG_PROCESS("Bad TCB addr=%x!", task->tcb_addr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_curr_task = task->tcb_addr == esp_core_dump_get_current_task_handle();
|
stack_is_valid = esp_core_dump_check_stack(task);
|
||||||
if (is_curr_task) {
|
if (!stack_is_valid) {
|
||||||
// Set correct stack top for current task; only modify if we came from the task,
|
|
||||||
// and not an ISR that crashed.
|
|
||||||
if (!xPortInterruptedFromISRContext()) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
stack_is_sane = esp_core_dump_check_stack(task->stack_start, task->stack_end);
|
|
||||||
if (!stack_is_sane) {
|
|
||||||
// Skip saving of invalid task if stack corrupted
|
// Skip saving of invalid task if stack corrupted
|
||||||
ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x), stack is corrupted (%x, %x)",
|
ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x), stack is corrupted (%x, %x)",
|
||||||
task->tcb_addr,
|
task->tcb_addr,
|
||||||
@ -532,80 +566,42 @@ bool esp_core_dump_check_task(panic_info_t *info,
|
|||||||
task->stack_start,
|
task->stack_start,
|
||||||
task->stack_end);
|
task->stack_end);
|
||||||
}
|
}
|
||||||
|
XtSolFrame *sol_frame = (XtSolFrame *)task->stack_start;
|
||||||
if (is_curr_task) {
|
if (sol_frame->exit == 0) {
|
||||||
if (!stack_is_sane)
|
ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x), EXIT/PC/PS/A0/SP %x %x %x %x %x",
|
||||||
ESP_COREDUMP_LOG_PROCESS("Current task 0x%x is broken!", task->tcb_addr);
|
task->tcb_addr,
|
||||||
ESP_COREDUMP_LOG_PROCESS("Current task (TCB:%x), EXIT/PC/PS/A0/SP %x %x %x %x %x",
|
sol_frame->exit,
|
||||||
task->tcb_addr,
|
sol_frame->pc,
|
||||||
exc_frame->exit,
|
sol_frame->ps,
|
||||||
exc_frame->pc,
|
sol_frame->a0,
|
||||||
exc_frame->ps,
|
sol_frame->a1);
|
||||||
exc_frame->a0,
|
|
||||||
exc_frame->a1);
|
|
||||||
} else {
|
} else {
|
||||||
XtSolFrame *task_frame = (XtSolFrame *)task->stack_start;
|
// to avoid warning that 'exc_frame' is unused when ESP_COREDUMP_LOG_PROCESS does nothing
|
||||||
if (stack_is_sane) {
|
|
||||||
if (task_frame->exit == 0) {
|
|
||||||
ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x), EXIT/PC/PS/A0/SP %x %x %x %x %x",
|
|
||||||
task->tcb_addr,
|
|
||||||
task_frame->exit,
|
|
||||||
task_frame->pc,
|
|
||||||
task_frame->ps,
|
|
||||||
task_frame->a0,
|
|
||||||
task_frame->a1);
|
|
||||||
} else {
|
|
||||||
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
|
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
|
||||||
XtExcFrame *task_frame2 = (XtExcFrame *)task->stack_start;
|
XtExcFrame *exc_frame = (XtExcFrame *)task->stack_start;
|
||||||
task_frame2->exccause = COREDUMP_INVALID_CAUSE_VALUE;
|
ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x) EXIT/PC/PS/A0/SP %x %x %x %x %x",
|
||||||
ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x) EXIT/PC/PS/A0/SP %x %x %x %x %x",
|
task->tcb_addr,
|
||||||
task->tcb_addr,
|
exc_frame->exit,
|
||||||
task_frame2->exit,
|
exc_frame->pc,
|
||||||
task_frame2->pc,
|
exc_frame->ps,
|
||||||
task_frame2->ps,
|
exc_frame->a0,
|
||||||
task_frame2->a0,
|
exc_frame->a1);
|
||||||
task_frame2->a1);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ESP_COREDUMP_LOG_PROCESS("Task (TCB:%x), stack_start=%x is incorrect, skip registers printing.",
|
|
||||||
task->tcb_addr, task->stack_start);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_current) {
|
|
||||||
*is_current = is_curr_task;
|
|
||||||
}
|
|
||||||
if (stack_is_valid) {
|
|
||||||
*stack_is_valid = stack_is_sane;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool esp_core_dump_check_stack(uint32_t stack_start, uint32_t stack_end)
|
static bool esp_core_dump_check_stack(core_dump_task_header_t *task)
|
||||||
{
|
{
|
||||||
uint32_t len = stack_end - stack_start;
|
|
||||||
bool task_is_valid = false;
|
|
||||||
// Check task's stack
|
// Check task's stack
|
||||||
if (!esp_stack_ptr_is_sane(stack_start) || !esp_core_dump_task_stack_end_is_sane(stack_end) ||
|
if (!esp_stack_ptr_is_sane(task->stack_start) || !esp_core_dump_task_stack_end_is_sane(task->stack_end) ||
|
||||||
(len > COREDUMP_MAX_TASK_STACK_SIZE)) {
|
(task->stack_start >= task->stack_end) ||
|
||||||
|
((task->stack_end-task->stack_start) > COREDUMP_MAX_TASK_STACK_SIZE)) {
|
||||||
// Check if current task stack is corrupted
|
// Check if current task stack is corrupted
|
||||||
task_is_valid = false;
|
ESP_COREDUMP_LOG_PROCESS("Invalid stack (%x...%x)!", task->stack_start, task->stack_end);
|
||||||
} else {
|
return false;
|
||||||
ESP_COREDUMP_LOG_PROCESS("Stack len = %lu (%x %x)", len, stack_start, stack_end);
|
|
||||||
task_is_valid = true;
|
|
||||||
}
|
}
|
||||||
return task_is_valid;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
void esp_core_dump_init_extra_info()
|
|
||||||
{
|
|
||||||
s_extra_info.crashed_task_tcb = COREDUMP_CURR_TASK_MARKER;
|
|
||||||
// Initialize exccause register to default value (required if current task corrupted)
|
|
||||||
s_extra_info.exccause.reg_val = COREDUMP_INVALID_CAUSE_VALUE;
|
|
||||||
s_extra_info.exccause.reg_index = EXCCAUSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t esp_core_dump_get_extra_info(void **info)
|
uint32_t esp_core_dump_get_extra_info(void **info)
|
||||||
|
@ -2529,7 +2529,7 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* This function fills array with TaskSnapshot_t structures for every task in the system.
|
* This function fills array with TaskSnapshot_t structures for every task in the system.
|
||||||
* Used by core dump facility to get snapshots of all tasks in the system.
|
* Used by panic handling code to get snapshots of all tasks in the system.
|
||||||
* Only available when configENABLE_TASK_SNAPSHOT is set to 1.
|
* Only available when configENABLE_TASK_SNAPSHOT is set to 1.
|
||||||
* @param pxTaskSnapshotArray Pointer to array of TaskSnapshot_t structures to store tasks snapshot data.
|
* @param pxTaskSnapshotArray Pointer to array of TaskSnapshot_t structures to store tasks snapshot data.
|
||||||
* @param uxArraySize Size of tasks snapshots array.
|
* @param uxArraySize Size of tasks snapshots array.
|
||||||
@ -2538,6 +2538,26 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC
|
|||||||
*/
|
*/
|
||||||
UBaseType_t uxTaskGetSnapshotAll( TaskSnapshot_t * const pxTaskSnapshotArray, const UBaseType_t uxArraySize, UBaseType_t * const pxTcbSz );
|
UBaseType_t uxTaskGetSnapshotAll( TaskSnapshot_t * const pxTaskSnapshotArray, const UBaseType_t uxArraySize, UBaseType_t * const pxTcbSz );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function iterates over all tasks in the system.
|
||||||
|
* Used by panic handling code to iterate over tasks in the system.
|
||||||
|
* Only available when configENABLE_TASK_SNAPSHOT is set to 1.
|
||||||
|
* @note This function should not be used while FreeRTOS is running (as it doesn't acquire any locks).
|
||||||
|
* @param pxTask task handle.
|
||||||
|
* @return Handle for the next task. If pxTask is NULL, returns hadnle for the first task.
|
||||||
|
*/
|
||||||
|
TaskHandle_t pxTaskGetNext( TaskHandle_t pxTask );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function fills TaskSnapshot_t structure for specified task.
|
||||||
|
* Used by panic handling code to get snapshot of a task.
|
||||||
|
* Only available when configENABLE_TASK_SNAPSHOT is set to 1.
|
||||||
|
* @note This function should not be used while FreeRTOS is running (as it doesn't acquire any locks).
|
||||||
|
* @param pxTask task handle.
|
||||||
|
* @param pxTaskSnapshot address of TaskSnapshot_t structure to fill.
|
||||||
|
*/
|
||||||
|
void vTaskGetSnapshot( TaskHandle_t pxTask, TaskSnapshot_t *pxTaskSnapshot );
|
||||||
|
|
||||||
/** @endcond */
|
/** @endcond */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -5877,6 +5877,118 @@ const TickType_t xConstTickCount = xTickCount;
|
|||||||
return uxTask;
|
return uxTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TCB_t *prvFirstTaskGet( List_t *pxList )
|
||||||
|
{
|
||||||
|
ListItem_t *pxListItem = listGET_HEAD_ENTRY( pxList );
|
||||||
|
if( pxListItem != listGET_END_MARKER( pxList ) ) {
|
||||||
|
return listGET_LIST_ITEM_OWNER( pxListItem );
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TCB_t *prvNextTaskGet( TCB_t *pxTCB )
|
||||||
|
{
|
||||||
|
List_t *pxList = listLIST_ITEM_CONTAINER( &( pxTCB->xStateListItem ) );
|
||||||
|
ListItem_t *pxListItem = listGET_NEXT( &( pxTCB->xStateListItem ) );
|
||||||
|
if( pxListItem != listGET_END_MARKER( pxList ) ) {
|
||||||
|
return listGET_LIST_ITEM_OWNER( pxListItem );
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void vTaskGetSnapshot( TaskHandle_t pxTask, TaskSnapshot_t *pxTaskSnapshot )
|
||||||
|
{
|
||||||
|
configASSERT( portVALID_TCB_MEM(pxTask) );
|
||||||
|
configASSERT( pxTaskSnapshot != NULL );
|
||||||
|
pxTaskSnapshot->pxTCB = (TCB_t *)pxTask;
|
||||||
|
pxTaskSnapshot->pxTopOfStack = (StackType_t *)((TCB_t *)pxTask)->pxTopOfStack;
|
||||||
|
pxTaskSnapshot->pxEndOfStack = ((TCB_t *)pxTask)->pxEndOfStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskHandle_t pxTaskGetNext( TaskHandle_t pxTask )
|
||||||
|
{
|
||||||
|
TCB_t *pxTCB = pxTask;
|
||||||
|
List_t *pxTaskList = NULL;
|
||||||
|
UBaseType_t i = configMAX_PRIORITIES;
|
||||||
|
UBaseType_t bCurTaskListFound = pdFALSE;
|
||||||
|
List_t *task_lists[] = {
|
||||||
|
pxDelayedTaskList,
|
||||||
|
pxOverflowDelayedTaskList,
|
||||||
|
#if( INCLUDE_vTaskDelete == 1 )
|
||||||
|
&xTasksWaitingTermination,
|
||||||
|
#endif
|
||||||
|
#if( INCLUDE_vTaskSuspend == 1 )
|
||||||
|
&xSuspendedTaskList
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
if( pxTask != NULL && !portVALID_TCB_MEM(pxTask) ) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pxTCB != NULL ) {
|
||||||
|
pxTCB = prvNextTaskGet( pxTCB );
|
||||||
|
if( pxTCB != NULL ) {
|
||||||
|
// take care not to return garbage
|
||||||
|
return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
|
||||||
|
}
|
||||||
|
pxTaskList = listLIST_ITEM_CONTAINER( &( ((TCB_t *)pxTask)->xStateListItem ) );
|
||||||
|
}
|
||||||
|
/* ready tasks lists */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
i--;
|
||||||
|
List_t *pxList = &( pxReadyTasksLists[ i ] );
|
||||||
|
if( bCurTaskListFound == pdFALSE && pxTaskList != NULL ) {
|
||||||
|
/* need to find list the current task item from */
|
||||||
|
if( pxTaskList == pxList ) {
|
||||||
|
bCurTaskListFound = pdTRUE;
|
||||||
|
}
|
||||||
|
continue; /* go to the next 'ready list' */
|
||||||
|
}
|
||||||
|
pxTCB = prvFirstTaskGet( pxList );
|
||||||
|
if( pxTCB != NULL ) {
|
||||||
|
// take care not to return garbage
|
||||||
|
return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while( i > tskIDLE_PRIORITY );
|
||||||
|
/* pending ready tasks lists */
|
||||||
|
for (i = 0; i < portNUM_PROCESSORS; i++) {
|
||||||
|
List_t *pxList = &( xPendingReadyList[ i ] );
|
||||||
|
if( bCurTaskListFound == pdFALSE && pxTaskList != NULL ) {
|
||||||
|
/* need to find list the current task item from */
|
||||||
|
if( pxTaskList == pxList ) {
|
||||||
|
bCurTaskListFound = pdTRUE;
|
||||||
|
}
|
||||||
|
continue; /* go to the next 'ready list' */
|
||||||
|
}
|
||||||
|
pxTCB = prvFirstTaskGet( pxList );
|
||||||
|
if( pxTCB != NULL ) {
|
||||||
|
// take care not to return garbage
|
||||||
|
return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* other tasks lists */
|
||||||
|
for (i = 0; i < sizeof(task_lists)/sizeof(task_lists[0]); i++) {
|
||||||
|
List_t *pxList = task_lists[ i ];
|
||||||
|
if( bCurTaskListFound == pdFALSE && pxTaskList != NULL ) {
|
||||||
|
/* need to find list the current task item from */
|
||||||
|
if( pxTaskList == pxList ) {
|
||||||
|
bCurTaskListFound = pdTRUE;
|
||||||
|
}
|
||||||
|
continue; /* go to the next 'ready list' */
|
||||||
|
}
|
||||||
|
pxTCB = prvFirstTaskGet( pxList );
|
||||||
|
if( pxTCB != NULL ) {
|
||||||
|
// take care not to return garbage
|
||||||
|
return portVALID_TCB_MEM(pxTCB) ? pxTCB : NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Code below here allows additional code to be inserted into this source file,
|
/* Code below here allows additional code to be inserted into this source file,
|
||||||
|
Loading…
Reference in New Issue
Block a user