diff --git a/components/esp32/ld/esp32.project.ld.in b/components/esp32/ld/esp32.project.ld.in index 720cf1b97..369ebb5d6 100644 --- a/components/esp32/ld/esp32.project.ld.in +++ b/components/esp32/ld/esp32.project.ld.in @@ -36,8 +36,14 @@ SECTIONS { . = ALIGN(4); _rtc_force_fast_start = ABSOLUTE(.); + + _coredump_rtc_fast_start = ABSOLUTE(.); + mapping[rtc_fast_coredump] + _coredump_rtc_fast_end = ABSOLUTE(.); + *(.rtc.force_fast .rtc.force_fast.*) . = ALIGN(4) ; + _rtc_force_fast_end = ABSOLUTE(.); } > rtc_data_seg @@ -52,10 +58,17 @@ SECTIONS { _rtc_data_start = ABSOLUTE(.); - mapping[rtc_data] + /* coredump mapping */ + _coredump_rtc_start = ABSOLUTE(.); + mapping[rtc_coredump] + _coredump_rtc_end = ABSOLUTE(.); + /* should be placed after coredump mapping */ + mapping[rtc_data] + *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .bss .bss.*) _rtc_data_end = ABSOLUTE(.); + } > rtc_data_location /* RTC bss, from any source file named rtc_wake_stub*.c */ @@ -151,6 +164,7 @@ SECTIONS *(.entry.text) *(.init.literal) *(.init) + _init_end = ABSOLUTE(.); } > iram0_0_seg @@ -188,7 +202,12 @@ SECTIONS *(.gnu.linkonce.s2.*) *(.jcr) - + /* coredump mapping */ + _coredump_dram_start = ABSOLUTE(.); + mapping[dram_coredump] + _coredump_dram_end = ABSOLUTE(.); + + /* should be placed after coredump mapping */ mapping[dram0_data] _data_end = ABSOLUTE(.); @@ -346,6 +365,12 @@ SECTIONS . = ALIGN(4); _iram_data_start = ABSOLUTE(.); + /* coredump mapping */ + _coredump_iram_start = ABSOLUTE(.); + mapping[iram_coredump] + _coredump_iram_end = ABSOLUTE(.); + + /* should be placed after coredump mapping */ mapping[iram0_data] _iram_data_end = ABSOLUTE(.); diff --git a/components/esp32/ld/esp32_fragments.lf b/components/esp32/ld/esp32_fragments.lf index cfdc79cea..2ab27f109 100644 --- a/components/esp32/ld/esp32_fragments.lf +++ b/components/esp32/ld/esp32_fragments.lf @@ -36,6 +36,22 @@ entries: entries: .rtc.bss +[sections:rtc_fast_coredump] +entries: + .rtc.fast.coredump+ + +[sections:rtc_coredump] +entries: + .rtc.coredump+ + +[sections:dram_coredump] +entries: + .dram1.coredump+ + +[sections:iram_coredump] +entries: + .iram.data.coredump+ + [sections:iram] entries: .iram1+ @@ -81,6 +97,10 @@ entries: rtc_bss -> rtc_bss wifi_iram -> flash_text wifi_rx_iram -> flash_text + dram_coredump -> dram_coredump + iram_coredump -> iram_coredump + rtc_coredump -> rtc_coredump + rtc_fast_coredump -> rtc_fast_coredump [scheme:rtc] entries: diff --git a/components/esp32s2/ld/esp32s2.project.ld.in b/components/esp32s2/ld/esp32s2.project.ld.in index d91dc1de3..cffa42e9c 100644 --- a/components/esp32s2/ld/esp32s2.project.ld.in +++ b/components/esp32s2/ld/esp32s2.project.ld.in @@ -36,6 +36,11 @@ SECTIONS { . = ALIGN(4); _rtc_force_fast_start = ABSOLUTE(.); + + _coredump_rtc_fast_start = ABSOLUTE(.); + mapping[rtc_fast_coredump] + _coredump_rtc_fast_end = ABSOLUTE(.); + *(.rtc.force_fast .rtc.force_fast.*) . = ALIGN(4) ; _rtc_force_fast_end = ABSOLUTE(.); @@ -52,6 +57,12 @@ SECTIONS { _rtc_data_start = ABSOLUTE(.); + /* coredump mapping */ + _coredump_rtc_start = ABSOLUTE(.); + mapping[rtc_coredump] + _coredump_rtc_end = ABSOLUTE(.); + + /* should be placed after coredump mapping */ mapping[rtc_data] *rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .bss .bss.*) @@ -161,6 +172,10 @@ SECTIONS mapping[iram0_text] + /* added to maintain compability */ + _coredump_iram_start = 0; + _coredump_iram_end = 0; + /* align + add 16B for the possibly overlapping instructions */ . = ALIGN(4) + 16; _iram_text_end = ABSOLUTE(.); @@ -193,6 +208,12 @@ SECTIONS *(.gnu.linkonce.s2.*) *(.jcr) + /* coredump mapping */ + _coredump_dram_start = ABSOLUTE(.); + mapping[dram_coredump] + _coredump_dram_end = ABSOLUTE(.); + + /* should be placed after coredump mapping */ mapping[dram0_data] _data_end = ABSOLUTE(.); diff --git a/components/esp32s2/ld/esp32s2_fragments.lf b/components/esp32s2/ld/esp32s2_fragments.lf index 83a282dcb..72b74b63b 100644 --- a/components/esp32s2/ld/esp32s2_fragments.lf +++ b/components/esp32s2/ld/esp32s2_fragments.lf @@ -36,6 +36,18 @@ entries: entries: .rtc.bss +[sections:rtc_fast_coredump] +entries: + .rtc.fast.coredump+ + +[sections:rtc_coredump] +entries: + .rtc.coredump+ + +[sections:dram_coredump] +entries: + .dram1.coredump+ + [sections:iram] entries: .iram1+ @@ -67,6 +79,9 @@ entries: rtc_bss -> rtc_bss wifi_iram -> flash_text wifi_rx_iram -> flash_text + dram_coredump -> dram_coredump + rtc_coredump -> rtc_coredump + rtc_fast_coredump -> rtc_fast_coredump [scheme:rtc] entries: diff --git a/components/espcoredump/espcoredump.py b/components/espcoredump/espcoredump.py index 9baa8fdeb..f9f7179a2 100755 --- a/components/espcoredump/espcoredump.py +++ b/components/espcoredump/espcoredump.py @@ -1727,11 +1727,6 @@ def info_corefile(args): def main(): parser = argparse.ArgumentParser(description='espcoredump.py v%s - ESP32 Core Dump Utility' % __version__, prog='espcoredump') - parser.add_argument('--chip', '-c', - help='Target chip type', - choices=['auto', 'esp32'], - default=os.environ.get('ESPTOOL_CHIP', 'auto')) - parser.add_argument( '--port', '-p', help='Serial port device', diff --git a/components/espcoredump/include_core_dump/esp_core_dump_port.h b/components/espcoredump/include_core_dump/esp_core_dump_port.h index 49090cf33..e66c60b93 100644 --- a/components/espcoredump/include_core_dump/esp_core_dump_port.h +++ b/components/espcoredump/include_core_dump/esp_core_dump_port.h @@ -41,6 +41,15 @@ extern "C" { #define COREDUMP_TCB_SIZE sizeof(StaticTask_t) +typedef enum { + COREDUMP_MEMORY_DRAM, + COREDUMP_MEMORY_IRAM, + COREDUMP_MEMORY_RTC, + COREDUMP_MEMORY_RTC_FAST, + COREDUMP_MEMORY_MAX, + COREDUMP_MEMORY_START = COREDUMP_MEMORY_DRAM +} coredump_region_t; + // Gets RTOS tasks snapshot uint32_t esp_core_dump_get_tasks_snapshot(core_dump_task_header_t** const tasks, const uint32_t snapshot_size); @@ -60,6 +69,10 @@ uint32_t esp_core_dump_get_task_regs_dump(core_dump_task_header_t *task, void ** void esp_core_dump_init_extra_info(void); uint32_t esp_core_dump_get_extra_info(void **info); +uint32_t esp_core_dump_get_user_ram_segments(void); +uint32_t esp_core_dump_get_user_ram_size(void); +int esp_core_dump_get_user_ram_info(coredump_region_t region, uint32_t *start); + // Data integrity check functions void esp_core_dump_checksum_init(core_dump_write_data_t* wr_data); void esp_core_dump_checksum_update(core_dump_write_data_t* wr_data, void* data, size_t data_len); @@ -122,6 +135,16 @@ extern uint8_t *s_core_dump_sp; } #endif +// coredump memory regions defined during compile timing +extern int _coredump_dram_start; +extern int _coredump_dram_end; +extern int _coredump_iram_start; +extern int _coredump_iram_end; +extern int _coredump_rtc_start; +extern int _coredump_rtc_end; +extern int _coredump_rtc_fast_start; +extern int _coredump_rtc_fast_end; + #ifdef __cplusplus } #endif diff --git a/components/espcoredump/src/core_dump_common.c b/components/espcoredump/src/core_dump_common.c index 09899b2d2..50b4aeead 100644 --- a/components/espcoredump/src/core_dump_common.c +++ b/components/espcoredump/src/core_dump_common.c @@ -29,7 +29,7 @@ static inline uint32_t esp_core_dump_get_tcb_len(void) return COREDUMP_TCB_SIZE; } -static inline uint32_t esp_core_dump_get_stack_len(uint32_t stack_start, uint32_t stack_end) +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 @@ -43,7 +43,7 @@ static esp_err_t esp_core_dump_save_task(core_dump_write_config_t *write_cfg, uint32_t stk_vaddr, stk_len; uint32_t stk_paddr = esp_core_dump_get_stack(task, &stk_vaddr, &stk_len); - stk_len = esp_core_dump_get_stack_len(stk_vaddr, stk_vaddr+stk_len); + stk_len = esp_core_dump_get_memory_len(stk_vaddr, stk_vaddr+stk_len); // Save TCB address, stack base and stack top addr err = write_cfg->write(write_cfg->priv, (void*)task, sizeof(core_dump_task_header_t)); @@ -114,6 +114,7 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_ ESP_COREDUMP_LOGI("Found tasks: %d!", task_num); // Verifies all tasks in the snapshot + for (task_id = 0; task_id < task_num; task_id++) { bool is_current_task = false, stack_is_valid = false; bool tcb_is_valid = esp_core_dump_check_task(frame, tasks[task_id], &is_current_task, &stack_is_valid); @@ -131,21 +132,21 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_ // Increase core dump size by task stack size uint32_t stk_vaddr, stk_len; esp_core_dump_get_stack(tasks[task_id], &stk_vaddr, &stk_len); - data_len += esp_core_dump_get_stack_len(stk_vaddr, stk_vaddr+stk_len); + data_len += esp_core_dump_get_memory_len(stk_vaddr, stk_vaddr+stk_len); // Add tcb size data_len += (tcb_sz + sizeof(core_dump_task_header_t)); } 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_stack_len(tasks[curr_task_index]->stack_start, tasks[curr_task_index]->stack_end); + 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)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_stack_len(tasks[curr_task_index]->stack_start, tasks[curr_task_index]->stack_end); + 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 @@ -154,6 +155,22 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_ curr_task_index = 0; } + // Add user memory region header 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++) { + uint32_t start = 0; + int data_sz = esp_core_dump_get_user_ram_info(i, &start); + + if (data_sz < 0) { + ESP_COREDUMP_LOGE("Invalid memory segment size"); + return ESP_FAIL; + } + + if (data_sz > 0) { + data_len += esp_core_dump_get_memory_len(start, start + data_sz); + } + } + // Add core dump header size data_len += sizeof(core_dump_header_t); @@ -185,6 +202,7 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_ if (xPortInterruptedFromISRContext()) { 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; err = write_cfg->write(write_cfg->priv, &hdr, sizeof(core_dump_header_t)); if (err != ESP_OK) { @@ -221,6 +239,30 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_ } } + // save user memory regions + 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++) { + uint32_t start = 0; + int data_sz = esp_core_dump_get_user_ram_info(i, &start); + + if (data_sz < 0) { + ESP_COREDUMP_LOGE("Invalid memory segment size"); + return ESP_FAIL; + } + + if (data_sz > 0) { + user_ram_stack_size.start = start; + user_ram_stack_size.size = esp_core_dump_get_memory_len(start, start + data_sz);; + err = esp_core_dump_save_mem_segment(write_cfg, &user_ram_stack_size); + if (err != ESP_OK) { + ESP_COREDUMP_LOGE("Failed to save user memory data, error=%d!", err); + return err; + } + } + } + } + // Write end if (write_cfg->end) { err = write_cfg->end(write_cfg->priv); @@ -234,6 +276,7 @@ static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_ } return err; } + #endif inline void esp_core_dump_write(void *frame, core_dump_write_config_t *write_cfg) diff --git a/components/espcoredump/src/core_dump_elf.c b/components/espcoredump/src/core_dump_elf.c index 0414178c9..308422d4f 100644 --- a/components/espcoredump/src/core_dump_elf.c +++ b/components/espcoredump/src/core_dump_elf.c @@ -23,7 +23,9 @@ #include "elf.h" // for ELF file types #define ELF_SEG_HEADERS_COUNT(_self_, _task_num_) (uint32_t)((_task_num_) * 2/*stack + tcb*/ \ - + 1/* regs notes */ + 1/* ver info + extra note */ + ((_self_)->interrupted_task.stack_start ? 1 : 0)) + + 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_CORE_SEC_TYPE 1 @@ -508,6 +510,31 @@ static int elf_write_tasks_data(core_dump_elf_t *self, void* frame, return elf_len; } +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); + + 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); + + ELF_CHECK_ERR((ret > 0), ret, "memory region write failed. Returned (%d).", ret); + total_sz += ret; + } + } + + return total_sz; +} + static int elf_write_core_dump_info(core_dump_elf_t *self) { void *extra_info; @@ -562,6 +589,12 @@ static int esp_core_dump_do_write_elf_pass(core_dump_elf_t *self, void* frame, data_sz = elf_write_tasks_data(self, frame, tasks, task_num); ELF_CHECK_ERR((data_sz > 0), data_sz, "ELF Size writing error, returned (%d).", data_sz); tot_len += data_sz; + + // write core dump memory regions defined by user + data_sz = elf_write_core_dump_user_data(self); + ELF_CHECK_ERR((data_sz >= 0), data_sz, "memory regions writing error, returned (%d).", data_sz); + tot_len += data_sz; + // write data with version control information and some extra info // this should go after tasks processing data_sz = elf_write_core_dump_info(self); diff --git a/components/espcoredump/src/core_dump_port.c b/components/espcoredump/src/core_dump_port.c index 6641a9ae4..c3ea66632 100644 --- a/components/espcoredump/src/core_dump_port.c +++ b/components/espcoredump/src/core_dump_port.c @@ -37,6 +37,8 @@ const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_port" #define COREDUMP_GET_EPS(reg, ptr) \ if (reg - EPS_2 + 2 <= XCHAL_NUM_INTLEVELS) COREDUMP_GET_REG_PAIR(reg, ptr) +#define COREDUMP_GET_MEMORY_SIZE(end, start) (end - start) + // Enumeration of registers of exception stack frame // and solicited stack frame typedef enum @@ -260,8 +262,14 @@ inline uint16_t esp_core_dump_get_arch_id() inline bool esp_core_dump_mem_seg_is_sane(uint32_t addr, uint32_t sz) { - //TODO: currently core dump supports memory segments in DRAM only, external SRAM not supported yet - return esp_ptr_in_dram((void *)addr) && esp_ptr_in_dram((void *)(addr+sz-1)); + //TODO: external SRAM not supported yet + return (esp_ptr_in_dram((void *)addr) && esp_ptr_in_dram((void *)(addr+sz-1))) || + (esp_ptr_in_rtc_slow((void *)addr) && esp_ptr_in_rtc_slow((void *)(addr+sz-1))) || + (esp_ptr_in_rtc_dram_fast((void *)addr) && esp_ptr_in_rtc_dram_fast((void *)(addr+sz-1))) +#if CONFIG_IDF_TARGET_ESP32 && CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY + || (esp_ptr_in_iram((void *)addr) && esp_ptr_in_iram((void *)(addr+sz-1))) +#endif + ; } inline bool esp_core_dump_task_stack_end_is_sane(uint32_t sp) @@ -568,4 +576,61 @@ uint32_t esp_core_dump_get_extra_info(void **info) return sizeof(s_extra_info); } +uint32_t esp_core_dump_get_user_ram_segments(void) +{ + uint32_t total_sz = 0; + + // count number of memory segments to insert into ELF structure + total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_dram_end, &_coredump_dram_start) > 0 ? 1 : 0; + total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_rtc_end, &_coredump_rtc_start) > 0 ? 1 : 0; + total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_rtc_fast_end, &_coredump_rtc_fast_start) > 0 ? 1 : 0; + total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_iram_end, &_coredump_iram_start) > 0 ? 1 : 0; + + 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); + 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); + total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_iram_end, &_coredump_iram_start); + + return total_sz; +} + +int esp_core_dump_get_user_ram_info(coredump_region_t region, uint32_t *start) { + + int total_sz = -1; + + 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; + + 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; + + default: + break; + } + + return total_sz; +} + #endif diff --git a/components/xtensa/include/esp_attr.h b/components/xtensa/include/esp_attr.h index d267346b0..1c3c766ee 100644 --- a/components/xtensa/include/esp_attr.h +++ b/components/xtensa/include/esp_attr.h @@ -32,9 +32,13 @@ // Forces data into IRAM instead of DRAM #define IRAM_DATA_ATTR __attribute__((section(".iram.data"))) +// Forces data into IRAM instead of DRAM and map it to coredump +#define COREDUMP_IRAM_DATA_ATTR _SECTION_ATTR_IMPL(".iram.data.coredump", __COUNTER__) + // Forces bss into IRAM instead of DRAM #define IRAM_BSS_ATTR __attribute__((section(".iram.bss"))) #else +#define COREDUMP_IRAM_DATA_ATTR #define IRAM_DATA_ATTR #define IRAM_BSS_ATTR @@ -85,6 +89,15 @@ // after restart or during a deep sleep / wake cycle. #define RTC_NOINIT_ATTR _SECTION_ATTR_IMPL(".rtc_noinit", __COUNTER__) +// Forces code into DRAM instead of flash and map it to coredump +#define COREDUMP_DRAM_ATTR _SECTION_ATTR_IMPL(".dram1.coredump", __COUNTER__) + +// Forces data into RTC memory and map it to coredump +#define COREDUMP_RTC_DATA_ATTR _SECTION_ATTR_IMPL(".rtc.coredump", __COUNTER__) + +// Allows to place data into RTC_FAST memory and map it to coredump +#define COREDUMP_RTC_FAST_ATTR _SECTION_ATTR_IMPL(".rtc.fast.coredump", __COUNTER__) + // Forces to not inline function #define NOINLINE_ATTR __attribute__((noinline)) diff --git a/docs/en/api-guides/core_dump.rst b/docs/en/api-guides/core_dump.rst index c144b0767..fc1ccd216 100644 --- a/docs/en/api-guides/core_dump.rst +++ b/docs/en/api-guides/core_dump.rst @@ -13,7 +13,8 @@ Overview ESP-IDF provides support to generate core dumps on unrecoverable software errors. This useful technique allows post-mortem analysis of software state at the moment of failure. Upon the crash system enters panic state, prints some information and halts or reboots depending configuration. User can choose to generate core dump in order to analyse the reason of failure on PC later on. Core dump contains snapshots of all tasks in the system at the moment of failure. Snapshots include tasks control blocks (TCB) and stacks. -So it is possible to find out what task, at what instruction (line of code) and what callstack of that task lead to the crash. +So it is possible to find out what task, at what instruction (line of code) and what callstack of that task lead to the crash. It is also possible dumping variables content on +demand if previously attributed accordingly. ESP-IDF provides special script `espcoredump.py` to help users to retrieve and analyse core dumps. This tool provides two commands for core dumps analysis: * info_corefile - prints crashed task's registers, callstack, list of available tasks in the system, memory regions and contents of memory stored in core dump (TCBs and stacks) @@ -94,8 +95,63 @@ ROM Functions in Backtraces It is possible situation that at the moment of crash some tasks or/and crashed task itself have one or more ROM functions in their callstacks. Since ROM is not part of the program ELF it will be impossible for GDB to parse such callstacks, because it tries to analyse functions' prologues to acomplish that. In that case callstack printing will be broken with error message at the first ROM function. -To overcome this issue you can use ROM ELF provided by Espressif (https://dl.espressif.com/dl/esp32_rom.elf) and pass it to 'espcoredump.py'. +To overcome this issue you can use ROM ELF provided by Espressif (https://dl.espressif.com/dl/{IDF_TARGET_PATH_NAME}_rom.elf) and pass it to 'espcoredump.py'. +Dumping variables on demand +--------------------------- + +Sometimes you want to read the last value of a variable to understand the root cause of a crash. +Core dump supports retrieving variable data over GDB by attributing special notations declared variables. + +Supported notations and RAM regions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. only:: esp32 + + - ``COREDUMP_DRAM_ATTR`` places variable into DRAM area which will be included into dump. + - ``COREDUMP_RTC_ATTR`` places variable into RTC area which will be included into dump. + - ``COREDUMP_RTC_FAST_ATTR`` places variable into RTC_FAST area which will be included into dump. + - ``COREDUMP_IRAM_ATTR`` places variable into IRAM area which will be included into dump when :ref:`Enable IRAM as 8 bit accessible memory ` is set. + +.. only:: esp32s2 + + - ``COREDUMP_DRAM_ATTR`` places variable into DRAM area which will be included into dump. + - ``COREDUMP_RTC_ATTR`` places variable into RTC area which will be included into dump. + - ``COREDUMP_RTC_FAST_ATTR`` places variable into RTC_FAST area which will be included into dump. + +Example +^^^^^^^ + +1. In :ref:`project-configuration-menu`, enable :ref:`COREDUMP TO FLASH `, then save and exit. + +2. In your project, create a global variable in DRAM area as such as: + + .. code-block:: bash + + // uint8_t global_var; + COREDUMP_DRAM_ATTR uint8_t global_var; + +3. In main application, set the variable to any value and `assert(0)` to cause a crash. + + .. code-block:: bash + + global_var = 25; + assert(0); + +4. Build, flash and run the application on a target device and wait for the dumping information. + +5. Run the command below to start core dumping in GDB, where ``PORT`` is the device USB port: + + .. code-block:: bash + + espcoredump.py -p PORT dbg_corefile + +6. In GDB shell, type ``p global_var`` to get the variable content: + + .. code-block:: bash + + (gdb) p global_var + $1 = 25 '\031' Running 'espcoredump.py' ------------------------ @@ -105,7 +161,6 @@ Generic command syntax: `espcoredump.py [options] command [args]` :Script Options: - * --chip,-c {auto,esp32}. Target chip type. Supported values are `auto` and `esp32`. * --port,-p PORT. Serial port device. * --baud,-b BAUD. Serial port baud rate used when flashing/reading. :Commands: @@ -120,4 +175,4 @@ Generic command syntax: * --save-core,-s SAVE_CORE. Save core to file. Othwerwise temporary core file will be deleted. Ignored with "-c". * --rom-elf,-r ROM_ELF. Path to ROM ELF file to use (if skipped "esp32_rom.elf" is used). * --print-mem,-m Print memory dump. Used only with "info_corefile". - * Path to program ELF file. + * Path to program ELF file. \ No newline at end of file