esp32: Replaces magic numbers with CRC for core dump in flash

This commit is contained in:
Alexey Gerenkov 2017-09-13 21:30:48 +03:00 committed by bot
parent 8b5f61eb35
commit a55cc99f50
8 changed files with 90 additions and 91 deletions

View 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

View file

@ -25,11 +25,12 @@
#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");

View 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();

View file

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

View file

@ -1,4 +1,4 @@
espcoredump.py v0.2-dev
espcoredump.py v0.3-dev
===============================================================
==================== ESP32 CORE DUMP START ====================

View file

@ -1,4 +1,4 @@
espcoredump.py v0.2-dev
espcoredump.py v0.3-dev
===============================================================
==================== ESP32 CORE DUMP START ====================

View 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__

View 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