ソースを参照

Merge branch 'esp32c3/coredump_bt_summary' into 'master'

coredump: Parse backtrace info for RISCV

See merge request espressif/esp-idf!13455
Mahavir Jain 4 年 前
コミット
64f9bc06ac

+ 9 - 0
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

+ 23 - 10
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 <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

+ 21 - 1
components/espcoredump/include/port/riscv/esp_core_dump_summary_extra_info.h → 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 <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

+ 16 - 0
components/espcoredump/include/port/xtensa/esp_core_dump_summary_extra_info.h → 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 <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

+ 4 - 0
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
 }

+ 4 - 0
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

+ 39 - 3
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

+ 8 - 0
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