mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-30 20:51:41 +00:00 
			
		
		
		
	espcoredump: On device core dump parsing to generate summary
This commit is contained in:
		| @@ -5,20 +5,23 @@ | ||||
|          "src/core_dump_elf.c" | ||||
|          "src/core_dump_binary.c") | ||||
|  | ||||
| set(includes "include") | ||||
| set(priv_includes "include_core_dump") | ||||
|  | ||||
| idf_build_get_property(target IDF_TARGET) | ||||
|  | ||||
| if(CONFIG_IDF_TARGET_ARCH_XTENSA) | ||||
|   set(srcs ${srcs} "src/port/xtensa/core_dump_port.c") | ||||
|   set(priv_includes ${priv_includes} "include_core_dump/port/xtensa") | ||||
|   list(APPEND srcs "src/port/xtensa/core_dump_port.c") | ||||
|   list(APPEND includes "include/port/xtensa") | ||||
|   list(APPEND priv_includes "include_core_dump/port/xtensa") | ||||
| elseif(CONFIG_IDF_TARGET_ARCH_RISCV) | ||||
|   set(srcs ${srcs} "src/port/riscv/core_dump_port.c") | ||||
|   set(priv_includes ${priv_includes} "include_core_dump/port/riscv") | ||||
|   list(APPEND srcs "src/port/riscv/core_dump_port.c") | ||||
|   list(APPEND includes "include/port/riscv") | ||||
|   list(APPEND priv_includes "include_core_dump/port/riscv") | ||||
| endif() | ||||
|  | ||||
| idf_component_register(SRCS ${srcs} | ||||
|                     INCLUDE_DIRS "include" | ||||
|                     INCLUDE_DIRS ${includes} | ||||
|                     PRIV_INCLUDE_DIRS ${priv_includes} | ||||
|                     LDFRAGMENTS linker.lf | ||||
|                     PRIV_REQUIRES spi_flash app_update mbedtls esp_rom soc) | ||||
|   | ||||
| @@ -5,10 +5,12 @@ COMPONENT_ADD_LDFRAGMENTS += linker.lf | ||||
|  | ||||
| ifdef CONFIG_IDF_TARGET_ARCH_XTENSA | ||||
| 	COMPONENT_SRCDIRS += src/port/xtensa | ||||
| 	COMPONENT_ADD_INCLUDEDIRS += include/port/xtensa | ||||
| 	COMPONENT_PRIV_INCLUDEDIRS += include_core_dump/port/xtensa | ||||
| endif | ||||
|  | ||||
| ifdef CONFIG_IDF_TARGET_ARCH_RISCV | ||||
| 	COMPONENT_SRCDIRS += src/port/riscv | ||||
| 	COMPONENT_ADD_INCLUDEDIRS += include/port/riscv | ||||
| 	COMPONENT_PRIV_INCLUDEDIRS += include_core_dump/port/riscv | ||||
| endif | ||||
|   | ||||
| @@ -17,11 +17,37 @@ | ||||
| #include <stddef.h> | ||||
| #include "esp_err.h" | ||||
| #include "esp_private/panic_internal.h" | ||||
| #include "esp_core_dump_summary_extra_info.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #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; | ||||
|  | ||||
| /** | ||||
|  * @brief Core dump summary, Most meaningful contents of the core dump | ||||
|  *        are accommodated in this structure | ||||
|  */ | ||||
| typedef struct { | ||||
|     uint32_t exc_tcb;                           /*!< TCB pointer to the task causing exception */ | ||||
|     char exc_task[16];                          /*!< Name of the task that caused exception */ | ||||
|     uint32_t exc_pc;                            /*!< Program counter for exception */ | ||||
|     esp_core_dump_bt_info_t exc_bt_info;        /*!< Backtrace information for task causing exception */ | ||||
|     uint32_t core_dump_version;                 /*!< Core dump version */ | ||||
|     uint8_t app_elf_sha256[APP_ELF_SHA256_SZ];  /*!< Crashing application's SHA256 sum as a string */ | ||||
|     esp_core_dump_summary_extra_info_t ex_info; /*!< Architecture specific extra data */ | ||||
| } esp_core_dump_summary_t; | ||||
|  | ||||
| /**************************************************************************************/ | ||||
| /******************************** EXCEPTION MODE API **********************************/ | ||||
| /**************************************************************************************/ | ||||
| @@ -111,6 +137,15 @@ 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); | ||||
|  | ||||
| /** | ||||
|  * @brief  Get the summary of a core dump. This function works only with ELF format core dumps. | ||||
|  * | ||||
|  * @param  summary   Summary of the core dump | ||||
|  * | ||||
|  * @return ESP_OK on success, otherwise \see esp_err_t | ||||
|  */ | ||||
| esp_err_t esp_core_dump_get_summary(esp_core_dump_summary_t *summary); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|   | ||||
| @@ -0,0 +1,35 @@ | ||||
| // Copyright 2021 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
|  | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
|  | ||||
| /** | ||||
|  * @brief RISC-V architecture specific extra information | ||||
|  */ | ||||
| typedef struct { | ||||
|     uint32_t mstatus;     /* Machine Status */ | ||||
|     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 */ | ||||
| } esp_core_dump_summary_extra_info_t; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @@ -0,0 +1,38 @@ | ||||
| // Copyright 2021 Espressif Systems (Shanghai) PTE LTD | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
|  | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| #include <xtensa/config/core-isa.h> | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
|  | ||||
| #define EPCx_REGISTER_COUNT XCHAL_NUM_INTLEVELS | ||||
|  | ||||
| /** | ||||
|  * @brief Xtensa architecture specific extra information | ||||
|  */ | ||||
| typedef struct { | ||||
|     uint32_t exc_cause;                 /*!< Cause of exception */ | ||||
|     uint32_t exc_vaddr;                 /*!< Virtual address of exception */ | ||||
|     uint32_t exc_a[16];                 /*!< a register set when the exception caused */ | ||||
|     uint32_t epcx[EPCx_REGISTER_COUNT]; /*!< PC register address at exception level(1 to 7) */ | ||||
|     uint8_t epcx_reg_bits;              /*!< Bit mask of available EPCx registers */ | ||||
| } esp_core_dump_summary_extra_info_t; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @@ -30,6 +30,7 @@ | ||||
| #include "esp_app_format.h" | ||||
| #include "esp_core_dump_types.h" | ||||
| #include "esp_core_dump_port_impl.h" | ||||
| #include "esp_core_dump.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| @@ -164,6 +165,33 @@ void esp_core_dump_port_set_crashed_tcb(uint32_t handle); | ||||
|  */ | ||||
| uint32_t esp_core_dump_get_extra_info(void **info); | ||||
|  | ||||
| /** | ||||
|  * @brief Parse extra information into summary | ||||
|  * | ||||
|  * @param summary Pointer to core dump summary structure | ||||
|  * @param ei_data Pointer to data of EXTRA_INFO note read from flash | ||||
|  */ | ||||
| void esp_core_dump_summary_parse_extra_info(esp_core_dump_summary_t *summary, void *ei_data); | ||||
|  | ||||
| /** | ||||
|  * @brief Parse exception registers into summary | ||||
|  * | ||||
|  * @param summary Pointer to core dump summary structure | ||||
|  * @param stack_data Pointer to data of crashed task's stack read from flash | ||||
|  */ | ||||
| void esp_core_dump_summary_parse_exc_regs(esp_core_dump_summary_t *summary, void *stack_data); | ||||
|  | ||||
| /** | ||||
|  * @brief Parse backtrace into bt_info | ||||
|  * | ||||
|  * @param bt_info Pointer to store backtrace info | ||||
|  * @param vaddr Pointer to crashed task's stack vaddr | ||||
|  * @param paddr Pointe to crashed task's stack paddr | ||||
|  * @param stack_size Stack size | ||||
|  */ | ||||
| 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); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|   | ||||
| @@ -15,6 +15,8 @@ | ||||
| #include "esp_attr.h" | ||||
| #include "esp_partition.h" | ||||
| #include "esp_ota_ops.h" | ||||
| #include "esp_spi_flash.h" | ||||
| #include "esp_flash_encrypt.h" | ||||
| #include "sdkconfig.h" | ||||
| #include "core_dump_checksum.h" | ||||
| #include "core_dump_elf.h" | ||||
| @@ -644,4 +646,131 @@ esp_err_t esp_core_dump_write_elf(core_dump_write_config_t *write_cfg) | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| /* 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) | ||||
| { | ||||
|     size_t out_size; | ||||
|     assert (core_data_handle); | ||||
|     assert(map_addr); | ||||
|  | ||||
|     /* Find the partition that could potentially contain a (previous) core dump. */ | ||||
|     const esp_partition_t *core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, | ||||
|                                                                 ESP_PARTITION_SUBTYPE_DATA_COREDUMP, | ||||
|                                                                 NULL); | ||||
|     if (!core_part) { | ||||
|         ESP_COREDUMP_LOGE("Core dump partition not found!"); | ||||
|         return ESP_ERR_NOT_FOUND; | ||||
|     } | ||||
|     if (core_part->size < sizeof(uint32_t)) { | ||||
|         ESP_COREDUMP_LOGE("Core dump partition too small!"); | ||||
|         return ESP_ERR_INVALID_SIZE; | ||||
|     } | ||||
|     /* Data read from the mmapped core dump partition will be garbage if flash | ||||
|      * encryption is enabled in hardware and core dump partition is not encrypted | ||||
|      */ | ||||
|     if (esp_flash_encryption_enabled() && !core_part->encrypted) { | ||||
|         ESP_COREDUMP_LOGE("Flash encryption enabled in hardware and core dump partition is not encrypted!"); | ||||
|         return ESP_ERR_NOT_SUPPORTED; | ||||
|     } | ||||
|     /* Read the size of the core dump file from the partition */ | ||||
|     esp_err_t ret = esp_partition_read(core_part, 0, &out_size, sizeof(uint32_t)); | ||||
|     if (ret != ESP_OK) { | ||||
|         ESP_COREDUMP_LOGE("Failed to read core dump data size"); | ||||
|         return ret; | ||||
|     } | ||||
|     /* map the full core dump parition, including the checksum. */ | ||||
|     return esp_partition_mmap(core_part, 0, out_size, SPI_FLASH_MMAP_DATA, | ||||
|                               map_addr, core_data_handle); | ||||
| } | ||||
|  | ||||
| static void elf_parse_version_info(esp_core_dump_summary_t *summary, void *data) | ||||
| { | ||||
|     core_dump_elf_version_info_t *version = (core_dump_elf_version_info_t *)data; | ||||
|     summary->core_dump_version = version->version; | ||||
|     memcpy(summary->app_elf_sha256, version->app_elf_sha256, ELF_APP_SHA256_SIZE); | ||||
|     ESP_COREDUMP_LOGD("Core dump version 0x%x", summary->core_dump_version); | ||||
|     ESP_COREDUMP_LOGD("App ELF SHA2 %s", (char *)summary->app_elf_sha256); | ||||
| } | ||||
|  | ||||
| static void elf_parse_exc_task_name(esp_core_dump_summary_t *summary, void *tcb_data) | ||||
| { | ||||
|     StaticTask_t *tcb = (StaticTask_t *) tcb_data; | ||||
|     /* An ugly way to get the task name. We could possibly use pcTaskGetTaskName here. | ||||
|      * But that has assumption that TCB pointer can be used as TaskHandle. So let's | ||||
|      * keep it this way. */ | ||||
|     memset(summary->exc_task, 0, sizeof(summary->exc_task)); | ||||
|     strncpy(summary->exc_task, (char *)tcb->ucDummy7, sizeof(summary->exc_task) - 1); | ||||
|     ESP_COREDUMP_LOGD("Crashing task %s", summary->exc_task); | ||||
| } | ||||
|  | ||||
| esp_err_t esp_core_dump_get_summary(esp_core_dump_summary_t *summary) | ||||
| { | ||||
|     int i; | ||||
|     elf_phdr *ph; | ||||
|     elf_note *note; | ||||
|     const void *map_addr; | ||||
|     size_t consumed_note_sz; | ||||
|     spi_flash_mmap_handle_t core_data_handle; | ||||
|  | ||||
|     if (!summary) { | ||||
|         return ESP_ERR_INVALID_ARG; | ||||
|     } | ||||
|     esp_err_t err = elf_core_dump_image_mmap(&core_data_handle, &map_addr); | ||||
|     if (err != ESP_OK) { | ||||
|         return err; | ||||
|     } | ||||
|     uint8_t *ptr = (uint8_t *) map_addr + sizeof(core_dump_header_t); | ||||
|     elfhdr *eh = (elfhdr *)ptr; | ||||
|  | ||||
|     ESP_COREDUMP_LOGD("ELF ident %02x %c %c %c", eh->e_ident[0], eh->e_ident[1], eh->e_ident[2], eh->e_ident[3]); | ||||
|     ESP_COREDUMP_LOGD("Ph_num %d offset %x", eh->e_phnum, eh->e_phoff); | ||||
|  | ||||
|     for (i = 0; i < eh->e_phnum; i++) { | ||||
|         ph = (elf_phdr *)((ptr + i * sizeof(*ph)) + eh->e_phoff); | ||||
|         ESP_COREDUMP_LOGD("PHDR type %d off %x vaddr %x paddr %x filesz %x memsz %x flags %x align %x", | ||||
|                           ph->p_type, ph->p_offset, ph->p_vaddr, ph->p_paddr, ph->p_filesz, ph->p_memsz, | ||||
|                           ph->p_flags, ph->p_align); | ||||
|         if (ph->p_type == PT_NOTE) { | ||||
|             consumed_note_sz = 0; | ||||
|             while(consumed_note_sz < ph->p_memsz) { | ||||
|                 note = (elf_note *)(ptr + ph->p_offset + consumed_note_sz); | ||||
|                 char *nm = (char *)(ptr + ph->p_offset + consumed_note_sz + sizeof(elf_note)); | ||||
|                 ESP_COREDUMP_LOGD("Note NameSZ %x DescSZ %x Type %x name %s", note->n_namesz, | ||||
|                                   note->n_descsz, note->n_type, nm); | ||||
|                 if (strncmp(nm, "EXTRA_INFO", note->n_namesz) == 0 ) { | ||||
|                     esp_core_dump_summary_parse_extra_info(summary, (void *)(nm + note->n_namesz)); | ||||
|                 } | ||||
|                 if (strncmp(nm, "ESP_CORE_DUMP_INFO", note->n_namesz) == 0 ) { | ||||
|                     elf_parse_version_info(summary, (void *)(nm + note->n_namesz)); | ||||
|                 } | ||||
|                 consumed_note_sz += note->n_namesz + note->n_descsz + sizeof(elf_note); | ||||
|                 ALIGN(4, consumed_note_sz); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     /* Following code assumes that task stack segment follows the TCB segment for the respective task. | ||||
|      * In general ELF does not impose any restrictions on segments' order so this can be changed without impacting core dump version. | ||||
|      * More universal and flexible way would be to retrieve stack start address from crashed task TCB segment and then look for the stack segment with that address. | ||||
|      */ | ||||
|     int flag = 0; | ||||
|     for (i = 0; i < eh->e_phnum; i++) { | ||||
|         ph = (elf_phdr *)((ptr + i * sizeof(*ph)) + eh->e_phoff); | ||||
|         if (ph->p_type == PT_LOAD) { | ||||
|             if (flag) { | ||||
|                 esp_core_dump_summary_parse_exc_regs(summary, (void *)(ptr + ph->p_offset)); | ||||
|                 esp_core_dump_summary_parse_backtrace_info(&summary->exc_bt_info, (void *) ph->p_vaddr, | ||||
|                                                            (void *)(ptr + ph->p_offset), ph->p_memsz); | ||||
|                 break; | ||||
|             } | ||||
|             if (ph->p_vaddr == summary->exc_tcb) { | ||||
|                 elf_parse_exc_task_name(summary, (void *)(ptr + ph->p_offset)); | ||||
|                 flag = 1; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     spi_flash_munmap(core_data_handle); | ||||
|     return ESP_OK; | ||||
| } | ||||
|  | ||||
| #endif //CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF | ||||
|   | ||||
| @@ -381,4 +381,38 @@ uint32_t esp_core_dump_get_extra_info(void **info) | ||||
|     return size; | ||||
| } | ||||
|  | ||||
| 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; | ||||
|     summary->exc_tcb = ei->crashed_task_tcb; | ||||
|     ESP_COREDUMP_LOGD("Crash TCB 0x%x", summary->exc_tcb); | ||||
| } | ||||
|  | ||||
| void esp_core_dump_summary_parse_exc_regs(esp_core_dump_summary_t *summary, void *stack_data) | ||||
| { | ||||
|     int i; | ||||
|     long *a_reg; | ||||
|     RvExcFrame *stack = (RvExcFrame *)stack_data; | ||||
|     summary->exc_pc = stack->mepc; | ||||
|     ESP_COREDUMP_LOGD("Crashing PC 0x%x", summary->exc_pc); | ||||
|  | ||||
|     summary->ex_info.mstatus = stack->mstatus; | ||||
|     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); | ||||
|     a_reg = &stack->a0; | ||||
|     for (i = 0; i < 8; i++) { | ||||
|         summary->ex_info.exc_a[i] = a_reg[i]; | ||||
|         ESP_COREDUMP_LOGD("A[%d] 0x%x", i, summary->ex_info.exc_a[i]); | ||||
|     } | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -26,6 +26,7 @@ | ||||
| #include "esp_rom_sys.h" | ||||
| #include "esp_core_dump_common.h" | ||||
| #include "esp_core_dump_port.h" | ||||
| #include "esp_debug_helpers.h" | ||||
|  | ||||
| const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_port"; | ||||
|  | ||||
| @@ -472,4 +473,90 @@ uint32_t esp_core_dump_get_extra_info(void **info) | ||||
|     return sizeof(s_extra_info); | ||||
| } | ||||
|  | ||||
| void esp_core_dump_summary_parse_extra_info(esp_core_dump_summary_t *summary, void *ei_data) | ||||
| { | ||||
|     int i; | ||||
|     xtensa_extra_info_t *ei = (xtensa_extra_info_t *) ei_data; | ||||
|     summary->exc_tcb = ei->crashed_task_tcb; | ||||
|     summary->ex_info.exc_vaddr = ei->excvaddr.reg_val; | ||||
|     summary->ex_info.exc_cause = ei->exccause.reg_val; | ||||
|     ESP_COREDUMP_LOGD("Crash TCB 0x%x", summary->exc_tcb); | ||||
|     ESP_COREDUMP_LOGD("excvaddr 0x%x", summary->ex_info.exc_vaddr); | ||||
|     ESP_COREDUMP_LOGD("exccause 0x%x", summary->ex_info.exc_cause); | ||||
|  | ||||
|     memset(summary->ex_info.epcx, 0, sizeof(summary->ex_info.epcx)); | ||||
|     summary->ex_info.epcx_reg_bits = 0; | ||||
|     for (i = 0; i < COREDUMP_EXTRA_REG_NUM; i++ ) { | ||||
|         if (ei->extra_regs[i].reg_index >= EPC_1 | ||||
|             && ei->extra_regs[i].reg_index < (EPC_1 + XCHAL_NUM_INTLEVELS)) { | ||||
|             summary->ex_info.epcx[ei->extra_regs[i].reg_index - EPC_1] = ei->extra_regs[i].reg_val; | ||||
|             summary->ex_info.epcx_reg_bits |= (1 << (ei->extra_regs[i].reg_index - EPC_1)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void esp_core_dump_summary_parse_exc_regs(esp_core_dump_summary_t *summary, void *stack_data) | ||||
| { | ||||
|     int i; | ||||
|     long *a_reg; | ||||
|     XtExcFrame *stack = (XtExcFrame *) stack_data; | ||||
|     summary->exc_pc = esp_cpu_process_stack_pc(stack->pc); | ||||
|     ESP_COREDUMP_LOGD("Crashing PC 0x%x", summary->exc_pc); | ||||
|  | ||||
|     a_reg = &stack->a0; | ||||
|     for (i = 0; i < 16; i++) { | ||||
|         summary->ex_info.exc_a[i] = a_reg[i]; | ||||
|         ESP_COREDUMP_LOGD("A[%d] 0x%x", i, summary->ex_info.exc_a[i]); | ||||
|     } | ||||
| } | ||||
|  | ||||
| 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) | ||||
| { | ||||
|     int offset; | ||||
|     bool corrupted; | ||||
|     esp_backtrace_frame_t frame; | ||||
|     XtExcFrame *stack = (XtExcFrame *) paddr; | ||||
|     int max_depth = (int) (sizeof(bt_info->bt) / sizeof(bt_info->bt[0])); | ||||
|     int index = 0; | ||||
|  | ||||
|     frame.pc = stack->pc; | ||||
|     frame.sp = stack->a1; | ||||
|     frame.next_pc = stack->a0; | ||||
|  | ||||
|     corrupted = !(esp_stack_ptr_is_sane(frame.sp) && | ||||
|                 esp_ptr_executable((void *)esp_cpu_process_stack_pc(frame.pc))); | ||||
|  | ||||
|     /* vaddr is actual stack address when crash occurred. However that stack is now saved | ||||
|      * in the flash at a different location. Hence for each SP, we need to adjust the offset | ||||
|      * to point to next frame in the flash */ | ||||
|     offset = (uint32_t) stack - (uint32_t) vaddr; | ||||
|  | ||||
|     ESP_COREDUMP_LOGD("Crash Backtrace"); | ||||
|     bt_info->bt[index] = esp_cpu_process_stack_pc(frame.pc); | ||||
|     ESP_COREDUMP_LOGD(" 0x%x", bt_info->bt[index]); | ||||
|     index++; | ||||
|  | ||||
|     while (max_depth-- > 0 && frame.next_pc && !corrupted) { | ||||
|         /* Check if the Stack Pointer is in valid address range */ | ||||
|         if (!((uint32_t)frame.sp >= (uint32_t)vaddr && | ||||
|             ((uint32_t)frame.sp <= (uint32_t)vaddr + stack_size))) { | ||||
|             corrupted = true; | ||||
|             break; | ||||
|         } | ||||
|         /* Adjusting the SP to address in flash than in actual RAM */ | ||||
|         frame.sp += offset; | ||||
|         if (!esp_backtrace_get_next_frame(&frame)) { | ||||
|             corrupted = true; | ||||
|         } | ||||
|         if (corrupted == false) { | ||||
|             bt_info->bt[index] = esp_cpu_process_stack_pc(frame.pc); | ||||
|             ESP_COREDUMP_LOGD(" 0x%x", bt_info->bt[index]); | ||||
|             index++; | ||||
|         } | ||||
|     } | ||||
|     bt_info->depth = index; | ||||
|     bt_info->corrupted = corrupted; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Shubham Patil
					Shubham Patil