#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__)
#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);
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;
#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
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;
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);
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) {
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)
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)
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;
}
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;
}
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;
}
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...");
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");
* @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();
* @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();
import array
import errno
import base64
+import binascii
idf_path = os.getenv('IDF_PATH')
if idf_path:
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
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
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:
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):