diff --git a/components/espcoredump/Kconfig b/components/espcoredump/Kconfig index c3e0f4ab7f..0447668581 100644 --- a/components/espcoredump/Kconfig +++ b/components/espcoredump/Kconfig @@ -76,7 +76,9 @@ menu "Core dump" depends on ESP_COREDUMP_ENABLE default 64 help - Maximum number of tasks snapshots in core dump. + Maximum number of tasks that will be included in the core dump. + Crashed task registers and stacks are always included. + Other tasks are included in order of their priority. (Highest priority ready task first) config ESP_COREDUMP_UART_DELAY int "Delay before print to UART" diff --git a/components/espcoredump/src/core_dump_elf.c b/components/espcoredump/src/core_dump_elf.c index c5e4419959..a3c522419f 100644 --- a/components/espcoredump/src/core_dump_elf.c +++ b/components/espcoredump/src/core_dump_elf.c @@ -408,6 +408,7 @@ static int elf_process_tasks_regs(core_dump_elf_t *self) void *task = NULL; int len = 0; int ret = 0; + int tasks_num = 0; esp_core_dump_reset_tasks_snapshots_iter(); task = esp_core_dump_get_current_task_handle(); @@ -421,6 +422,7 @@ static int elf_process_tasks_regs(core_dump_elf_t *self) ELF_CHECK_ERR((ret > 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret); } len += ret; + tasks_num++; } // processes PR_STATUS and register dump for each task // each call to the processing function appends PR_STATUS note into note segment @@ -430,6 +432,11 @@ static int elf_process_tasks_regs(core_dump_elf_t *self) if (task == esp_core_dump_get_current_task_handle()) { continue; // skip current task (already processed) } + if (tasks_num > CONFIG_ESP_COREDUMP_MAX_TASKS_NUM) { + ESP_COREDUMP_LOG_PROCESS("Reached maximum number of tasks (%d), stopping task register processing", + CONFIG_ESP_COREDUMP_MAX_TASKS_NUM); + break; + } 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) { @@ -439,6 +446,7 @@ static int elf_process_tasks_regs(core_dump_elf_t *self) ELF_CHECK_ERR((ret > 0), ret, "Task %x, PR_STATUS write failed, return (%d).", task, ret); } len += ret; + tasks_num++; } } ret = elf_process_note_segment(self, len); // tasks regs note @@ -462,6 +470,25 @@ static int elf_save_task(core_dump_elf_t *self, core_dump_task_header_t *task) return elf_len; } +static int elf_save_interrupted_stack(core_dump_elf_t *self, core_dump_mem_seg_header_t *interrupted_stack) +{ + int ret = 0; + /* interrupt stacks: + - 'port_IntStack' is in the data section for xtensa + - 'xIsrStack' is in the bss section for risc-v + */ + 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); + } + return ret; +} + static int elf_write_tasks_data(core_dump_elf_t *self) { int elf_len = 0; @@ -469,8 +496,8 @@ static int elf_write_tasks_data(core_dump_elf_t *self) core_dump_task_header_t task_hdr = { 0 }; core_dump_mem_seg_header_t interrupted_stack = { 0 }; int ret = ELF_PROC_ERR_OTHER; - uint16_t tasks_num = 0; - uint16_t bad_tasks_num = 0; + int tasks_num = 0; + int bad_tasks_num = 0; ESP_COREDUMP_LOG_PROCESS("================ Processing task registers ================"); ret = elf_process_tasks_regs(self); @@ -478,31 +505,45 @@ static int elf_write_tasks_data(core_dump_elf_t *self) elf_len += ret; ESP_COREDUMP_LOG_PROCESS("================ Processing task data ================"); - // processes all task's stack data and writes segment data into partition - // if flash configuration is set - task = NULL; + + // first write crashed task data esp_core_dump_reset_tasks_snapshots_iter(); - while ((task = esp_core_dump_get_next_task(task))) { + task = esp_core_dump_get_current_task_handle(); + if (esp_core_dump_get_task_snapshot(task, &task_hdr, &interrupted_stack)) { + int ret = elf_save_task(self, &task_hdr); + ELF_CHECK_ERR((ret > 0), ret, + "Task %x, TCB write failed, return (%d).", task, ret); + elf_len += ret; + + // Handle interrupted stack (only relevant for current task) + ret = elf_save_interrupted_stack(self, &interrupted_stack); + if (ret > 0) { + elf_len += ret; + } tasks_num++; - if (!esp_core_dump_get_task_snapshot(task, &task_hdr, &interrupted_stack)) { + } + + 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 (tasks_num > CONFIG_ESP_COREDUMP_MAX_TASKS_NUM) { + ESP_COREDUMP_LOG_PROCESS("Reached maximum number of tasks (%d), stopping task register processing", + CONFIG_ESP_COREDUMP_MAX_TASKS_NUM); + break; + } + tasks_num++; + if (!esp_core_dump_get_task_snapshot(task, &task_hdr, NULL)) { bad_tasks_num++; continue; } + ret = elf_save_task(self, &task_hdr); ELF_CHECK_ERR((ret > 0), ret, "Task %x, TCB write failed, return (%d).", task, 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; } diff --git a/docs/en/api-guides/core_dump.rst b/docs/en/api-guides/core_dump.rst index b826e28842..9d0d1b52d9 100644 --- a/docs/en/api-guides/core_dump.rst +++ b/docs/en/api-guides/core_dump.rst @@ -29,7 +29,7 @@ The ELF format contains extended features and allows more information regarding The Binary format is kept for compatibility reasons. Binary format core dump files are smaller while provide better performance. -The :ref:`CONFIG_ESP_COREDUMP_MAX_TASKS_NUM` option configures the number of task snapshots saved by the core dump. +The :ref:`CONFIG_ESP_COREDUMP_MAX_TASKS_NUM` option configures the number of task snapshots saved by the core dump. Crashed task registers and the stack are always saved, regardless of this configuration option. Other tasks are included in order of their priority (starting with the highest-priority ready task). Core dump data integrity checking is supported via the ``Components`` > ``Core dump`` > ``Core dump data integrity check`` option. diff --git a/docs/zh_CN/api-guides/core_dump.rst b/docs/zh_CN/api-guides/core_dump.rst index ed18e49f15..2906c8bcfc 100644 --- a/docs/zh_CN/api-guides/core_dump.rst +++ b/docs/zh_CN/api-guides/core_dump.rst @@ -29,7 +29,7 @@ ELF 格式具备扩展特性,支持在发生崩溃时保存更多关于错误 出于兼容性考虑,核心转储文件保留二进制格式。二进制格式的核心转储文件更小,性能更优。 -选项 :ref:`CONFIG_ESP_COREDUMP_MAX_TASKS_NUM` 配置核心转储保存的任务快照数量。 +选项 :ref:`CONFIG_ESP_COREDUMP_MAX_TASKS_NUM` 可用于配置核心转储保存的任务快照数量。崩溃任务的寄存器和栈总是会被保存,不受此配置选项影响。其他任务的快照将根据优先级顺序(从就绪状态下优先级最高的任务开始)依次保存。 通过 ``Components`` > ``Core dump`` > ``Core dump data integrity check`` 选项可进行核心转储数据完整性检查。