diff --git a/components/espcoredump/Kconfig b/components/espcoredump/Kconfig index 9134413832..28a54a02a6 100644 --- a/components/espcoredump/Kconfig +++ b/components/espcoredump/Kconfig @@ -90,6 +90,15 @@ menu "Core dump" To ensure that core dump itself will not overflow task/ISR stack set this to the value above 800. NOTE: It eats DRAM. + config ESP_COREDUMP_SUMMARY_STACKDUMP_SIZE + int "Size of the stack dump buffer" + depends on ESP_COREDUMP_DATA_FORMAT_ELF && ESP_COREDUMP_ENABLE_TO_FLASH && IDF_TARGET_ARCH_RISCV + range 512 4096 + default 1024 + help + Size of the buffer that would be reserved for extracting backtrace info summary. + This buffer will contain the stack dump of the crashed task. This dump is useful in generating backtrace + choice ESP_COREDUMP_DECODE prompt "Handling of UART core dumps in IDF Monitor" depends on ESP_COREDUMP_ENABLE_TO_UART diff --git a/components/espcoredump/include/esp_core_dump.h b/components/espcoredump/include/esp_core_dump.h index 7d41b97e57..40fd90d8b2 100644 --- a/components/espcoredump/include/esp_core_dump.h +++ b/components/espcoredump/include/esp_core_dump.h @@ -14,10 +14,11 @@ #ifndef ESP_CORE_DUMP_H_ #define ESP_CORE_DUMP_H_ +#include "sdkconfig.h" #include #include "esp_err.h" #include "esp_private/panic_internal.h" -#include "esp_core_dump_summary_extra_info.h" +#include "esp_core_dump_summary_port.h" #ifdef __cplusplus extern "C" { @@ -25,14 +26,7 @@ extern "C" { #define APP_ELF_SHA256_SZ (CONFIG_APP_RETRIEVE_LEN_ELF_SHA + 1) -/** - * @brief Backtrace information - */ -typedef struct { - uint32_t bt[16]; /*!< Backtrace (array of PC) */ - uint32_t depth; /*!< Number of backtrace entries */ - bool corrupted; /*!< Status flag for backtrace is corrupt or not */ -} esp_core_dump_bt_info_t; +#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF /** * @brief Core dump summary, Most meaningful contents of the core dump @@ -48,6 +42,8 @@ typedef struct { esp_core_dump_summary_extra_info_t ex_info; /*!< Architecture specific extra data */ } esp_core_dump_summary_t; +#endif /* CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF */ + /**************************************************************************************/ /******************************** EXCEPTION MODE API **********************************/ /**************************************************************************************/ @@ -137,15 +133,32 @@ 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 && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF + /** - * @brief Get the summary of a core dump. This function works only with ELF format core dumps. + * @brief Get the summary of a core dump. * * @param summary Summary of the core dump * * @return ESP_OK on success, otherwise \see esp_err_t + * + * @note This function works only if coredump is stored in flash and in ELF format + * + * Example usage: + * @code{c} + * esp_core_dump_summary_t *summary = malloc(sizeof(esp_core_dump_summary_t)); + * if (summary) { + * if (esp_core_dump_get_summary(summary) == ESP_OK) { + * // Do stuff + * } + * } + * free(summary); + * @endcode */ esp_err_t esp_core_dump_get_summary(esp_core_dump_summary_t *summary); +#endif /* CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF */ + #ifdef __cplusplus } #endif diff --git a/components/espcoredump/include/port/riscv/esp_core_dump_summary_extra_info.h b/components/espcoredump/include/port/riscv/esp_core_dump_summary_port.h similarity index 51% rename from components/espcoredump/include/port/riscv/esp_core_dump_summary_extra_info.h rename to components/espcoredump/include/port/riscv/esp_core_dump_summary_port.h index 510fdc06af..f2b5d0d9e6 100644 --- a/components/espcoredump/include/port/riscv/esp_core_dump_summary_extra_info.h +++ b/components/espcoredump/include/port/riscv/esp_core_dump_summary_port.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #pragma once +#include "sdkconfig.h" #include #ifdef __cplusplus @@ -19,6 +20,21 @@ extern "C" { #endif +#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF + +/** + * @brief Backtrace information + * + * For RISCV, backtrace cannot be generated on device without including and parsing + * DWARF sections. Including these sections would increase the binary size so provide + * the stackdump that can be later used to generate backtrace with the help of GDB or by parsing the ELF file + * on the host machine + */ +typedef struct { + uint8_t stackdump[CONFIG_ESP_COREDUMP_SUMMARY_STACKDUMP_SIZE]; /*!< Stack dump of the crashing task. */ + uint32_t dump_size; /*!< Size (in bytes) of the stack dump */ +} esp_core_dump_bt_info_t; + /** * @brief RISC-V architecture specific extra information */ @@ -27,9 +43,13 @@ typedef struct { uint32_t mtvec; /* Machine Trap-Vector Base Address */ uint32_t mcause; /* Machine Trap Cause */ uint32_t mtval; /* Machine Trap Value */ - uint32_t exc_a[8]; /*!< a register set when the exception caused */ + uint32_t ra; /* Return Address */ + uint32_t sp; /* Stack pointer */ + uint32_t exc_a[8]; /* A0-A7 registers when the exception caused */ } esp_core_dump_summary_extra_info_t; +#endif /* CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF */ + #ifdef __cplusplus } #endif diff --git a/components/espcoredump/include/port/xtensa/esp_core_dump_summary_extra_info.h b/components/espcoredump/include/port/xtensa/esp_core_dump_summary_port.h similarity index 70% rename from components/espcoredump/include/port/xtensa/esp_core_dump_summary_extra_info.h rename to components/espcoredump/include/port/xtensa/esp_core_dump_summary_port.h index 3db7a70be8..815c1fff70 100644 --- a/components/espcoredump/include/port/xtensa/esp_core_dump_summary_extra_info.h +++ b/components/espcoredump/include/port/xtensa/esp_core_dump_summary_port.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #pragma once +#include "sdkconfig.h" #include #include @@ -20,8 +21,21 @@ extern "C" { #endif +#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF + #define EPCx_REGISTER_COUNT XCHAL_NUM_INTLEVELS +/** + * @brief Backtrace information. + * + * For Xtensa, backtrace can be generated on device due to windowed register ABI. + */ +typedef struct { + uint32_t bt[16]; /*!< Backtrace (array of PC) */ + uint32_t depth; /*!< Number of backtrace entries */ + bool corrupted; /*!< Status flag for backtrace is corrupt or not */ +} esp_core_dump_bt_info_t; + /** * @brief Xtensa architecture specific extra information */ @@ -33,6 +47,8 @@ typedef struct { uint8_t epcx_reg_bits; /*!< Bit mask of available EPCx registers */ } esp_core_dump_summary_extra_info_t; +#endif /* CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF */ + #ifdef __cplusplus } #endif 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 5c0058ca49..b99beb32ec 100644 --- a/components/espcoredump/include_core_dump/esp_core_dump_port.h +++ b/components/espcoredump/include_core_dump/esp_core_dump_port.h @@ -24,6 +24,7 @@ * both Xtensa and RISC-V architecture. */ +#include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "soc/cpu.h" #include "esp_debug_helpers.h" @@ -165,6 +166,8 @@ void esp_core_dump_port_set_crashed_tcb(uint32_t handle); */ uint32_t esp_core_dump_get_extra_info(void **info); +#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF + /** * @brief Parse extra information into summary * @@ -191,6 +194,7 @@ void esp_core_dump_summary_parse_exc_regs(esp_core_dump_summary_t *summary, void */ void esp_core_dump_summary_parse_backtrace_info(esp_core_dump_bt_info_t *bt_info, const void *vaddr, const void *paddr, uint32_t stack_size); +#endif /* CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF */ #ifdef __cplusplus } diff --git a/components/espcoredump/src/core_dump_elf.c b/components/espcoredump/src/core_dump_elf.c index 3dfbc2de1a..58bd691ecf 100644 --- a/components/espcoredump/src/core_dump_elf.c +++ b/components/espcoredump/src/core_dump_elf.c @@ -646,6 +646,8 @@ esp_err_t esp_core_dump_write_elf(core_dump_write_config_t *write_cfg) return err; } +#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH + /* Below are the helper function to parse the core dump ELF stored in flash */ static esp_err_t elf_core_dump_image_mmap(spi_flash_mmap_handle_t* core_data_handle, const void **map_addr) @@ -773,4 +775,6 @@ esp_err_t esp_core_dump_get_summary(esp_core_dump_summary_t *summary) return ESP_OK; } +#endif // CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH + #endif //CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF diff --git a/components/espcoredump/src/port/riscv/core_dump_port.c b/components/espcoredump/src/port/riscv/core_dump_port.c index 837427d802..3336cbbc37 100644 --- a/components/espcoredump/src/port/riscv/core_dump_port.c +++ b/components/espcoredump/src/port/riscv/core_dump_port.c @@ -381,6 +381,8 @@ uint32_t esp_core_dump_get_extra_info(void **info) return size; } +#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF + void esp_core_dump_summary_parse_extra_info(esp_core_dump_summary_t *summary, void *ei_data) { riscv_extra_info_t *ei = (riscv_extra_info_t *)ei_data; @@ -400,8 +402,10 @@ void esp_core_dump_summary_parse_exc_regs(esp_core_dump_summary_t *summary, void summary->ex_info.mtvec = stack->mtvec; summary->ex_info.mcause = stack->mcause; summary->ex_info.mtval = stack->mtval; - ESP_COREDUMP_LOGD("mstatus:0x%x mtvec:0x%x mcause:0x%x mval:0x%x", - stack->mstatus, stack->mtvec, stack->mcause, stack->mtval); + summary->ex_info.ra = stack->ra; + summary->ex_info.sp = stack->sp; + ESP_COREDUMP_LOGD("mstatus:0x%x mtvec:0x%x mcause:0x%x mval:0x%x RA: 0x%x SP: 0x%x", + stack->mstatus, stack->mtvec, stack->mcause, stack->mtval, stack->ra, stack->sp); a_reg = &stack->a0; for (i = 0; i < 8; i++) { summary->ex_info.exc_a[i] = a_reg[i]; @@ -412,7 +416,39 @@ void esp_core_dump_summary_parse_exc_regs(esp_core_dump_summary_t *summary, void void esp_core_dump_summary_parse_backtrace_info(esp_core_dump_bt_info_t *bt_info, const void *vaddr, const void *paddr, uint32_t stack_size) { - return; + if (!vaddr || !paddr || !bt_info) { + bt_info->dump_size = 0; + return; + } + + /* Check whether the stack is a fake stack created during coredump generation + * If its a fake stack, we don't have any actual stack dump + */ + if (vaddr >= COREDUMP_FAKE_STACK_START && vaddr < COREDUMP_FAKE_STACK_LIMIT) { + bt_info->dump_size = 0; + return; + } + + /* Top of the stack consists of the context registers saved after crash, + * extract the value of stack pointer (SP) at the time of crash + */ + RvExcFrame *stack = (RvExcFrame *) paddr; + uint32_t *sp = (uint32_t *)stack->sp; + + /* vaddr is actual stack address when crash occurred. However that stack is now saved + * in the flash at a different location. Hence, we need to adjust the offset + * to point to correct data in the flash */ + int offset = (uint32_t)stack - (uint32_t)vaddr; + + // Skip the context saved register frame + uint32_t regframe_size = (uint32_t)sp - (uint32_t)vaddr; + + uint32_t dump_size = MIN(stack_size - regframe_size, CONFIG_ESP_COREDUMP_SUMMARY_STACKDUMP_SIZE); + + memcpy(&bt_info->stackdump[0], (uint8_t *)sp + offset, dump_size); + bt_info->dump_size = dump_size; } +#endif /* #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF */ + #endif diff --git a/components/espcoredump/src/port/xtensa/core_dump_port.c b/components/espcoredump/src/port/xtensa/core_dump_port.c index 35b74d1968..8fdaacb73a 100644 --- a/components/espcoredump/src/port/xtensa/core_dump_port.c +++ b/components/espcoredump/src/port/xtensa/core_dump_port.c @@ -473,6 +473,8 @@ uint32_t esp_core_dump_get_extra_info(void **info) return sizeof(s_extra_info); } +#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF + void esp_core_dump_summary_parse_extra_info(esp_core_dump_summary_t *summary, void *ei_data) { int i; @@ -513,6 +515,10 @@ void esp_core_dump_summary_parse_exc_regs(esp_core_dump_summary_t *summary, void void esp_core_dump_summary_parse_backtrace_info(esp_core_dump_bt_info_t *bt_info, const void *vaddr, const void *paddr, uint32_t stack_size) { + if (!vaddr || !paddr || !bt_info) { + return; + } + int offset; bool corrupted; esp_backtrace_frame_t frame; @@ -559,4 +565,6 @@ void esp_core_dump_summary_parse_backtrace_info(esp_core_dump_bt_info_t *bt_info bt_info->corrupted = corrupted; } +#endif /* #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF */ + #endif