coredump: Parse backtrace info for RISCV

For RISCV, backtrace generation on device is not possible without
including and parsing DWARF sections. We extract the crash task stack
and let the host generate the backtrace
This commit is contained in:
Sachin Parekh 2021-05-05 17:03:22 +05:30 committed by Shubham Patil
parent 8536cf46a5
commit e0fc13b23d
8 changed files with 124 additions and 14 deletions

View File

@ -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

View File

@ -14,10 +14,11 @@
#ifndef ESP_CORE_DUMP_H_
#define ESP_CORE_DUMP_H_
#include "sdkconfig.h"
#include <stddef.h>
#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

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "sdkconfig.h"
#include <stdint.h>
#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

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "sdkconfig.h"
#include <stdint.h>
#include <xtensa/config/core-isa.h>
@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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