Merge branch 'fix/coredump_max_tasks_num' into 'master'

fix(coredump): implement CONFIG_ESP_COREDUMP_MAX_TASKS_NUM limitation

Closes IDFGH-13516

See merge request espressif/esp-idf!41008
This commit is contained in:
Erhan Kurubas
2025-08-08 10:36:24 +02:00
12 changed files with 104 additions and 49 deletions

View File

@@ -62,7 +62,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"

View File

@@ -80,6 +80,7 @@ void esp_core_dump_init(void);
*/
void esp_core_dump_write(panic_info_t *info);
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
/**
* @brief Check integrity of coredump data in flash.
* This function reads the coredump data while calculating their checksum. If it
@@ -113,8 +114,6 @@ esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size);
*/
esp_err_t esp_core_dump_image_erase(void);
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
/**
* @brief Get panic reason from the core dump.
*

View File

@@ -1,11 +1,14 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#if CONFIG_ESP_COREDUMP_ENABLE
#include <string.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "soc/soc_memory_layout.h"
#include "freertos/FreeRTOS.h"
#include "esp_private/freertos_debug.h"
@@ -18,8 +21,6 @@
const static char TAG[] __attribute__((unused)) = "esp_core_dump_common";
#if CONFIG_ESP_COREDUMP_ENABLE
#define COREDUMP_GET_MEMORY_SIZE(end, start) (end - start)
/**
@@ -345,4 +346,4 @@ void esp_core_dump_write(panic_info_t *info)
esp_core_dump_print_write_end();
}
#endif
#endif // CONFIG_ESP_COREDUMP_ENABLE

View File

@@ -3,11 +3,14 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#if CONFIG_ESP_COREDUMP_ENABLE
#include <string.h>
#include "esp_attr.h"
#include "esp_partition.h"
#include "esp_flash_encrypt.h"
#include "sdkconfig.h"
#include "core_dump_checksum.h"
#include "esp_core_dump_port.h"
#include "esp_core_dump_port_impl.h"
@@ -406,6 +409,7 @@ static int elf_process_tasks_regs(core_dump_elf_t *self)
void *task = NULL;
int len = 0;
int ret = 0;
uint16_t tasks_num = 0;
esp_core_dump_reset_tasks_snapshots_iter();
task = esp_core_dump_get_current_task_handle();
@@ -419,6 +423,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
@@ -429,6 +434,11 @@ static int elf_process_tasks_regs(core_dump_elf_t *self)
if (!task || task == esp_core_dump_get_current_task_handle()) { // skip current task (already processed)
continue;
}
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) {
@@ -438,6 +448,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
@@ -461,6 +472,28 @@ 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;
#if !CONFIG_ESP_COREDUMP_CAPTURE_DRAM
/* interrupt stacks:
- 'port_IntStack' is in the data section for xtensa
- 'xIsrStack' is in the bss section for risc-v
When DRAM capture is enabled, interrupt stack saving can be done during the full section store
*/
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);
}
#endif
return ret;
}
static int elf_process_task_data(core_dump_elf_t *self)
{
int elf_len = 0;
@@ -471,13 +504,37 @@ static int elf_process_task_data(core_dump_elf_t *self)
uint16_t bad_tasks_num = 0;
ESP_COREDUMP_LOG_PROCESS("================ Processing task data ================");
// processes all task's stack data and writes segment data into partition
// if flash configuration is set
// first write crashed task data
esp_core_dump_reset_tasks_snapshots_iter();
void *current_task = esp_core_dump_get_current_task_handle();
if (esp_core_dump_get_task_snapshot(current_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).", current_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++;
}
esp_core_dump_task_iterator_init(&task_iter);
while (esp_core_dump_task_iterator_next(&task_iter) != -1) {
// Skip the current task (already processed above)
if (!task_iter.pxTaskHandle || task_iter.pxTaskHandle == current_task) {
continue;
}
if (tasks_num > CONFIG_ESP_COREDUMP_MAX_TASKS_NUM) {
ESP_COREDUMP_LOG_PROCESS("Reached maximum number of tasks (%d), stopping task data processing",
CONFIG_ESP_COREDUMP_MAX_TASKS_NUM);
break;
}
tasks_num++;
if (!esp_core_dump_get_task_snapshot(task_iter.pxTaskHandle, &task_hdr, &interrupted_stack)) {
if (!esp_core_dump_get_task_snapshot(task_iter.pxTaskHandle, &task_hdr, NULL)) {
bad_tasks_num++;
continue;
}
@@ -485,23 +542,6 @@ static int elf_process_task_data(core_dump_elf_t *self)
ELF_CHECK_ERR((ret > 0), ret,
"Task %x, TCB write failed, return (%d).", task_iter.pxTaskHandle, ret);
elf_len += ret;
/* interrupt stacks:
- 'port_IntStack' is in the data section for xtensa
- 'xIsrStack' is in the bss section for risc-v
When DRAM capture is enabled, interrupt stack saving can be done during the full section store
*/
#if !CONFIG_ESP_COREDUMP_CAPTURE_DRAM
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;
}
#endif
}
ESP_COREDUMP_LOG_PROCESS("Found %d bad task out of %d", bad_tasks_num, tasks_num);
@@ -1021,3 +1061,5 @@ esp_err_t esp_core_dump_get_summary(esp_core_dump_summary_t *summary)
}
#endif // CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
#endif // CONFIG_ESP_COREDUMP_ENABLE

View File

@@ -1,8 +1,12 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
#include <string.h>
#include "esp_partition.h"
#include "esp_log.h"
@@ -18,8 +22,6 @@
const static char TAG[] __attribute__((unused)) = "esp_core_dump_flash";
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
typedef struct _core_dump_partition_t {
/* Core dump partition start. */
uint32_t start;
@@ -398,8 +400,6 @@ esp_err_t esp_core_dump_image_check(void)
return ESP_OK;
}
#endif
esp_err_t esp_core_dump_image_erase(void)
{
/* If flash is encrypted, we can only write blocks of 16 bytes, let's always
@@ -522,3 +522,5 @@ esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
return ESP_OK;
}
#endif // CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH

View File

@@ -1,11 +1,12 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#if CONFIG_ESP_COREDUMP_ENABLE
#include <string.h>
#include "esp_core_dump_types.h"
@@ -122,3 +123,5 @@ static uint32_t core_dump_sha_finish(core_dump_checksum_ctx cks_ctx, core_dump_c
return core_dump_sha_size();
}
#endif // CONFIG_ESP_COREDUMP_ENABLE

View File

@@ -1,8 +1,12 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#if CONFIG_ESP_COREDUMP_ENABLE_TO_UART
#include <string.h>
#include "soc/uart_reg.h"
#include "soc/gpio_periph.h"
@@ -16,8 +20,6 @@
const static char TAG[] __attribute__((unused)) = "esp_core_dump_uart";
#if CONFIG_ESP_COREDUMP_ENABLE_TO_UART
void esp_core_dump_print_write_start(void) __attribute__((alias("esp_core_dump_uart_print_write_start")));
void esp_core_dump_print_write_end(void) __attribute__((alias("esp_core_dump_uart_print_write_end")));
esp_err_t esp_core_dump_write_init(void) __attribute__((alias("esp_core_dump_uart_hw_init")));
@@ -176,4 +178,5 @@ void esp_core_dump_init(void)
{
ESP_COREDUMP_LOGI("Init core dump to UART");
}
#endif
#endif // CONFIG_ESP_COREDUMP_ENABLE_TO_UART

View File

@@ -9,6 +9,10 @@
* @brief Core dump port implementation for RISC-V based boards.
*/
#include "sdkconfig.h"
#if CONFIG_ESP_COREDUMP_ENABLE
#include <string.h>
#include <stdbool.h>
#include "soc/soc_memory_layout.h"
@@ -29,8 +33,6 @@ const static char TAG[] __attribute__((unused)) = "esp_core_dump_port";
#define COREDUMP_FAKE_STACK_START 0x20000000U
#define COREDUMP_FAKE_STACK_LIMIT 0x30000000U
#if CONFIG_ESP_COREDUMP_ENABLE
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) < (b) ? (b) : (a))
@@ -447,4 +449,4 @@ void esp_core_dump_summary_parse_backtrace_info(esp_core_dump_bt_info_t *bt_info
#endif /* #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH */
#endif
#endif /* CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH */

View File

@@ -9,6 +9,10 @@
* @brief Core dump port implementation for Xtensa based boards.
*/
#include "sdkconfig.h"
#if CONFIG_ESP_COREDUMP_ENABLE
#include <string.h>
#include <stdbool.h>
#include "soc/soc_memory_layout.h"
@@ -121,8 +125,6 @@ typedef struct {
uint32_t reserved;
} __attribute__((packed)) xtensa_elf_reg_dump_t;
#if CONFIG_ESP_COREDUMP_ENABLE
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
@@ -565,4 +567,4 @@ void esp_core_dump_summary_parse_backtrace_info(esp_core_dump_bt_info_t *bt_info
#endif /* #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH */
#endif
#endif /* CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH */

View File

@@ -31,7 +31,7 @@ Format & Size
Core dump files are generated in ELF format, which contains extended features and allows comprehensive information regarding erroneous tasks and crashed software to be saved. The ELF format is flexible and can be extended in future revisions to save additional information.
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).
Data Integrity Check
^^^^^^^^^^^^^^^^^^^^

View File

@@ -31,14 +31,13 @@
核心转储文件以 ELF 格式生成该格式具有可扩展性能够在系统崩溃时完整保存错误任务和故障软件的详细信息。ELF 格式具备良好的扩展灵活性,便于未来版本升级时存储更多诊断信息。
选项 :ref:`CONFIG_ESP_COREDUMP_MAX_TASKS_NUM` 可用于配置核心转储保存的任务快照数量。
选项 :ref:`CONFIG_ESP_COREDUMP_MAX_TASKS_NUM` 可用于配置核心转储保存的任务快照数量。崩溃任务的寄存器和栈总是会被保存,不受此配置选项影响。其他任务的快照将根据优先级顺序(从就绪状态下优先级最高的任务开始)依次保存。
数据完整性检查
^^^^^^^^^^^^^^^^^^^^
核心转储文件包含 SHA256 校验和用于验证核心转储文件的完整性确保文件未被损坏。SHA256 哈希算法在检测损坏方面具有很高的准确率,包括多位错误。
保留栈大小
^^^^^^^^^^^^^^^^^^^