mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
Merge branch 'coredump_save_all_regions_v5.3' into 'release/v5.3'
Save .bss, .data and .heap sections in to the coredump (v5.3) See merge request espressif/esp-idf!30438
This commit is contained in:
@@ -47,6 +47,18 @@ menu "Core dump"
|
||||
depends on ESP_COREDUMP_DATA_FORMAT_ELF
|
||||
endchoice
|
||||
|
||||
config ESP_COREDUMP_CAPTURE_DRAM
|
||||
bool "Include whole .bss and .data sections and heap data into core dump file"
|
||||
default n
|
||||
#TODO: Heap walker api is not ready for the esp32c5 (IDF-9641)
|
||||
depends on ESP_COREDUMP_DATA_FORMAT_ELF && !IDF_TARGET_ESP32C5
|
||||
help
|
||||
Storing these sections can help with easier debugging and troubleshooting.
|
||||
However, additional storage space will be required in the core dump partition.
|
||||
At least 128KB should be reserved, but the actual amount required may vary based
|
||||
on the application's DRAM usage.
|
||||
Note that sections located in external RAM will not be stored.
|
||||
|
||||
config ESP_COREDUMP_CHECK_BOOT
|
||||
bool "Check core dump data integrity on boot"
|
||||
default y
|
||||
@@ -112,7 +124,8 @@ menu "Core dump"
|
||||
help
|
||||
Size of the memory to be reserved for core dump stack. If 0 core dump process will run on
|
||||
the stack of crashed task/ISR, otherwise special stack will be allocated.
|
||||
To ensure that core dump itself will not overflow task/ISR stack set this to the value above 800.
|
||||
To ensure that core dump itself will not overflow task/ISR stack set this to the value around 1300-1800
|
||||
depending on the chosen checksum calculation method. SHA256 method needs more stack space than CRC32.
|
||||
NOTE: It eats DRAM.
|
||||
|
||||
config ESP_COREDUMP_SUMMARY_STACKDUMP_SIZE
|
||||
|
||||
@@ -20,15 +20,25 @@ extern "C" {
|
||||
* One can use these definitions to retrieve the start address and/or the size
|
||||
* of a specific region using the functions below.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
COREDUMP_MEMORY_DRAM,
|
||||
COREDUMP_MEMORY_IRAM,
|
||||
#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM
|
||||
COREDUMP_MEMORY_DRAM_BSS,
|
||||
COREDUMP_MEMORY_DRAM_DATA,
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
COREDUMP_MEMORY_DRAM_BSS_HIGH,
|
||||
COREDUMP_MEMORY_DRAM_DATA_HIGH,
|
||||
#endif
|
||||
#else
|
||||
COREDUMP_MEMORY_DRAM,
|
||||
#endif
|
||||
#if SOC_RTC_MEM_SUPPORTED
|
||||
COREDUMP_MEMORY_RTC,
|
||||
COREDUMP_MEMORY_RTC_FAST,
|
||||
#endif
|
||||
COREDUMP_MEMORY_MAX,
|
||||
COREDUMP_MEMORY_START = COREDUMP_MEMORY_DRAM
|
||||
COREDUMP_MEMORY_START = COREDUMP_MEMORY_IRAM
|
||||
} coredump_region_t;
|
||||
|
||||
/**
|
||||
@@ -126,6 +136,12 @@ esp_err_t esp_core_dump_write_data(core_dump_write_data_t *wr_data, void *data,
|
||||
*/
|
||||
esp_err_t esp_core_dump_write_end(core_dump_write_data_t *wr_data);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the stack information which will be used from the coredump module itself.
|
||||
* It will show the whole stack boundaries in case the stack is shared with the crashed task.
|
||||
*/
|
||||
void esp_core_dump_get_own_stack_info(uint32_t *addr, uint32_t *size);
|
||||
|
||||
/**
|
||||
* @brief Stores the core dump in either binary or ELF format.
|
||||
*/
|
||||
@@ -157,7 +173,7 @@ static inline core_dump_task_handle_t esp_core_dump_get_current_task_handle(void
|
||||
* @brief Get the length, in bytes, of a given memory location. Padding is
|
||||
* taken into account in this calculation.
|
||||
*
|
||||
* @param start Start address of the momery location.
|
||||
* @param start Start address of the memory location.
|
||||
* @param end End address of the memory location.
|
||||
*
|
||||
* @return Size of the memory location, multiple of sizeof(uint32_t).
|
||||
|
||||
@@ -25,6 +25,25 @@ const static char TAG[] __attribute__((unused)) = "esp_core_dump_common";
|
||||
/**
|
||||
* @brief Memory regions to dump, defined at compile time.
|
||||
*/
|
||||
#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM
|
||||
#if !CONFIG_IDF_TARGET_ESP32P4
|
||||
extern int _bss_start;
|
||||
extern int _bss_end;
|
||||
extern int _data_start;
|
||||
extern int _data_end;
|
||||
#else
|
||||
extern int _bss_start_low;
|
||||
extern int _bss_end_low;
|
||||
extern int _data_start_low;
|
||||
extern int _data_end_low;
|
||||
extern int _bss_start_high;
|
||||
extern int _bss_end_high;
|
||||
extern int _data_start_high;
|
||||
extern int _data_end_high;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Regions for the user defined variable locations */
|
||||
extern int _coredump_dram_start;
|
||||
extern int _coredump_dram_end;
|
||||
extern int _coredump_iram_start;
|
||||
@@ -160,6 +179,7 @@ FORCE_INLINE_ATTR void esp_core_dump_setup_stack(void)
|
||||
FORCE_INLINE_ATTR void esp_core_dump_report_stack_usage(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif // CONFIG_ESP_COREDUMP_STACK_SIZE > 0
|
||||
|
||||
static void* s_exc_frame = NULL;
|
||||
@@ -254,19 +274,29 @@ uint32_t esp_core_dump_get_user_ram_segments(void)
|
||||
return total_sz;
|
||||
}
|
||||
|
||||
uint32_t esp_core_dump_get_user_ram_size(void)
|
||||
{
|
||||
uint32_t total_sz = 0;
|
||||
|
||||
total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_dram_end, &_coredump_dram_start);
|
||||
#if SOC_RTC_MEM_SUPPORTED
|
||||
total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_rtc_end, &_coredump_rtc_start);
|
||||
total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_rtc_fast_end, &_coredump_rtc_fast_start);
|
||||
static const struct {
|
||||
int *start;
|
||||
int *end;
|
||||
} s_memory_sections[COREDUMP_MEMORY_MAX] = {
|
||||
[COREDUMP_MEMORY_IRAM] = { &_coredump_iram_start, &_coredump_iram_end },
|
||||
#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM
|
||||
#if !CONFIG_IDF_TARGET_ESP32P4
|
||||
[COREDUMP_MEMORY_DRAM_BSS] = { &_bss_start, &_bss_end },
|
||||
[COREDUMP_MEMORY_DRAM_DATA] = { &_data_start, &_data_end },
|
||||
#else
|
||||
[COREDUMP_MEMORY_DRAM_BSS] = { &_bss_start_low, &_bss_end_low },
|
||||
[COREDUMP_MEMORY_DRAM_DATA] = { &_data_start_low, &_data_end_low },
|
||||
[COREDUMP_MEMORY_DRAM_BSS_HIGH] = { &_bss_start_high, &_bss_end_high },
|
||||
[COREDUMP_MEMORY_DRAM_DATA_HIGH] = { &_data_start_high, &_data_end_high },
|
||||
#endif
|
||||
total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_iram_end, &_coredump_iram_start);
|
||||
|
||||
return total_sz;
|
||||
}
|
||||
#else
|
||||
[COREDUMP_MEMORY_DRAM] = { &_coredump_dram_start, &_coredump_dram_end },
|
||||
#endif
|
||||
#if SOC_RTC_MEM_SUPPORTED
|
||||
[COREDUMP_MEMORY_RTC] = { &_coredump_rtc_start, &_coredump_rtc_end },
|
||||
[COREDUMP_MEMORY_RTC_FAST] = { &_coredump_rtc_fast_start, &_coredump_rtc_fast_end },
|
||||
#endif
|
||||
};
|
||||
|
||||
int esp_core_dump_get_user_ram_info(coredump_region_t region, uint32_t *start)
|
||||
{
|
||||
@@ -274,36 +304,34 @@ int esp_core_dump_get_user_ram_info(coredump_region_t region, uint32_t *start)
|
||||
|
||||
ESP_COREDUMP_DEBUG_ASSERT(start != NULL);
|
||||
|
||||
switch (region) {
|
||||
case COREDUMP_MEMORY_DRAM:
|
||||
*start = (uint32_t)&_coredump_dram_start;
|
||||
total_sz = (uint8_t *)&_coredump_dram_end - (uint8_t *)&_coredump_dram_start;
|
||||
break;
|
||||
|
||||
case COREDUMP_MEMORY_IRAM:
|
||||
*start = (uint32_t)&_coredump_iram_start;
|
||||
total_sz = (uint8_t *)&_coredump_iram_end - (uint8_t *)&_coredump_iram_start;
|
||||
break;
|
||||
|
||||
#if SOC_RTC_MEM_SUPPORTED
|
||||
case COREDUMP_MEMORY_RTC:
|
||||
*start = (uint32_t)&_coredump_rtc_start;
|
||||
total_sz = (uint8_t *)&_coredump_rtc_end - (uint8_t *)&_coredump_rtc_start;
|
||||
break;
|
||||
|
||||
case COREDUMP_MEMORY_RTC_FAST:
|
||||
*start = (uint32_t)&_coredump_rtc_fast_start;
|
||||
total_sz = (uint8_t *)&_coredump_rtc_fast_end - (uint8_t *)&_coredump_rtc_fast_start;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
if (region >= COREDUMP_MEMORY_START && region < COREDUMP_MEMORY_MAX) {
|
||||
total_sz = (uint8_t *)s_memory_sections[region].end - (uint8_t *)s_memory_sections[region].start;
|
||||
*start = (uint32_t)s_memory_sections[region].start;
|
||||
}
|
||||
|
||||
return total_sz;
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM
|
||||
void esp_core_dump_get_own_stack_info(uint32_t *addr, uint32_t *size)
|
||||
{
|
||||
#if CONFIG_ESP_COREDUMP_STACK_SIZE > 0
|
||||
/* Custom stack reserved for the coredump */
|
||||
*addr = (uint32_t)s_coredump_stack;
|
||||
*size = sizeof(s_coredump_stack);
|
||||
#else
|
||||
/* Shared stack with the crashed task */
|
||||
core_dump_task_handle_t handle = esp_core_dump_get_current_task_handle();
|
||||
TaskSnapshot_t rtos_snapshot = { 0 };
|
||||
vTaskGetSnapshot(handle, &rtos_snapshot);
|
||||
StaticTask_t *current = (StaticTask_t *)handle;
|
||||
*addr = (uint32_t)current->pxDummy6; //pxStack
|
||||
*size = (uint32_t)rtos_snapshot.pxTopOfStack - (uint32_t)current->pxDummy6; /* free */
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ESP_COREDUMP_CAPTURE_DRAM */
|
||||
|
||||
inline bool esp_core_dump_tcb_addr_is_sane(uint32_t addr)
|
||||
{
|
||||
return esp_core_dump_mem_seg_is_sane(addr, esp_core_dump_get_tcb_len());
|
||||
|
||||
@@ -80,6 +80,11 @@ typedef struct _core_dump_elf_t {
|
||||
uint16_t segs_count;
|
||||
core_dump_write_data_t write_data;
|
||||
uint32_t note_data_size; /* can be used where static storage needed */
|
||||
#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM
|
||||
/* To avoid checksum failure, coredump stack region will be excluded while storing the sections. */
|
||||
uint32_t coredump_stack_start;
|
||||
uint32_t coredump_stack_size;
|
||||
#endif
|
||||
} core_dump_elf_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -474,10 +479,17 @@ static int elf_write_tasks_data(core_dump_elf_t *self)
|
||||
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_iter.pxTaskHandle, ret);
|
||||
elf_len += ret;
|
||||
|
||||
#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM
|
||||
/* Only crashed task data will be saved here. The other task's data will be automatically saved within the sections */
|
||||
if (esp_core_dump_get_current_task_handle() == task_iter.pxTaskHandle)
|
||||
#endif
|
||||
{
|
||||
ret = elf_save_task(self, &task_hdr);
|
||||
ELF_CHECK_ERR((ret > 0), ret,
|
||||
"Task %x, TCB write failed, return (%d).", task_iter.pxTaskHandle, 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);
|
||||
@@ -493,28 +505,148 @@ static int elf_write_tasks_data(core_dump_elf_t *self)
|
||||
return elf_len;
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM
|
||||
|
||||
/* Coredump stack will also be used by the checksum functions while saving sections.
|
||||
* There is a potential for inconsistency when writing coredump stack to the flash and calculating checksum simultaneously.
|
||||
* This is because, coredump stack will be modified during the process, leading to incorrect checksum calculations.
|
||||
* To mitigate this issue, it's important to ensure that the coredump stack excluded from checksum calculation by
|
||||
* filter out from the written regions.
|
||||
* Typically, the coredump stack can be located in two different sections.
|
||||
* 1. In the bss section;
|
||||
* 1.a if `CONFIG_ESP_COREDUMP_STACK_SIZE` set to a nonzero value
|
||||
* 1.b if the crashed task is created with a static task buffer using the xTaskCreateStatic() api
|
||||
* 2. In the heap section, if custom stack is not defined and the crashed task buffer is allocated in the heap
|
||||
* with the xTaskCreate() api
|
||||
*
|
||||
* esp_core_dump_store_section() will check if the coredump stack is located inside the section.
|
||||
* If it is, this part will be skipped.
|
||||
* |+++++++++| xxxxxxxxxxxxxx |++++++++|
|
||||
* |+++++++++| coredump stack |++++++++|
|
||||
*/
|
||||
static int esp_core_dump_store_section(core_dump_elf_t *self, uint32_t start, uint32_t data_len)
|
||||
{
|
||||
uint32_t end = start + data_len;
|
||||
int total_sz = 0;
|
||||
int ret;
|
||||
|
||||
if (self->coredump_stack_start > start && self->coredump_stack_start < end) {
|
||||
/* write until the coredump stack. */
|
||||
data_len = self->coredump_stack_start - start;
|
||||
ret = elf_add_segment(self, PT_LOAD,
|
||||
start,
|
||||
(void*)start,
|
||||
data_len);
|
||||
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
}
|
||||
total_sz += ret;
|
||||
|
||||
/* Skip coredump stack and set offset for the rest of the section */
|
||||
start = self->coredump_stack_start + self->coredump_stack_size;
|
||||
data_len = end - start;
|
||||
}
|
||||
|
||||
if (data_len > 0) {
|
||||
ret = elf_add_segment(self, PT_LOAD,
|
||||
(uint32_t)start,
|
||||
(void*)start,
|
||||
(uint32_t)data_len);
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
}
|
||||
total_sz += ret;
|
||||
}
|
||||
|
||||
return total_sz;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
core_dump_elf_t *self;
|
||||
int *total_sz;
|
||||
int ret;
|
||||
} heap_block_data_t;
|
||||
|
||||
bool esp_core_dump_write_heap_blocks(walker_heap_into_t heap_info, walker_block_info_t block_info, void* user_data)
|
||||
{
|
||||
heap_block_data_t *param = user_data;
|
||||
int *total_sz = param->total_sz;
|
||||
core_dump_elf_t *self = param->self;
|
||||
int *ret = ¶m->ret;
|
||||
|
||||
if (*ret <= 0) {
|
||||
/* There was a flash write failure at the previous write attempt */
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((intptr_t)heap_info.end - (intptr_t)block_info.ptr < block_info.size) {
|
||||
ESP_COREDUMP_LOGE("Block corruption detected in the heap (%p-%p)", heap_info.start, heap_info.end);
|
||||
ESP_COREDUMP_LOGE("Corrupted block addr:%p size:%x)", block_info.ptr, block_info.size);
|
||||
/* Heap walker will skip the next block in the same heap region and it will continue from the next heap region's block. */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (block_info.used && block_info.size > 0) {
|
||||
ESP_COREDUMP_LOG_PROCESS("heap block @%p sz:(%x)", (void *)block_info.ptr, block_info.size);
|
||||
|
||||
if (!esp_core_dump_mem_seg_is_sane((uint32_t)block_info.ptr, block_info.size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self->coredump_stack_start == (uint32_t)block_info.ptr) {
|
||||
/* skip writing coredump stack block */
|
||||
return true;
|
||||
}
|
||||
|
||||
*ret = elf_add_segment(self, PT_LOAD,
|
||||
(uint32_t)block_info.ptr,
|
||||
(void*)block_info.ptr,
|
||||
block_info.size);
|
||||
if (*ret <= 0) {
|
||||
return false;
|
||||
}
|
||||
*total_sz += *ret;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int esp_core_dump_store_section(core_dump_elf_t *self, uint32_t start, uint32_t data_len)
|
||||
{
|
||||
return elf_add_segment(self, PT_LOAD,
|
||||
start,
|
||||
(void*)start,
|
||||
data_len);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int elf_write_core_dump_user_data(core_dump_elf_t *self)
|
||||
{
|
||||
int data_len = 0;
|
||||
int total_sz = 0;
|
||||
uint32_t start = 0;
|
||||
|
||||
for (coredump_region_t i = COREDUMP_MEMORY_START; i < COREDUMP_MEMORY_MAX; i++) {
|
||||
data_len = esp_core_dump_get_user_ram_info(i, &start);
|
||||
int data_len = esp_core_dump_get_user_ram_info(i, &start);
|
||||
|
||||
ELF_CHECK_ERR((data_len >= 0), ELF_PROC_ERR_OTHER, "invalid memory region");
|
||||
|
||||
if (data_len > 0) {
|
||||
int ret = elf_add_segment(self, PT_LOAD,
|
||||
(uint32_t)start,
|
||||
(void*)start,
|
||||
(uint32_t) data_len);
|
||||
|
||||
int ret = esp_core_dump_store_section(self, start, data_len);
|
||||
ELF_CHECK_ERR((ret > 0), ret, "memory region write failed. Returned (%d).", ret);
|
||||
total_sz += ret;
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM
|
||||
heap_block_data_t user_data = {.self = self, .total_sz = &total_sz, .ret = 1};
|
||||
heap_caps_walk(MALLOC_CAP_8BIT, esp_core_dump_write_heap_blocks, &user_data);
|
||||
ELF_CHECK_ERR((user_data.ret > 0), user_data.ret, "Heap memory write failed. Returned (%d).", user_data.ret);
|
||||
#endif
|
||||
|
||||
return total_sz;
|
||||
}
|
||||
|
||||
@@ -676,6 +808,12 @@ static esp_err_t esp_core_dump_write_elf(void)
|
||||
int tot_len = sizeof(dump_hdr);
|
||||
int write_len = sizeof(dump_hdr);
|
||||
|
||||
#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM
|
||||
esp_core_dump_get_own_stack_info(&self.coredump_stack_start, &self.coredump_stack_size);
|
||||
ESP_COREDUMP_LOG_PROCESS("Core dump stack start=%p size = %d",
|
||||
(void *)self.coredump_stack_start, self.coredump_stack_size);
|
||||
#endif
|
||||
|
||||
esp_err_t err = esp_core_dump_write_init();
|
||||
if (err != ESP_OK) {
|
||||
ESP_COREDUMP_LOGE("Elf write init failed!");
|
||||
|
||||
Reference in New Issue
Block a user