coredump: Makes compatible with legacy binary core dumps

Also:
 - improves coredump versioning scheme
 - Moves some API funtions to respective flash/UART dependent code
This commit is contained in:
Alexey Gerenkov 2019-11-22 18:15:19 +03:00
parent c56a954976
commit e092d6f858
10 changed files with 1000 additions and 955 deletions

View file

@ -444,11 +444,6 @@ void start_cpu0_default(void)
#if CONFIG_ESP32_ENABLE_COREDUMP
esp_core_dump_init();
size_t core_data_sz = 0;
size_t core_data_addr = 0;
if (esp_core_dump_image_get(&core_data_addr, &core_data_sz) == ESP_OK && core_data_sz > 0) {
ESP_LOGI(TAG, "Found core dump %d bytes in flash @ 0x%x", core_data_sz, core_data_addr);
}
#endif
#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE

View file

@ -557,16 +557,26 @@ class ESPCoreDumpLoaderError(ESPCoreDumpError):
super(ESPCoreDumpLoaderError, self).__init__(message)
def esp_core_dump_ver(chip, maj, min):
return (((chip & 0xFFFF) << 16) | ((maj & 0xFF) << 8) | ((min & 0xFF) << 0))
class ESPCoreDumpLoader(object):
"""Core dump loader base class
"""
ESP32_COREDUMP_VERSION_BIN = 1
ESP32_COREDUMP_VERSION_ELF_CRC32 = 2
ESP32_COREDUMP_VERSION_ELF_SHA256 = 3
# TODO: add class for core dump version and move all version-dependent params to it
ESP_CORE_DUMP_CHIP_ESP32 = 0
# "legacy" stands for core dumps v0.1 (before IDF v4.1)
ESP32_COREDUMP_VERSION_BIN_V1 = esp_core_dump_ver(ESP_CORE_DUMP_CHIP_ESP32, 0, 1)
ESP32_COREDUMP_VERSION_BIN_V2 = esp_core_dump_ver(ESP_CORE_DUMP_CHIP_ESP32, 0, 2)
ESP32_COREDUMP_VERSION_ELF_CRC32 = esp_core_dump_ver(ESP_CORE_DUMP_CHIP_ESP32, 1, 0)
ESP32_COREDUMP_VERSION_ELF_SHA256 = esp_core_dump_ver(ESP_CORE_DUMP_CHIP_ESP32, 1, 1)
ESP_CORE_DUMP_INFO_TYPE = 8266
ESP_CORE_DUMP_TASK_INFO_TYPE = 678
ESP_CORE_DUMP_EXTRA_INFO_TYPE = 677
ESP_COREDUMP_CURR_TASK_MARKER = 0xdeadbeef
ESP32_COREDUMP_BIN_V1_HDR_FMT = '<4L'
ESP32_COREDUMP_BIN_V1_HDR_SZ = struct.calcsize(ESP32_COREDUMP_BIN_V1_HDR_FMT)
ESP32_COREDUMP_HDR_FMT = '<5L'
ESP32_COREDUMP_HDR_SZ = struct.calcsize(ESP32_COREDUMP_HDR_FMT)
ESP32_COREDUMP_TSK_HDR_FMT = '<3L'
@ -584,6 +594,7 @@ class ESPCoreDumpLoader(object):
"""Base constructor for core dump loader
"""
self.fcore = None
self.hdr = {}
def _get_registers_from_stack(self, data, grows_down):
"""Returns list of registers (in GDB format) from xtensa stack frame
@ -713,21 +724,18 @@ class ESPCoreDumpLoader(object):
if self.fcore_name:
self.remove_tmp_file(self.fcore_name)
def extract_elf_corefile(self, core_fname=None, exe_name=None, off=0):
def _extract_elf_corefile(self, core_fname=None, off=0, exe_name=None):
""" Reads the ELF formatted core dump image and parse it
"""
core_off = off
data = self.read_data(core_off, self.ESP32_COREDUMP_HDR_SZ)
tot_len,coredump_ver,task_num,tcbsz,segs_num = struct.unpack_from(self.ESP32_COREDUMP_HDR_FMT, data)
if coredump_ver == self.ESP32_COREDUMP_VERSION_ELF_CRC32:
if self.hdr['ver'] == self.ESP32_COREDUMP_VERSION_ELF_CRC32:
checksum_len = self.ESP32_COREDUMP_CRC_SZ
elif coredump_ver == self.ESP32_COREDUMP_VERSION_ELF_SHA256:
elif self.hdr['ver'] == self.ESP32_COREDUMP_VERSION_ELF_SHA256:
checksum_len = self.ESP32_COREDUMP_SHA256_SZ
else:
raise ESPCoreDumpLoaderError("Core dump version '%d' is not supported!" % coredump_ver)
core_off += self.ESP32_COREDUMP_HDR_SZ
raise ESPCoreDumpLoaderError("Core dump version '%d' is not supported!" % self.hdr['ver'])
core_elf = ESPCoreDumpElfFile()
data = self.read_data(core_off, tot_len - checksum_len - self.ESP32_COREDUMP_HDR_SZ)
data = self.read_data(core_off, self.hdr['tot_len'] - checksum_len - self.ESP32_COREDUMP_HDR_SZ)
with open(core_fname, 'w+b') as fce:
try:
fce.write(data)
@ -750,39 +758,27 @@ class ESPCoreDumpLoader(object):
n_ver_len = struct.calcsize("<L")
n_sha256_len = self.ESP32_COREDUMP_SHA256_SZ * 2 # SHA256 as hex string
n_ver,coredump_sha256 = struct.unpack("<L%ds" % (n_sha256_len), note.desc[:n_ver_len + n_sha256_len])
if coredump_sha256 != app_sha256 or n_ver != coredump_ver:
if coredump_sha256 != app_sha256 or n_ver != self.hdr['ver']:
raise ESPCoreDumpError("Invalid application image for coredump: app_SHA256(%s) != coredump_SHA256(%s)." %
(app_sha256, coredump_sha256))
except ESPCoreDumpError as e:
logging.warning("Failed to extract ELF core dump image into file %s. (Reason: %s)" % (core_fname, e))
return core_fname
def create_corefile(self, core_fname=None, exe_name=None, rom_elf=None, off=0):
def _extract_bin_corefile(self, core_fname=None, rom_elf=None, off=0):
"""Creates core dump ELF file
"""
core_off = off
data = self.read_data(core_off, self.ESP32_COREDUMP_HDR_SZ)
tot_len,coredump_ver,task_num,tcbsz,segs_num = struct.unpack_from(self.ESP32_COREDUMP_HDR_FMT, data)
if not core_fname:
fce = tempfile.NamedTemporaryFile(mode='w+b', delete=False)
core_fname = fce.name
if coredump_ver == self.ESP32_COREDUMP_VERSION_ELF_CRC32 or coredump_ver == self.ESP32_COREDUMP_VERSION_ELF_SHA256:
return self.extract_elf_corefile(core_fname, exe_name)
elif coredump_ver > self.ESP32_COREDUMP_VERSION_ELF_SHA256:
raise ESPCoreDumpLoaderError("Core dump version '%d' is not supported! Should be up to '%d'." %
(coredump_ver, self.ESP32_COREDUMP_VERSION_ELF_SHA256))
with open(core_fname, 'w+b') as fce:
tcbsz_aligned = tcbsz
tcbsz_aligned = self.hdr['tcbsz']
if tcbsz_aligned % 4:
tcbsz_aligned = 4 * (old_div(tcbsz_aligned,4) + 1)
# The version of core dump is ESP32_COREDUMP_VERSION_BIN
core_off += self.ESP32_COREDUMP_HDR_SZ
core_elf = ESPCoreDumpElfFile()
notes = b''
core_dump_info_notes = b''
task_info_notes = b''
task_status = EspCoreDumpTaskStatus()
for i in range(task_num):
for i in range(self.hdr['task_num']):
task_status.task_index = i
task_status.task_flags = EspCoreDumpTaskStatus.TASK_STATUS_CORRECT
data = self.read_data(core_off, self.ESP32_COREDUMP_TSK_HDR_SZ)
@ -803,8 +799,8 @@ class ESPCoreDumpLoader(object):
task_status.task_tcb_addr = tcb_addr
try:
if self.tcb_is_sane(tcb_addr, tcbsz_aligned):
if tcbsz != tcbsz_aligned:
core_elf.add_program_segment(tcb_addr, data[:tcbsz - tcbsz_aligned],
if self.hdr['tcbsz'] != tcbsz_aligned:
core_elf.add_program_segment(tcb_addr, data[:self.hdr['tcbsz'] - tcbsz_aligned],
ESPCoreDumpElfFile.PT_LOAD, ESPCoreDumpSegment.PF_R | ESPCoreDumpSegment.PF_W)
else:
core_elf.add_program_segment(tcb_addr, data, ESPCoreDumpElfFile.PT_LOAD, ESPCoreDumpSegment.PF_R | ESPCoreDumpSegment.PF_W)
@ -844,20 +840,21 @@ class ESPCoreDumpLoader(object):
notes += note
if ESPCoreDumpElfFile.REG_EXCCAUSE_IDX in extra_regs and len(core_dump_info_notes) == 0:
# actually there will be only one such note - for crashed task
core_dump_info_notes += Elf32NoteDesc("ESP_CORE_DUMP_INFO", self.ESP_CORE_DUMP_INFO_TYPE, struct.pack("<L", coredump_ver)).dump()
core_dump_info_notes += Elf32NoteDesc("ESP_CORE_DUMP_INFO", self.ESP_CORE_DUMP_INFO_TYPE, struct.pack("<L", self.hdr['ver'])).dump()
exc_regs = []
for reg_id in extra_regs:
exc_regs.extend([reg_id, extra_regs[reg_id]])
core_dump_info_notes += Elf32NoteDesc("EXTRA_INFO", self.ESP_CORE_DUMP_EXTRA_INFO_TYPE,
struct.pack("<%dL" % (1 + len(exc_regs)), tcb_addr, *exc_regs)).dump()
for i in range(segs_num):
data = self.read_data(core_off, self.ESP32_COREDUMP_MEM_SEG_HDR_SZ)
core_off += self.ESP32_COREDUMP_MEM_SEG_HDR_SZ
mem_start,mem_sz = struct.unpack_from(self.ESP32_COREDUMP_MEM_SEG_HDR_FMT, data)
logging.debug("Read memory segment %d bytes @ 0x%x" % (mem_sz, mem_start))
data = self.read_data(core_off, stack_len_aligned)
core_elf.add_program_segment(mem_start, data, ESPCoreDumpElfFile.PT_LOAD, ESPCoreDumpSegment.PF_R | ESPCoreDumpSegment.PF_W)
core_off += mem_sz
if self.hdr['ver'] == self.ESP32_COREDUMP_VERSION_BIN_V2:
for i in range(self.hdr['segs_num']):
data = self.read_data(core_off, self.ESP32_COREDUMP_MEM_SEG_HDR_SZ)
core_off += self.ESP32_COREDUMP_MEM_SEG_HDR_SZ
mem_start,mem_sz = struct.unpack_from(self.ESP32_COREDUMP_MEM_SEG_HDR_FMT, data)
logging.debug("Read memory segment %d bytes @ 0x%x" % (mem_sz, mem_start))
data = self.read_data(core_off, stack_len_aligned)
core_elf.add_program_segment(mem_start, data, ESPCoreDumpElfFile.PT_LOAD, ESPCoreDumpSegment.PF_R | ESPCoreDumpSegment.PF_W)
core_off += mem_sz
# add notes
try:
core_elf.add_aux_segment(notes, ESPCoreDumpElfFile.PT_NOTE, 0)
@ -875,17 +872,35 @@ class ESPCoreDumpLoader(object):
# add ROM text sections
if rom_elf:
for ps in rom_elf.program_segments:
if ps.flags & ESPCoreDumpSegment.PF_X:
try:
core_elf.add_program_segment(ps.addr, ps.data, ESPCoreDumpElfFile.PT_LOAD, ps.flags)
except ESPCoreDumpError as e:
logging.warning("Skip ROM segment %d bytes @ 0x%x. (Reason: %s)" % (len(ps.data), ps.addr, e))
if (ps.flags & ESPCoreDumpSegment.PF_X) == 0:
continue
try:
core_elf.add_program_segment(ps.addr, ps.data, ESPCoreDumpElfFile.PT_LOAD, ps.flags)
except ESPCoreDumpError as e:
logging.warning("Skip ROM segment %d bytes @ 0x%x. (Reason: %s)" % (len(ps.data), ps.addr, e))
# dump core ELF
core_elf.e_type = ESPCoreDumpElfFile.ET_CORE
core_elf.e_machine = ESPCoreDumpElfFile.EM_XTENSA
core_elf.dump(fce)
return core_fname
def create_corefile(self, core_fname=None, exe_name=None, rom_elf=None, off=0):
"""Creates core dump ELF file
"""
data = self.read_data(off, self.ESP32_COREDUMP_HDR_SZ)
vals = struct.unpack_from(self.ESP32_COREDUMP_HDR_FMT, data)
self.hdr = dict(zip(('tot_len', 'ver', 'task_num', 'tcbsz', 'segs_num'), vals))
if not core_fname:
fce = tempfile.NamedTemporaryFile(mode='w+b', delete=False)
core_fname = fce.name
if self.hdr['ver'] == self.ESP32_COREDUMP_VERSION_ELF_CRC32 or self.hdr['ver'] == self.ESP32_COREDUMP_VERSION_ELF_SHA256:
return self._extract_elf_corefile(core_fname, off + self.ESP32_COREDUMP_HDR_SZ, exe_name)
elif self.hdr['ver'] == self.ESP32_COREDUMP_VERSION_BIN_V2:
return self._extract_bin_corefile(core_fname, rom_elf, off + self.ESP32_COREDUMP_HDR_SZ)
elif self.hdr['ver'] == self.ESP32_COREDUMP_VERSION_BIN_V1:
return self._extract_bin_corefile(core_fname, rom_elf, off + self.ESP32_COREDUMP_BIN_V1_HDR_SZ)
raise ESPCoreDumpLoaderError("Core dump version '0x%x' is not supported!" % (self.hdr['ver']))
def read_data(self, off, sz):
"""Reads data from raw core dump got from flash or UART
"""
@ -1101,7 +1116,8 @@ class ESPCoreDumpFlashLoader(ESPCoreDumpLoader):
data = self.read_data(0, self.ESP32_COREDUMP_HDR_SZ)
self.checksum_len = 0
_,coredump_ver,_,_,_ = struct.unpack_from(self.ESP32_COREDUMP_HDR_FMT, data)
if coredump_ver == self.ESP32_COREDUMP_VERSION_ELF_CRC32 or coredump_ver == self.ESP32_COREDUMP_VERSION_BIN:
if coredump_ver == self.ESP32_COREDUMP_VERSION_ELF_CRC32 or coredump_ver == self.ESP32_COREDUMP_VERSION_BIN_V1 \
or coredump_ver == self.ESP32_COREDUMP_VERSION_BIN_V2:
logging.debug("Dump size = %d, crc off = 0x%x", self.dump_sz, self.dump_sz - self.ESP32_COREDUMP_CRC_SZ)
data = self.read_data(self.dump_sz - self.ESP32_COREDUMP_CRC_SZ, self.ESP32_COREDUMP_CRC_SZ)
dump_crc, = struct.unpack_from(self.ESP32_COREDUMP_CRC_FMT, data)
@ -1470,7 +1486,7 @@ def info_corefile(args):
def gdbmi_freertos_get_task_name(p, tcb_addr):
p,res = gdbmi_data_evaluate_expression(p, "(char*)((TCB_t *)0x%x)->pcTaskName" % tcb_addr)
result = re.match('0x[a-fA-F0-9]+[ \t]*\'([^\']*)\'', res.value)
result = re.match("0x[a-fA-F0-9]+[^']*'([^']*)'", res.value)
if result:
return p,result.group(1)
return p,''
@ -1691,7 +1707,8 @@ def main():
parser_debug_coredump.add_argument('--gdb', '-g', help='Path to gdb', default='xtensa-esp32-elf-gdb')
parser_debug_coredump.add_argument('--core', '-c', help='Path to core dump file (if skipped core dump will be read from flash)', type=str)
parser_debug_coredump.add_argument('--core-format', '-t', help='(elf, raw or b64). File specified with "-c" is an ELF ("elf"), '
'raw (raw) or base64-encoded (b64) binary', type=str, default='elf')
'raw (raw) or base64-encoded (b64) binary',
choices=['b64', 'elf', 'raw'], type=str, default='elf')
parser_debug_coredump.add_argument('--off', '-o', help='Ofsset of coredump partition in flash '
'(type "make partition_table" to see).', type=int, default=None)
parser_debug_coredump.add_argument('--save-core', '-s', help='Save core to file. Othwerwise temporary core file will be deleted. '
@ -1706,7 +1723,8 @@ def main():
parser_info_coredump.add_argument('--gdb', '-g', help='Path to gdb', default='xtensa-esp32-elf-gdb')
parser_info_coredump.add_argument('--core', '-c', help='Path to core dump file (if skipped core dump will be read from flash)', type=str)
parser_info_coredump.add_argument('--core-format', '-t', help='(elf, raw or b64). File specified with "-c" is an ELF ("elf"), '
'raw (raw) or base64-encoded (b64) binary', type=str, default='elf')
'raw (raw) or base64-encoded (b64) binary',
choices=['b64', 'elf', 'raw'], type=str, default='elf')
parser_info_coredump.add_argument('--off', '-o', help='Offset of coredump partition in flash (type '
'"make partition_table" to see).', type=int, default=None)
parser_info_coredump.add_argument('--save-core', '-s', help='Save core to file. Othwerwise temporary core file will be deleted. '

View file

@ -27,11 +27,19 @@
#include "esp_core_dump_priv.h"
#include "soc/cpu.h"
#include "esp_debug_helpers.h"
#include "esp_app_format.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_IDF_TARGET_ESP32
#define COREDUMP_VERSION_CHIP ESP_CHIP_ID_ESP32
#elif CONFIG_IDF_TARGET_ESP32S2BETA
// TODO: set to ESP32-S2 chip ID
#define COREDUMP_VERSION_CHIP ~ESP_CHIP_ID_ESP32
#endif
#define COREDUMP_TCB_SIZE sizeof(StaticTask_t)
// Gets RTOS tasks snapshot

View file

@ -41,9 +41,15 @@ extern "C" {
#endif
#define COREDUMP_MAX_TASK_STACK_SIZE (64*1024)
#define COREDUMP_VERSION_BIN 1
#define COREDUMP_VERSION_ELF_CRC32 2
#define COREDUMP_VERSION_ELF_SHA256 3
// COREDUMP_VERSION_CHIP is defined in ports
#define COREDUMP_VERSION_MAKE(_maj_, _min_) ((((COREDUMP_VERSION_CHIP)&0xFFFF) << 16) | (((_maj_)&0xFF) << 8) | (((_min_)&0xFF) << 0))
#define COREDUMP_VERSION_BIN 0
#define COREDUMP_VERSION_ELF 1
// legacy bin coredumps (before IDF v4.1) has version set to 1
#define COREDUMP_VERSION_BIN_LEGACY COREDUMP_VERSION_MAKE(COREDUMP_VERSION_BIN, 1) // -> 0x0001
#define COREDUMP_VERSION_BIN_CURRENT COREDUMP_VERSION_MAKE(COREDUMP_VERSION_BIN, 2) // -> 0x0002
#define COREDUMP_VERSION_ELF_CRC32 COREDUMP_VERSION_MAKE(COREDUMP_VERSION_ELF, 0) // -> 0x0100
#define COREDUMP_VERSION_ELF_SHA256 COREDUMP_VERSION_MAKE(COREDUMP_VERSION_ELF, 1) // -> 0x0101
#define COREDUMP_CURR_TASK_MARKER 0xDEADBEEF
#define COREDUMP_CURR_TASK_NOT_FOUND -1
@ -55,7 +61,7 @@ extern "C" {
#define COREDUMP_SHA256_LEN 32
#endif
#else
#define COREDUMP_VERSION COREDUMP_VERSION_BIN
#define COREDUMP_VERSION COREDUMP_VERSION_BIN_CURRENT
#endif
typedef esp_err_t (*esp_core_dump_write_prepare_t)(void *priv, uint32_t *data_len);

View file

@ -13,7 +13,6 @@
// limitations under the License.
#include <string.h>
#include <stdbool.h>
#include "esp_partition.h"
#include "sdkconfig.h"
#include "esp_core_dump_priv.h"
#include "core_dump_elf.h"
@ -256,94 +255,7 @@ inline void esp_core_dump_write(void *frame, core_dump_write_config_t *write_cfg
esp_core_dump_report_stack_usage();
}
void esp_core_dump_init(void)
void __attribute__((weak)) esp_core_dump_init(void)
{
#if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH
esp_core_dump_flash_init();
#endif
#if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART
ESP_COREDUMP_LOGI("Init core dump to UART");
#endif
}
esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
{
esp_err_t err;
const void *core_data;
spi_flash_mmap_handle_t core_data_handle;
if (out_addr == NULL || out_size == NULL) {
return ESP_ERR_INVALID_ARG;
}
const esp_partition_t *core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_COREDUMP,
NULL);
if (!core_part) {
ESP_LOGE(TAG, "No core dump partition found!");
return ESP_ERR_NOT_FOUND;
}
if (core_part->size < sizeof(uint32_t)) {
ESP_LOGE(TAG, "Too small core dump partition!");
return ESP_ERR_INVALID_SIZE;
}
err = esp_partition_mmap(core_part, 0, sizeof(uint32_t),
SPI_FLASH_MMAP_DATA, &core_data, &core_data_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to mmap core dump data (%d)!", err);
return err;
}
uint32_t *dw = (uint32_t *)core_data;
*out_size = *dw;
spi_flash_munmap(core_data_handle);
if ((*out_size < sizeof(uint32_t)) || (*out_size > core_part->size)) {
ESP_LOGE(TAG, "Incorrect size of core dump image: %d", *out_size);
return ESP_ERR_INVALID_SIZE;
}
// remap full core dump with CRC
err = esp_partition_mmap(core_part, 0, *out_size,
SPI_FLASH_MMAP_DATA, &core_data, &core_data_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to mmap core dump data (%d)!", err);
return err;
}
#if CONFIG_ESP32_COREDUMP_CHECKSUM_CRC32
uint32_t *crc = (uint32_t *)(((uint8_t *)core_data) + *out_size);
crc--; // Point to CRC field
// Calculate CRC over core dump data except for CRC field
core_dump_crc_t cur_crc = crc32_le(0, (uint8_t const *)core_data, *out_size - sizeof(core_dump_crc_t));
if (*crc != cur_crc) {
ESP_LOGD(TAG, "Core dump CRC offset 0x%x, data size: %u",
(uint32_t)((uint32_t)crc - (uint32_t)core_data), *out_size);
ESP_LOGE(TAG, "Core dump data CRC check failed: 0x%x -> 0x%x!", *crc, cur_crc);
spi_flash_munmap(core_data_handle);
return ESP_ERR_INVALID_CRC;
}
#elif CONFIG_ESP32_COREDUMP_CHECKSUM_SHA256
uint8_t* sha256_ptr = (uint8_t*)(((uint8_t *)core_data) + *out_size);
sha256_ptr -= COREDUMP_SHA256_LEN;
ESP_LOGD(TAG, "Core dump data offset, size: %d, %u!",
(uint32_t)((uint32_t)sha256_ptr - (uint32_t)core_data), *out_size);
unsigned char sha_output[COREDUMP_SHA256_LEN];
mbedtls_sha256_context ctx;
ESP_LOGI(TAG, "Calculate SHA256 for coredump:");
(void)esp_core_dump_sha(&ctx, core_data, *out_size - COREDUMP_SHA256_LEN, sha_output);
if (memcmp((uint8_t*)sha256_ptr, (uint8_t*)sha_output, COREDUMP_SHA256_LEN) != 0) {
ESP_LOGE(TAG, "Core dump data SHA256 check failed:");
esp_core_dump_print_sha256("Calculated SHA256", (uint8_t*)sha_output);
esp_core_dump_print_sha256("Image SHA256",(uint8_t*)sha256_ptr);
spi_flash_munmap(core_data_handle);
return ESP_ERR_INVALID_CRC;
} else {
ESP_LOGI(TAG, "Core dump data SHA256 is correct");
}
#endif
spi_flash_munmap(core_data_handle);
*out_addr = core_part->address;
return ESP_OK;
}
/* do nothing by default */
}

View file

@ -13,9 +13,14 @@
// limitations under the License.
#include <string.h>
#include "esp_partition.h"
#include "esp32/rom/crc.h"
#include "esp_log.h"
#include "esp_core_dump_priv.h"
#include "esp_flash_internal.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/crc.h"
#elif CONFIG_IDF_TARGET_ESP32S2BETA
#include "esp32s2beta/rom/crc.h"
#endif
const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_flash";
@ -50,6 +55,7 @@ static core_dump_flash_config_t s_core_flash_config;
#define ESP_COREDUMP_FLASH_ERASE(_off_, _len_) esp_flash_erase_region(esp_flash_default_chip, _off_, _len_)
#endif
esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size);
static inline core_dump_crc_t esp_core_dump_calc_flash_config_crc(void)
{
@ -251,5 +257,97 @@ void esp_core_dump_to_flash(void *frame)
esp_core_dump_write(frame, &wr_cfg);
ESP_COREDUMP_LOGI("Core dump has been saved to flash.");
}
void esp_core_dump_init(void)
{
size_t core_data_sz = 0;
size_t core_data_addr = 0;
esp_core_dump_flash_init();
if (esp_core_dump_image_get(&core_data_addr, &core_data_sz) == ESP_OK && core_data_sz > 0) {
ESP_COREDUMP_LOGI("Found core dump %d bytes in flash @ 0x%x", core_data_sz, core_data_addr);
}
}
#endif
esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
{
esp_err_t err;
const void *core_data;
spi_flash_mmap_handle_t core_data_handle;
if (out_addr == NULL || out_size == NULL) {
return ESP_ERR_INVALID_ARG;
}
const esp_partition_t *core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_COREDUMP,
NULL);
if (!core_part) {
ESP_LOGE(TAG, "No core dump partition found!");
return ESP_ERR_NOT_FOUND;
}
if (core_part->size < sizeof(uint32_t)) {
ESP_LOGE(TAG, "Too small core dump partition!");
return ESP_ERR_INVALID_SIZE;
}
err = esp_partition_mmap(core_part, 0, sizeof(uint32_t),
SPI_FLASH_MMAP_DATA, &core_data, &core_data_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to mmap core dump data (%d)!", err);
return err;
}
uint32_t *dw = (uint32_t *)core_data;
*out_size = *dw;
spi_flash_munmap(core_data_handle);
if ((*out_size < sizeof(uint32_t)) || (*out_size > core_part->size)) {
ESP_LOGE(TAG, "Incorrect size of core dump image: %d", *out_size);
return ESP_ERR_INVALID_SIZE;
}
// remap full core dump with CRC
err = esp_partition_mmap(core_part, 0, *out_size,
SPI_FLASH_MMAP_DATA, &core_data, &core_data_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to mmap core dump data (%d)!", err);
return err;
}
// TODO: check CRC or SHA basing on the version of coredump image stored in flash
#if CONFIG_ESP32_COREDUMP_CHECKSUM_CRC32
uint32_t *crc = (uint32_t *)(((uint8_t *)core_data) + *out_size);
crc--; // Point to CRC field
// Calculate CRC over core dump data except for CRC field
core_dump_crc_t cur_crc = crc32_le(0, (uint8_t const *)core_data, *out_size - sizeof(core_dump_crc_t));
if (*crc != cur_crc) {
ESP_LOGD(TAG, "Core dump CRC offset 0x%x, data size: %u",
(uint32_t)((uint32_t)crc - (uint32_t)core_data), *out_size);
ESP_LOGE(TAG, "Core dump data CRC check failed: 0x%x -> 0x%x!", *crc, cur_crc);
spi_flash_munmap(core_data_handle);
return ESP_ERR_INVALID_CRC;
}
#elif CONFIG_ESP32_COREDUMP_CHECKSUM_SHA256
uint8_t* sha256_ptr = (uint8_t*)(((uint8_t *)core_data) + *out_size);
sha256_ptr -= COREDUMP_SHA256_LEN;
ESP_LOGD(TAG, "Core dump data offset, size: %d, %u!",
(uint32_t)((uint32_t)sha256_ptr - (uint32_t)core_data), *out_size);
unsigned char sha_output[COREDUMP_SHA256_LEN];
mbedtls_sha256_context ctx;
ESP_LOGI(TAG, "Calculate SHA256 for coredump:");
(void)esp_core_dump_sha(&ctx, core_data, *out_size - COREDUMP_SHA256_LEN, sha_output);
if (memcmp((uint8_t*)sha256_ptr, (uint8_t*)sha_output, COREDUMP_SHA256_LEN) != 0) {
ESP_LOGE(TAG, "Core dump data SHA256 check failed:");
esp_core_dump_print_sha256("Calculated SHA256", (uint8_t*)sha_output);
esp_core_dump_print_sha256("Image SHA256",(uint8_t*)sha256_ptr);
spi_flash_munmap(core_data_handle);
return ESP_ERR_INVALID_CRC;
} else {
ESP_LOGI(TAG, "Core dump data SHA256 is correct");
}
#endif
spi_flash_munmap(core_data_handle);
*out_addr = core_part->address;
return ESP_OK;
}

View file

@ -166,4 +166,9 @@ void esp_core_dump_to_uart(XtExcFrame *frame)
esp_core_dump_write((void*)frame, &wr_cfg);
ESP_COREDUMP_LOGI("Core dump has been written to uart.");
}
void esp_core_dump_init(void)
{
ESP_COREDUMP_LOGI("Init core dump to UART");
}
#endif

View file

@ -1,38 +1,38 @@
UD0AAAIAAAAKAAAAfAEAAAAAAAA=
ID0AAAABAAAKAAAAfAEAAAAAAAA=
f0VMRgEBAQAAAAAAAAAAAAQAXgABAAAAAAAAADQAAAAAAAAAAAAAADQAIAAWACgA
AAAAAA==
BAAAAPQCAAAAAAAAAAAAAMAXAADAFwAABgAAAAAAAAA=
AQAAALQaAACgavs/oGr7P3wBAAB8AQAABgAAAAAAAAA=
AQAAADAcAAAgtPs/ILT7P/gBAAD4AQAABgAAAAAAAAA=
AQAAACgeAACQrPs/kKz7P3wBAAB8AQAABgAAAAAAAAA=
AQAAAKQfAABwqfs/cKn7PwwDAAAMAwAABgAAAAAAAAA=
AQAAALAiAABMgPs/TID7P3wBAAB8AQAABgAAAAAAAAA=
AQAAACwkAACQfvs/kH77P6gBAACoAQAABgAAAAAAAAA=
AQAAANQlAACwePs/sHj7P3wBAAB8AQAABgAAAAAAAAA=
AQAAAFAnAADwdvs/8Hb7P6wBAACsAQAABgAAAAAAAAA=
AQAAAPwoAAAUafs/FGn7P3wBAAB8AQAABgAAAAAAAAA=
AQAAAHgqAABgZ/s/YGf7P6ABAACgAQAABgAAAAAAAAA=
AQAAABgsAACYbPs/mGz7P3wBAAB8AQAABgAAAAAAAAA=
AQAAAJQtAACAvPs/gLz7P6gBAACoAQAABgAAAAAAAAA=
AQAAADwvAAD0ivs/9Ir7P3wBAAB8AQAABgAAAAAAAAA=
AQAAALgwAAAgifs/IIn7P8ABAADAAQAABgAAAAAAAAA=
AQAAAHgyAAA0+/o/NPv6P3wBAAB8AQAABgAAAAAAAAA=
AQAAAPQzAABg+fo/YPn6P8ABAADAAQAABgAAAAAAAAA=
AQAAALQ1AABwWPs/cFj7P3wBAAB8AQAABgAAAAAAAAA=
AQAAADA3AACwVvs/sFb7P6wBAACsAQAABgAAAAAAAAA=
AQAAANw4AACQUfs/kFH7P3wBAAB8AQAABgAAAAAAAAA=
AQAAAFg6AACwT/s/sE/7P8wBAADMAQAABgAAAAAAAAA=
BAAAACQ8AAAAAAAAAAAAABQBAAAUAQAABgAAAAAAAAA=
AQAAALQaAABgYvs/YGL7P3wBAAB8AQAABgAAAAAAAAA=
AQAAADAcAAAQqvs/EKr7P/ABAADwAQAABgAAAAAAAAA=
AQAAACAeAAB4ovs/eKL7P3wBAAB8AQAABgAAAAAAAAA=
AQAAAJwfAABgn/s/YJ/7PwQDAAAEAwAABgAAAAAAAAA=
AQAAAKAiAAA0dvs/NHb7P3wBAAB8AQAABgAAAAAAAAA=
AQAAABwkAACAdPs/gHT7P6ABAACgAQAABgAAAAAAAAA=
AQAAALwlAACYbvs/mG77P3wBAAB8AQAABgAAAAAAAAA=
AQAAADgnAADgbPs/4Gz7P6QBAACkAQAABgAAAAAAAAA=
AQAAANwoAADUYPs/1GD7P3wBAAB8AQAABgAAAAAAAAA=
AQAAAFgqAAAgX/s/IF/7P6ABAACgAQAABgAAAAAAAAA=
AQAAAPgrAABYZPs/WGT7P3wBAAB8AQAABgAAAAAAAAA=
AQAAAHQtAABwsvs/cLL7P6ABAACgAQAABgAAAAAAAAA=
AQAAABQvAADcgPs/3ID7P3wBAAB8AQAABgAAAAAAAAA=
AQAAAJAwAAAAf/s/AH/7P8gBAADIAQAABgAAAAAAAAA=
AQAAAFgyAAA0+/o/NPv6P3wBAAB8AQAABgAAAAAAAAA=
AQAAANQzAABg+fo/YPn6P8ABAADAAQAABgAAAAAAAAA=
AQAAAJQ1AABYUPs/WFD7P3wBAAB8AQAABgAAAAAAAAA=
AQAAABA3AACgTvs/oE77P6QBAACkAQAABgAAAAAAAAA=
AQAAALQ4AAB4Sfs/eEn7P3wBAAB8AQAABgAAAAAAAAA=
AQAAADA6AACgR/s/oEf7P8QBAADEAQAABgAAAAAAAAA=
BAAAAPQ7AAAAAAAAAAAAABQBAAAUAQAABgAAAAAAAAA=
CAAAAEwCAAABAAAA
Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoGr7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQ4NQCAIBgD9FABADRUAQP////8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYGL7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARQ4NQCAIBgD9FABADRUAQP////8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgODYDgtPs/
AgAAACy1+z8gtfs/cOn6PwAAAAAAAAAABQAAAK3///8gAAAAIGv7PwEAAACAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAODYDQqvs/
AgAAAByr+z8Qq/s/cOn6PwAAAAAAAAAABQAAAK3///8gAAAA4GL7PwEAAACAAAAA
AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -40,44 +40,44 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA
Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkKz7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1pIAQCAFBgD9FABADRUAQP////8XAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeKL7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3JIAQCAFBgD9FABADRUAQP////8XAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+TAIAwqvs/
rKr7PwAAAAAAAAAAwBsEAFcAAAA3AAAAnAH+PwAA9D8AAAAAAAAAAAAAAADDGwQA
AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+TAIAgoPs/
nKD7PwAAAAAAAAAA0hQBAFcAAAA3AAAA9D8AAAAAAAAAAAAAAAAAAHiDCIDAXvs/
AAAAAICC+z8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA
Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATID7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABogOQCAABgBsxABAd8QAQP////8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANHb7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsoUOQCAABgBsxABAd8QAQP////8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM44DYBQf/s/
AAAAAAAAAAABAAAAAQAAgAMAAAAjAAYA1JcIgEB/+z8DAAAAIwgGACAIBgABAAAA
IAgGAOCO+z8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFI4DYBAdfs/
AAAAAAAAAAABAAAAAQAAgAMAAAAjAAYAeJcIgDB1+z8DAAAAIwgGACAIBgABAAAA
IAgGANCE+z8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA
Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsHj7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABogOQCAFBgBsxABAd8QAQP////8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmG77PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsoUOQCAFBgBsxABAd8QAQP////8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM44DYCwd/s/
AAAAAAMAAAABAAAAAQAAgAMAAAAjAAYAepEIgJB3+z8Ucfs/SB0AQCAEBgABAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFI4DYCgbfs/
AAAAAAMAAAABAAAAAQAAgAMAAAAjCgYAHpEIgIBt+z/8Zvs/SB0AQCAEBgABAAAA
IAQGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -85,29 +85,14 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA
Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFGn7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASBQIQCAFBgD9FABADRUAQPn///8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1GD7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQIQCADBgD9FABADRUAQPn///8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALqbCIAgaPs/
AAAAAFojBADUlwiAAFf7PwMAAAAjCAYASBQIgABo+z/cAPA/AQAAADgA+z8BAAAA
IAUGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA
Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmGz7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASBQIQCADBgD9FABADRUAQPj///8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALqbCIBAvfs/
AAAAAFojBADtWA2A4Kn7PwAIAAAEAPs/SBQIgCC9+z/cAPA/AQAAADgA+z8BAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF6bCIDgX/s/
AAAAAGwcAQB4lwiA8E77PwMAAAAjCAYAFBQIgMBf+z/cAPA/AQAAADgA+z8BAAAA
IAMGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -115,15 +100,30 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA
Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9Ir7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASBQIQCAABgAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWGT7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQIQCABBgD9FABADRUAQPj///8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF2pCIDgifs/
AAAAAAAAAAAsgvs/AAAAAAAAAABgXPs/SBQIgMCJ+z/cAPA/AQAAADgA+z9wXPs/
iCsNQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF6bCIAws/s/
AAAAAGwcAQBxWA2A0J/7PwAIAAAEAPs/FBQIgBCz+z/cAPA/AQAAADgA+z8BAAAA
IAEGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA
Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3ID7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQIQCAABgAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGpCIDAf/s/
AAAAAAAAAAAUePs/AAAAAAAAAABQVPs/FBQIgKB/+z/cAPA/AQAAADgA+z9gVPs/
UCsNQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -131,13 +131,13 @@ AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA
Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANPv6PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASBQIQCAGBgAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQIQCAGBgAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJCNCIAg+vo/
AAAAAAAAAADoQfs/HQAAAFUAAADgUPs/SBQIgAD6+j/cAPA/AQAAADgA+z8BAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADSNCIAg+vo/
AAAAAAAAAADQOfs/FQAAAFUAAADQSPs/FBQIgAD6+j/cAPA/AQAAADgA+z8BAAAA
IAYGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -145,14 +145,14 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA
Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcFj7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkI0IQCAIBgAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWFD7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANI0IQCAIBgAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEMdCIBwV/s/
9FP7PwAAAABIVPs/AAAAAAEAAAAAAAAAkI0IgFBX+z8BAAAABAAAAOxB+z8KAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8dCIBgT/s/
3Ev7PwAAAAAwTPs/AAAAAAEAAAAAAAAANI0IgEBP+z8BAAAABAAAANQ5+z8KAAAA
AACAABwA9D8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -160,150 +160,150 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA
Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkFH7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASBQIQCAOBgAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeEn7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQIQCAOBgAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJCNCIBwUPs/
AAAAAAAAAADoQfs/zc0AAAEAAAAAAAAASBQIgFBQ+z/cAPA/AQAAADgA+z8BAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADSNCIBgSPs/
AAAAAAAAAADQOfs/zc0AAAEAAAAAAAAAFBQIgEBI+z/cAPA/AQAAADgA+z8BAAAA
IAAGAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
kLT7P7C1+z9yHwQAiED7P4hA+z+gavs/gED7PxIAAABYbPs/WGz7P6Bq+z8AAAAA
BwAAAByu+z91bmFsaWduZWRfcHRyX3QAAQAAABi2+z8AAAAAIAwGAA8AAADOzs7O
gKr7P6Cr+z+EGAEAcDj7P3A4+z9gYvs/aDj7PxIAAAAYZPs/GGT7P2Bi+z8AAAAA
BwAAAASk+z91bmFsaWduZWRfcHRyX3QAAQAAAACs+z8AAAAAIAwGAA8AAADOzs7O
BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOn6P3Dp+j/Y6fo/
AAAAAAAAAAABAAAAAAAAAAAAAAAAAAAASB0AQAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADOzs4=
776t3n0ODUAwCAYAWA4NgOC0+z8CAAAALLX7PyC1+z9w6fo/AAAAAAAAAAAFAAAA
rf///yAAAAAga/s/AQAAAIAAAAABAAAAAAAAAAAAAAAdAAAABQAAAP0UAEANFQBA
/////wEAAACAAAAAOCQIQFRH+z8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAEAAACAAAAAAQAAAAAAAABYDg2AELX7PwEAAABw6fo/
ELgNgBC1+z8KAAAAAwAAACC1+z9w6fo/AAAAAAAAAACgDg2AQLX7PwoAAACUDPs/
lAJAPx4AAACCWUA/AwAAAACOCIBQZ/s/AQAAANzn68S8gQiAcLX7PwAAAAAAAAAA
vIEIgHC1+z8AAAAAAwAAACAAAAAAAACAIQAGAAEAAAAAAAAAkLX7P4gODUAAAAAA
IwAGAIhA+z+gavs/AAAAAAAAAACwtfs/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvLX7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
776t3kUODUAwCAYAIA4NgNCq+z8CAAAAHKv7PxCr+z9w6fo/AAAAAAAAAAAFAAAA
rf///yAAAADgYvs/AQAAAIAAAAABAAAAAAAAAAAAAAAdAAAABQAAAP0UAEANFQBA
/////wEAAACAAAAABCQIQNw++z8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAEAAACAAAAAAQAAAAAAAAAgDg2AAKv7PwEAAABw6fo/
vLUNgACr+z8KAAAAAwAAABCr+z9w6fo/AAAAAAAAAABoDg2AMKv7PwoAAACUDPs/
lAJAPx4AAADmV0A/AwAAAKSNCIAQX/s/AQAAAO8BvNBggQiAYKv7PwAAAAAAAAAA
YIEIgGCr+z8AAAAAAwAAACAAAAAAAACAIQAGAAEAAAAAAAAAgKv7P1AODUAAAAAA
IwAGAHA4+z9gYvs/AAAAAAAAAACgq/s/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArKv7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
cKn7PxCs+z+PGwQAYED7P2BA+z+QrPs/WED7PxQAAAC0U/s/tFP7P5Cs+z8AAAAA
BQAAAICM+z91bml0eVRhc2sAzs7Ozs4AAAAAAHys+z8AAAAAIQAGAAwAAADOzs7O
AAAAAAAAAAAAAAAAAAAAAA==
YJ/7PwCi+z+hFAEASDj7P0g4+z94ovs/QDj7PxQAAACcS/s/nEv7P3ii+z8AAAAA
BQAAAGiC+z91bml0eVRhc2sAzs7Ozs4AAAAAAGSi+z8AAAAAIQAGAAwAAADOzs7O
BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOn6P3Dp+j/Y6fo/
AAAAAAAAAAABAAAAAAAAAAAAAAAAAAAASB0AQAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADOzs4=
nCQIQNaSAEAwBQYAD5MAgDCq+z+sqvs/AAAAAAAAAADAGwQAVwAAADcAAACcAf4/
AAD0PwAAAAAAAAAAAAAAAMMbBAAAAAAABAAAABcAAAD//wAAAAAAAP0UAEANFQBA
/////5wmCEDDGwQA/IMIQLQ9+z8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAP//P7MAAAAAAAAAAAAAAAAzYQ2AUKr7P6yq+z//AAAA
tD37PwAAAAAAAAAAAAAAADZdDYBwqvs/rKr7P/8AAABVVQTAAP8AAAAA/wAAAAD/
o2ENgKCq+z8BAAAAsKv7P6NhDYCgqvs/AQAAANzn68T+AAAArKv7P////38QAAAA
vIEIgNCr+z8AAAAAAAAAAKWlpaWlpaWlpaWlpQAAAAAAAAAAAAAAAAAAAAAAAAAA
aCQIQNySAEAwBQYAD5MAgCCg+z+coPs/AAAAAAAAAADSFAEAVwAAADcAAAD0PwAA
AAAAAAAAAAAAAAAAeIMIgMBe+z8AAAAAgIL7PxcAAAD//wAAAAAAAP0UAEANFQBA
/////2gmCEDAXvs/oIMIQDw1+z8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAP//P7MAAAAAAAAAAAAAAAC3YA2AQKD7P5yg+z//AAAA
PDX7PwAAAAAAAAAAAAAAALpcDYBgoPs/nKD7P/8AAABlXwTAAP8AAAAA/wAAAAD/
J2ENgJCg+z8BAAAAoKH7PydhDYCQoPs/AQAAAO8BvND+AAAAnKH7PwAAAAAQAAAA
YIEIgMCh+z8AAAAAAAAAAKWlpaWlpaWlpaWlpQAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADc5+vE
rKr7PwAAAIAhAAYAIGH7PwAAAADwq/s/mGENQAAAAAAjAAYAYED7P5Cs+z8AAAAA
AAAAABCs+z8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAcrPs/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADvAbzQ
nKD7PwAAAIAhAAYAAFf7PwAAAADgofs/HGENQAAAAAAjAAYASDj7P3ii+z8AAAAA
AAAAAACi+z8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAMovs/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
kH77P9B/+z/Ozs7O/D/7P7h4+z9MgPs/9D/7PxkAAADOzs7Ozs7OzkyA+z8AAAAA
AAAAADx6+z9JRExFMQDOzs7Ozs7Ozs4AAQAAADiA+z8AAAAAIQAGAAcAAADOzs7O
AAAAAA==
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
AAAAAAAAAAAAAAAAAAAAAA==
YPn6P8D6+j/Ozs7OeFj7P5hR+z80+/o/cD/7PwMAAADk6vo/5Or6PzT7+j/c6vo/
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
YPn6P8D6+j/Ozs7OYFD7P4BJ+z80+/o/WDf7PwMAAADk6vo/5Or6PzT7+j/c6vo/
FgAAACTr+j9lc3BfdGltZXIAzs7Ozs4AAAAAACD7+j8AAAAAIQAGAAEAAADOzs7O
FgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOn6P3Dp+j/Y6fo/
AAAAAAAAAAABAAAAAAAAAAAAAAAAAAAASB0AQAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -311,59 +311,60 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADOzs4=
nCQIQEgUCEAwBgYAkI0IgCD6+j8AAAAAAAAAAOhB+z8dAAAAVQAAAOBQ+z9IFAiA
aCQIQBQUCEAwBgYANI0IgCD6+j8AAAAAAAAAANA5+z8VAAAAVQAAANBI+z8UFAiA
APr6P9wA8D8BAAAAOAD7PwEAAAAgBgYAAAAAAAAAAAD//wAAAAAAAAAAAAAAAAAA
AAAAAJwmCEABAAAA/IMIQGSM+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAJwkCEC0gQhAMAAFAAAAAAAHOA2AQPr6P7jq+j8AAAAA
AAAAAPQ3DUAAAAAAAAAAALyBCICA+vo/AAAAAAAAAAAAAAAAAAAAAAAAAAD/////
AAAAAAAAAADz1gMA3OfrxAzr+j8AAAAAAQAAACMOBgAAAAAAoPr6P/Q3DUAAAAAA
IwAGALRB+z80+/o/AAAAAAAAAADA+vo/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAGgmCEABAAAAoIMIQPyN+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAGgkCEBYgQhAMAAFAAAAAACLNw2AQPr6P7jq+j8AAAAA
AAAAAHg3DUAAAAAAAAAAAGCBCICA+vo/AAAAAAAAAAAAAAAAAAAAAAAAAAD/////
AAAAAAAAAACMxAAA7wG80Azr+j8AAAAAAQAAACMOBgAAAAAAoPr6P3g3DUAAAAAA
IwAGAJw5+z80+/o/AAAAAAAAAADA+vo/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzPr6PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAA==
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
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
AAAAAAAAAAAAAAAAAAAAAAAAAAA=
FAAAAEgAAABKIAAA
RVNQX0NPUkVfRFVNUF9JTkZPAAA=
AgAAADJhYTkyNjY1YTFiNzg5OWMyZjI4NjhmOGRhZWRmZDVhMWUzNWExYWVhMzY1
ZjkzNmRjODllZThjYzcxNzhhNTMAAAAA
AAEAADYxNTFkNThkNGUzNmJmYWI5MmM4ZTYzYzgzYTEzOThlZDdhNjFkYzFhYjk0
NWQxNzI5ZTY3MDUxNmY5N2NiZjQAAAAA
DAAAAJQAAAClAgAA
RVhUUkFfSU5GTwAA
oGr7P+gAAAAdAAAA7gAAAAUAAADCAAAAAAAAAMMAAAAAAAAAxAAAAAAAAADFAAAA
AAAAAMYAAAAAAAAAxwAAAAAAAACxAAAAm4cOQLIAAAAAAAAAswAAAAAAAAC0AAAA
AAAAALUAAAAAAAAAtgAAAAAAAAC3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
YGL7P+gAAAAdAAAA7gAAAAUAAADCAAAAAAAAAMMAAAAAAAAAxAAAACAIBgDFAAAA
AAAAAMYAAAAAAAAAxwAAAAAAAACxAAAAR4UOQLIAAAAAAAAAswAAAAAAAAC0AAAA
QCwIQLUAAAAAAAAAtgAAAAAAAAC3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAA==
v1VmGg==
hvIqKg==

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@ Overview
ESP-IDF provides support to generate core dumps on unrecoverable software errors. This useful technique allows post-mortem analysis of software state at the moment of failure.
Upon the crash system enters panic state, prints some information and halts or reboots depending configuration. User can choose to generate core dump in order to analyse
the reason of failure on PC later on. Core dump contains snapshots of all tasks in the system at the moment of failure. Snapshots include tasks control blocks (TCB) and stacks.
So it is possible to find out what task, at what instruction (line of code) and what callstack of that task lead to the crash.
So it is possible to find out what task, at what instruction (line of code) and what callstack of that task lead to the crash.
ESP-IDF provides special script `espcoredump.py` to help users to retrieve and analyse core dumps. This tool provides two commands for core dumps analysis:
* info_corefile - prints crashed task's registers, callstack, list of available tasks in the system, memory regions and contents of memory stored in core dump (TCBs and stacks)
@ -29,8 +29,8 @@ There are a number of core dump related configuration options which user can cho
* ELF format (Executable and Linkable Format file for core dump)
* Binary format (Basic binary format for core dump)
The ELF format contains extended features and allow to save more information about broken tasks and crashed software but it requires more space in the flash memory.
It also stores SHA256 of crashed application image. This format of core dump is recommended for new software designs and is flexible enough to extend saved information for future revisions.
The ELF format contains extended features and allow to save more information about broken tasks and crashed software but it requires more space in the flash memory.
It also stores SHA256 of crashed application image. This format of core dump is recommended for new software designs and is flexible enough to extend saved information for future revisions.
The Binary format is kept for compatibility standpoint, it uses less space in the memory to keep data and provides better performance.
3. Maximum number of tasks snapshots in core dump (`Components -> Core dump -> Maximum number of tasks`).
@ -47,8 +47,8 @@ The SHA256 hash algorithm provides greater probability of detecting corruption t
Save core dump to flash
-----------------------
When this option is selected core dumps are saved to special partition on flash. When using default partition table files which are provided with ESP-IDF it automatically
allocates necessary space on flash, But if user wants to use its own layout file together with core dump feature it should define separate partition for core dump
When this option is selected core dumps are saved to special partition on flash. When using default partition table files which are provided with ESP-IDF it automatically
allocates necessary space on flash, But if user wants to use its own layout file together with core dump feature it should define separate partition for core dump
as it is shown below::
# Name, Type, SubType, Offset, Size
@ -58,7 +58,7 @@ as it is shown below::
factory, app, factory, 0x10000, 1M
coredump, data, coredump,, 64K
There are no special requrements for partition name. It can be choosen according to the user application needs, but partition type should be 'data' and
There are no special requrements for partition name. It can be choosen according to the user application needs, but partition type should be 'data' and
sub-type should be 'coredump'. Also when choosing partition size note that core dump data structure introduces constant overhead of 20 bytes and per-task overhead of 12 bytes.
This overhead does not include size of TCB and stack for every task. So partirion size should be at least 20 + max tasks number x (12 + TCB size + max task stack size) bytes.
@ -68,7 +68,7 @@ or `espcoredump.py -p </path/to/serial/port> dbg_corefile </path/to/program/elf/
Print core dump to UART
-----------------------
When this option is selected base64-encoded core dumps are printed on UART upon system panic. In this case user should save core dump text body to some file manually and
When this option is selected base64-encoded core dumps are printed on UART upon system panic. In this case user should save core dump text body to some file manually and
then run the following command: `espcoredump.py info_corefile -t b64 -c </path/to/saved/base64/text> </path/to/program/elf/file>`
or `espcoredump.py dbg_corefile -t b64 -c </path/to/saved/base64/text> </path/to/program/elf/file>`
@ -112,3 +112,4 @@ Generic command syntax:
* --save-core,-s SAVE_CORE. Save core to file. Othwerwise temporary core file will be deleted. Ignored with "-c".
* --rom-elf,-r ROM_ELF. Path to ROM ELF file to use (if skipped "esp32_rom.elf" is used).
* --print-mem,-m Print memory dump. Used only with "info_corefile".
* <prog> Path to program ELF file.