]> granicus.if.org Git - esp-idf/commitdiff
esp32: Replaces magic numbers with CRC for core dump in flash
authorAlexey Gerenkov <alexey@espressif.com>
Wed, 13 Sep 2017 18:30:48 +0000 (21:30 +0300)
committerbot <bot@espressif.com>
Thu, 15 Nov 2018 06:13:48 +0000 (06:13 +0000)
components/esp32/Kconfig
components/esp32/core_dump.c
components/esp32/include/esp_core_dump.h
components/espcoredump/espcoredump.py
components/espcoredump/test/expected_output
components/espcoredump/test/expected_output_new_CT
components/freertos/include/freertos/FreeRTOSConfig.h
docs/en/api-guides/core_dump.rst

index b53a684098c392eb7e9c8c10fce289fb5368b495..32f699d7be0c3234a2aabe2a501b8910efe7ace0 100644 (file)
@@ -306,13 +306,6 @@ config ESP32_CORE_DUMP_UART_DELAY
         Config delay (in ms) before printing core dump to UART.
         Delay can be interrupted by pressing Enter key.
 
-config ESP32_CORE_DUMP_LOG_LEVEL
-    int "Core dump module logging level"
-    depends on ESP32_ENABLE_COREDUMP
-    default 1
-    help
-        Config core dump module logging level (0-5).
-
 choice NUMBER_OF_UNIVERSAL_MAC_ADDRESS
     bool "Number of universally administered (by IEEE) MAC address"
     default FOUR_UNIVERSAL_MAC_ADDRESS
index 078afe93ba3998008512ecc4e8f47317df6223c2..6150893fac45edc9390c4f1b8d9184b82fcb1bb0 100644 (file)
 #include "esp_partition.h"
 #include "esp_clk.h"
 
-#if CONFIG_ESP32_ENABLE_COREDUMP
-#define LOG_LOCAL_LEVEL CONFIG_ESP32_CORE_DUMP_LOG_LEVEL
 #include "esp_log.h"
-const static DRAM_ATTR char TAG[] = "esp_core_dump";
+const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump";
+
+typedef uint32_t core_dump_crc_t;
 
+#if CONFIG_ESP32_ENABLE_COREDUMP
 #define ESP_COREDUMP_LOG( level, format, ... )  if (LOG_LOCAL_LEVEL >= level)   { ets_printf(DRAM_STR(format), esp_log_early_timestamp(), (const char *)TAG, ##__VA_ARGS__); }
 #define ESP_COREDUMP_LOGE( format, ... )  ESP_COREDUMP_LOG(ESP_LOG_ERROR, LOG_FORMAT(E, format), ##__VA_ARGS__)
 #define ESP_COREDUMP_LOGW( format, ... )  ESP_COREDUMP_LOG(ESP_LOG_WARN, LOG_FORMAT(W, format), ##__VA_ARGS__)
@@ -47,6 +48,7 @@ const static DRAM_ATTR char TAG[] = "esp_core_dump";
 #define COREDUMP_MAX_TASKS_NUM              32
 #define COREDUMP_MAX_TASK_STACK_SIZE        (64*1024)
 
+
 typedef esp_err_t (*esp_core_dump_write_prepare_t)(void *priv, uint32_t *data_len);
 typedef esp_err_t (*esp_core_dump_write_start_t)(void *priv);
 typedef esp_err_t (*esp_core_dump_write_end_t)(void *priv);
@@ -143,9 +145,9 @@ static void esp_core_dump_write(XtExcFrame *frame, core_dump_write_config_t *wri
             else {
 #if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH
                 XtExcFrame *task_frame2 = (XtExcFrame *)tasks[i].pxTopOfStack;
-#endif
                 ESP_COREDUMP_LOG_PROCESS("Task EXIT/PC/PS/A0/SP %x %x %x %x %x",
                     task_frame2->exit, task_frame2->pc, task_frame2->ps, task_frame2->a0, task_frame2->a1);
+#endif
             }
         }
         len = (uint32_t)tasks[i].pxEndOfStack - (uint32_t)tasks[i].pxTopOfStack;
@@ -248,13 +250,10 @@ static void esp_core_dump_write(XtExcFrame *frame, core_dump_write_config_t *wri
 
 #if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH
 
-// magic numbers to control core dump data consistency
-#define COREDUMP_FLASH_MAGIC_START    0xE32C04EDUL
-#define COREDUMP_FLASH_MAGIC_END      0xE32C04EDUL
-
 typedef struct _core_dump_write_flash_data_t
 {
-    uint32_t    off;
+    uint32_t        off; // current offset in partition
+    core_dump_crc_t crc; // CRC of dumped data
 } core_dump_write_flash_data_t;
 
 typedef struct _core_dump_partition_t
@@ -267,15 +266,20 @@ typedef struct _core_dump_partition_t
 
 typedef struct _core_dump_flash_config_t
 {
-    // core dump partition start
+    // core dump partition config
     core_dump_partition_t partition;
-    // core dump partition size
-    uint32_t              crc;
+    // CRC of core dump partition config
+    core_dump_crc_t       partition_config_crc;
 } core_dump_flash_config_t;
 
 // core dump flash data
 static core_dump_flash_config_t s_core_flash_config;
 
+static inline core_dump_crc_t esp_core_dump_calc_flash_config_crc(void)
+{
+    return crc32_le(0, (uint8_t const *)&s_core_flash_config.partition, sizeof(s_core_flash_config.partition));
+}
+
 static uint32_t esp_core_dump_write_flash_padded(size_t off, uint8_t *data, uint32_t data_size)
 {
     esp_err_t err;
@@ -302,8 +306,9 @@ static uint32_t esp_core_dump_write_flash_padded(size_t off, uint8_t *data, uint
     if (len) {
         // write last bytes with padding, actual TCB len can be retrieved by esptool from core dump header
         rom_data.data32 = 0;
-        for (k = 0; k < len; k++)
+        for (k = 0; k < len; k++) {
             rom_data.data8[k] = *(data + data_len + k);
+        }
         err = spi_flash_write(off + data_len, &rom_data, sizeof(uint32_t));
         if (err != ESP_OK) {
             ESP_COREDUMP_LOGE("Failed to finish write data to flash (%d)!", err);
@@ -322,18 +327,19 @@ static esp_err_t esp_core_dump_flash_write_prepare(void *priv, uint32_t *data_le
     core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv;
 
     // check for available space in partition
-    // add space for 2 magics. TODO: change to CRC
-    if ((*data_len + 2*sizeof(uint32_t)) > s_core_flash_config.partition.size) {
+    if ((*data_len + sizeof(uint32_t)) > s_core_flash_config.partition.size) {
         ESP_COREDUMP_LOGE("Not enough space to save core dump!");
         return ESP_ERR_NO_MEM;
     }
-    *data_len += 2*sizeof(uint32_t);
+    // add space for CRC
+    *data_len += sizeof(core_dump_crc_t);
 
-    wr_data->off = 0;
+    memset(wr_data, 0, sizeof(*wr_data));
 
     sec_num = *data_len / SPI_FLASH_SEC_SIZE;
-    if (*data_len % SPI_FLASH_SEC_SIZE)
+    if (*data_len % SPI_FLASH_SEC_SIZE) {
         sec_num++;
+    }
     assert(sec_num * SPI_FLASH_SEC_SIZE <= s_core_flash_config.partition.size);
     err = spi_flash_erase_range(s_core_flash_config.partition.start + 0, sec_num * SPI_FLASH_SEC_SIZE);
     if (err != ESP_OK) {
@@ -362,9 +368,7 @@ static esp_err_t esp_core_dump_flash_write_word(core_dump_write_flash_data_t *wr
 
 static esp_err_t esp_core_dump_flash_write_start(void *priv)
 {
-    core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv;
-    // save magic 1
-    return esp_core_dump_flash_write_word(wr_data, COREDUMP_FLASH_MAGIC_START);
+    return ESP_OK;
 }
 
 static esp_err_t esp_core_dump_flash_write_end(void *priv)
@@ -381,17 +385,16 @@ static esp_err_t esp_core_dump_flash_write_end(void *priv)
     if (err != ESP_OK) {
         ESP_COREDUMP_LOGE("Failed to read flash (%d)!", err);
         return err;
-    }
-    else {
+    } else {
         ESP_COREDUMP_LOG_PROCESS("Data from flash:");
         for (uint32_t i = 0; i < sizeof(rom_data)/sizeof(rom_data.data32[0]); i++) {
             ESP_COREDUMP_LOG_PROCESS("%x", rom_data.data32[i]);
         }
     }
 #endif
-
-    // save magic 2
-    return esp_core_dump_flash_write_word(wr_data, COREDUMP_FLASH_MAGIC_END);
+    // write core dump CRC
+    ESP_COREDUMP_LOG_PROCESS("Dump data CRC = 0x%x", wr_data->crc);
+    return esp_core_dump_flash_write_word(wr_data, wr_data->crc);
 }
 
 static esp_err_t esp_core_dump_flash_write_data(void *priv, void * data, uint32_t data_len)
@@ -400,10 +403,12 @@ static esp_err_t esp_core_dump_flash_write_data(void *priv, void * data, uint32_
     core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv;
 
     uint32_t len = esp_core_dump_write_flash_padded(s_core_flash_config.partition.start + wr_data->off, data, data_len);
-    if (len != data_len)
+    if (len != data_len) {
         return ESP_FAIL;
+    }
 
     wr_data->off += len;
+    wr_data->crc = crc32_le(wr_data->crc, data, data_len);
 
     return err;
 }
@@ -413,10 +418,14 @@ void esp_core_dump_to_flash(XtExcFrame *frame)
     core_dump_write_config_t wr_cfg;
     core_dump_write_flash_data_t wr_data;
 
-    uint32_t crc = crc32_le(UINT32_MAX, (uint8_t const *)&s_core_flash_config.partition,
-                            sizeof(s_core_flash_config.partition));
-    if (s_core_flash_config.crc != crc) {
-        ESP_COREDUMP_LOGE("Core dump flash config is corrupted! CRC=0x%x instead of 0x%x", crc, s_core_flash_config.crc);
+    core_dump_crc_t crc = esp_core_dump_calc_flash_config_crc();
+    if (s_core_flash_config.partition_config_crc != crc) {
+        ESP_COREDUMP_LOGE("Core dump flash config is corrupted! CRC=0x%x instead of 0x%x", crc, s_core_flash_config.partition_config_crc);
+        return;
+    }
+    // check that partition can hold at least core dump data length
+    if (s_core_flash_config.partition.start == 0 || s_core_flash_config.partition.size < sizeof(uint32_t)) {
+        ESP_COREDUMP_LOGE("Invalid flash partition config!");
         return;
     }
 
@@ -500,10 +509,11 @@ static esp_err_t esp_core_dump_uart_write_data(void *priv, void * data, uint32_t
 static int esp_core_dump_uart_get_char() {
     int i;
     uint32_t reg = (READ_PERI_REG(UART_STATUS_REG(0)) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT;
-    if (reg)
+    if (reg) {
         i = READ_PERI_REG(UART_FIFO_REG(0));
-    else
+    } else {
         i = -1;
+    }
     return i;
 }
 
@@ -532,8 +542,9 @@ void esp_core_dump_to_uart(XtExcFrame *frame)
     ch = esp_core_dump_uart_get_char();
     while (!(ch == '\n' || ch == '\r')) {
         tm_cur = xthal_get_ccount() / cpu_ticks_per_ms;
-        if (tm_cur >= tm_end)
+        if (tm_cur >= tm_end){
             break;
+        }
         ch = esp_core_dump_uart_get_char();
     }
     ESP_COREDUMP_LOGI("Print core dump to uart...");
@@ -554,10 +565,9 @@ void esp_core_dump_init()
         return;
     }
     ESP_COREDUMP_LOGI("Found partition '%s' @ %x %d bytes", core_part->label, core_part->address, core_part->size);
-    s_core_flash_config.partition.start = core_part->address;
-    s_core_flash_config.partition.size  = core_part->size;
-    s_core_flash_config.crc             = crc32_le(UINT32_MAX, (uint8_t const *)&s_core_flash_config.partition,
-                                                    sizeof(s_core_flash_config.partition));
+    s_core_flash_config.partition.start      = core_part->address;
+    s_core_flash_config.partition.size       = core_part->size;
+    s_core_flash_config.partition_config_crc = esp_core_dump_calc_flash_config_crc();
 #endif
 #if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART
     ESP_COREDUMP_LOGI("Init core dump to UART");
index c6634364c52f3390a0821b4a09ebbcd4ccfb904a..89a1c2779c6c4c22512fd0799a44a89475678d98 100644 (file)
@@ -25,29 +25,29 @@ void esp_core_dump_init();
  * @brief  Saves core dump to flash.
  *
  * The structure of data stored in flash is as follows:
- * |   MAGIC1   |
+ *
  * |  TOTAL_LEN |  TASKS_NUM | TCB_SIZE |
  * | TCB_ADDR_1 | STACK_TOP_1 | STACK_END_1 | TCB_1 | STACK_1 |
  * .            .       .         .
  * .            .       .         .
  * | TCB_ADDR_N | STACK_TOP_N | STACK_END_N | TCB_N | STACK_N |
- * |   MAGIC2   |
+ * |    CRC32   |
+ *
  * Core dump in flash consists of header and data for every task in the system at the moment of crash.
- * For flash data integrity control two magic numbers are used at the beginning and the end of core dump.
+ * For flash data integrity control CRC is used at the end of core the dump data.
  * The structure of core dump data is described below in details.
- * 1) MAGIC1 and MAGIC2 are special numbers stored at the beginning and the end of core dump.
- *    They are used to control core dump data integrity. Size of every number is 4 bytes.
- * 2) Core dump starts with header:
- * 2.1) TOTAL_LEN is total length of core dump data in flash including magic numbers. Size is 4 bytes.
- * 2.2) TASKS_NUM is the number of tasks for which data are stored. Size is 4 bytes.
- * 2.3) TCB_SIZE is the size of task's TCB structure. Size is 4 bytes.
- * 3) Core dump header is followed by the data for every task in the system.
+ * 1) Core dump starts with header:
+ * 1.1) TOTAL_LEN is total length of core dump data in flash including CRC. Size is 4 bytes.
+ * 1.2) TASKS_NUM is the number of tasks for which data are stored. Size is 4 bytes.
+ * 1.3) TCB_SIZE is the size of task's TCB structure. Size is 4 bytes.
+ * 2) Core dump header is followed by the data for every task in the system.
  *    Task data are started with task header:
- * 3.1) TCB_ADDR is the address of TCB in memory. Size is 4 bytes.
- * 3.2) STACK_TOP is the top of task's stack (address of the topmost stack item). Size is 4 bytes.
- * 3.2) STACK_END is the end of task's stack (address from which task's stack starts). Size is 4 bytes.
- * 4) Task header is followed by TCB data. Size is TCB_SIZE bytes.
- * 5) Task's stack is placed after TCB data. Size is (STACK_END - STACK_TOP) bytes.
+ * 2.1) TCB_ADDR is the address of TCB in memory. Size is 4 bytes.
+ * 2.2) STACK_TOP is the top of task's stack (address of the topmost stack item). Size is 4 bytes.
+ * 2.2) STACK_END is the end of task's stack (address from which task's stack starts). Size is 4 bytes.
+ * 3) Task header is followed by TCB data. Size is TCB_SIZE bytes.
+ * 4) Task's stack is placed after TCB data. Size is (STACK_END - STACK_TOP) bytes.
+ * 5) CRC is placed at the end of the data.
  */
 void esp_core_dump_to_flash();
 
@@ -55,8 +55,8 @@ void esp_core_dump_to_flash();
  * @brief  Print base64-encoded core dump to UART.
  *
  * The structure of core dump data is the same as for data stored in flash (@see esp_core_dump_to_flash) with some notes:
- * 1) Magic numbers are not present in core dump printed to UART.
- * 2) Since magic numbers are omitted TOTAL_LEN does not include their size.
+ * 1) CRC is not present in core dump printed to UART.
+ * 2) Since CRC is omitted TOTAL_LEN does not include its size.
  * 3) Printed base64 data are surrounded with special messages to help user recognize the start and end of actual data.
  */
 void esp_core_dump_to_uart();
index 7f024eb5f0e37f4370ff5e43b5eae8bb20eaafeb..bb45dfb244e6c1e5f6a2b2d0d235378517d3a69b 100755 (executable)
@@ -24,6 +24,7 @@ import struct
 import array
 import errno
 import base64
+import binascii
 
 idf_path = os.getenv('IDF_PATH')
 if idf_path:
@@ -35,7 +36,7 @@ except ImportError:
     print("Esptool is not found! Set proper $IDF_PATH in environment.")
     sys.exit(2)
 
-__version__ = "0.2-dev"
+__version__ = "0.3-dev"
 
 if os.name == 'nt':
     CLOSE_FDS = False
@@ -690,12 +691,10 @@ class ESPCoreDumpFileLoader(ESPCoreDumpLoader):
 class ESPCoreDumpFlashLoader(ESPCoreDumpLoader):
     """Core dump flash loader class
     """
-    ESP32_COREDUMP_FLASH_MAGIC_START    = 0xE32C04ED
-    ESP32_COREDUMP_FLASH_MAGIC_END      = 0xE32C04ED
-    ESP32_COREDUMP_FLASH_MAGIC_FMT      = '<L'
-    ESP32_COREDUMP_FLASH_MAGIC_SZ       = struct.calcsize(ESP32_COREDUMP_FLASH_MAGIC_FMT)
-    ESP32_COREDUMP_FLASH_HDR_FMT        = '<4L'
-    ESP32_COREDUMP_FLASH_HDR_SZ         = struct.calcsize(ESP32_COREDUMP_FLASH_HDR_FMT)
+    ESP32_COREDUMP_FLASH_CRC_FMT    = '<L'
+    ESP32_COREDUMP_FLASH_CRC_SZ     = struct.calcsize(ESP32_COREDUMP_FLASH_CRC_FMT)
+    ESP32_COREDUMP_FLASH_LEN_FMT    = '<L'
+    ESP32_COREDUMP_FLASH_LEN_SZ     = struct.calcsize(ESP32_COREDUMP_FLASH_LEN_FMT)
 
     def __init__(self, off, tool_path=None, chip='esp32', port=None, baud=None):
         """Constructor for core dump flash loader
@@ -722,7 +721,7 @@ class ESPCoreDumpFlashLoader(ESPCoreDumpLoader):
             tool_args.extend(['-p', self.port])
         if self.baud:
             tool_args.extend(['-b', str(self.baud)])
-        tool_args.extend(['read_flash', str(off), str(self.ESP32_COREDUMP_FLASH_HDR_SZ), ''])
+        tool_args.extend(['read_flash', str(off), str(self.ESP32_COREDUMP_FLASH_LEN_SZ), ''])
 
         self.fcore_name = None
         try:
@@ -750,26 +749,20 @@ class ESPCoreDumpFlashLoader(ESPCoreDumpLoader):
     def _read_core_dump_length(self, f):
         """Reads core dump length
         """
-        data = f.read(4*4)
-        mag1,tot_len,task_num,tcbsz = struct.unpack_from(self.ESP32_COREDUMP_FLASH_HDR_FMT, data)
-        if mag1 != self.ESP32_COREDUMP_FLASH_MAGIC_START:
-            raise ESPCoreDumpLoaderError("Invalid start magic number!")
+        data = f.read(self.ESP32_COREDUMP_FLASH_LEN_SZ)
+        tot_len, = struct.unpack_from(self.ESP32_COREDUMP_FLASH_LEN_FMT, data)
         return tot_len
 
     def create_corefile(self, core_fname=None, rom_elf=None):
         """Checks flash coredump data integrity and creates ELF file
         """
-        data = self.read_data(0, self.ESP32_COREDUMP_FLASH_MAGIC_SZ)
-        mag1, = struct.unpack_from(self.ESP32_COREDUMP_FLASH_MAGIC_FMT, data)
-        if mag1 != self.ESP32_COREDUMP_FLASH_MAGIC_START:
-            raise ESPCoreDumpLoaderError("Invalid start marker %x" % mag1)
-
-        data = self.read_data(self.dump_sz-self.ESP32_COREDUMP_FLASH_MAGIC_SZ, self.ESP32_COREDUMP_FLASH_MAGIC_SZ)
-        mag2, = struct.unpack_from(self.ESP32_COREDUMP_FLASH_MAGIC_FMT, data)
-        if mag2 != self.ESP32_COREDUMP_FLASH_MAGIC_END:
-            raise ESPCoreDumpLoaderError("Invalid end marker %x" % mag2)
-        
-        return super(ESPCoreDumpFlashLoader, self).create_corefile(core_fname, off=self.ESP32_COREDUMP_FLASH_MAGIC_SZ, rom_elf=rom_elf)
+        data = self.read_data(self.dump_sz - self.ESP32_COREDUMP_FLASH_CRC_SZ, self.ESP32_COREDUMP_FLASH_CRC_SZ)
+        dump_crc, = struct.unpack_from(self.ESP32_COREDUMP_FLASH_CRC_FMT, data)
+        data = self.read_data(0, self.dump_sz - self.ESP32_COREDUMP_FLASH_CRC_SZ)
+        data_crc = binascii.crc32(data) & 0xffffffff
+        if dump_crc != data_crc:
+            raise ESPCoreDumpLoaderError("Invalid core dump CRC %x, should be %x" % (data_crc, dump_crc))        
+        return super(ESPCoreDumpFlashLoader, self).create_corefile(core_fname)
 
 
 class GDBMIOutRecordHandler(object):
index 4056fdb0f70257c922b744dae611b46e113780db..568935006a708d1545df217d331d2919de9e463d 100644 (file)
@@ -1,4 +1,4 @@
-espcoredump.py v0.2-dev
+espcoredump.py v0.3-dev
 ===============================================================
 ==================== ESP32 CORE DUMP START ====================
 
index f4e50d8531edad574a11e9cf7c95a485a498325a..32599ab10a20637b0b26bfce9809a8ce2280b1ad 100644 (file)
@@ -1,4 +1,4 @@
-espcoredump.py v0.2-dev
+espcoredump.py v0.3-dev
 ===============================================================
 ==================== ESP32 CORE DUMP START ====================
 
index aa33917e2c07d11b21fb09e2c5cfbead6f313f28..80185f9e0458df179a2bcc73701c7bdf0d3c4a77 100644 (file)
@@ -300,7 +300,12 @@ extern void vPortCleanUpTCB ( void *pxTCB );
 #define configXT_BOARD                      1   /* Board mode */
 #define configXT_SIMULATOR                                     0
 
-#define configENABLE_TASK_SNAPSHOT                     1
+#if CONFIG_ESP32_ENABLE_COREDUMP
+#define configENABLE_TASK_SNAPSHOT          1
+#endif
+#ifndef configENABLE_TASK_SNAPSHOT
+#define configENABLE_TASK_SNAPSHOT          1
+#endif
 
 #if CONFIG_SYSVIEW_ENABLE
 #ifndef __ASSEMBLER__
index 0b313804fd4d9392b50e6f39ad16ea92472d2f70..be75cbe1defe357a6d0f05abbacd1b677b63a442 100644 (file)
@@ -24,9 +24,7 @@ There are a number of core dump related configuration options which user can cho
 * Save core dump to flash
 * Print core dump to UART
 
-2. Logging level of core dump module (`Components -> ESP32-specific config -> Core dump module logging level`). Value is a number from 0 (no output) to 5 (most verbose).
-
-3. Delay before core dump will be printed to UART (`Components -> ESP32-specific config -> Core dump print to UART delay`). Value is in ms.
+2. Delay before core dump will be printed to UART (`Components -> ESP32-specific config -> Core dump print to UART delay`). Value is in ms.
 
 
 Save core dump to flash