Merge branch 'bugfix/coredump_bin_fmt_ver_update' into 'master'

Fixes coredump compatibility with legacy binary core dumps

See merge request espressif/esp-idf!6794
This commit is contained in:
Ivan Grokhotkov 2020-01-10 10:04:17 +08:00
commit a559014ff0
10 changed files with 1000 additions and 955 deletions

View File

@ -443,11 +443,6 @@ void start_cpu0_default(void)
#if CONFIG_ESP32_ENABLE_COREDUMP #if CONFIG_ESP32_ENABLE_COREDUMP
esp_core_dump_init(); 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 #endif
#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE #if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE

View File

@ -557,16 +557,26 @@ class ESPCoreDumpLoaderError(ESPCoreDumpError):
super(ESPCoreDumpLoaderError, self).__init__(message) 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): class ESPCoreDumpLoader(object):
"""Core dump loader base class """Core dump loader base class
""" """
ESP32_COREDUMP_VERSION_BIN = 1 # TODO: add class for core dump version and move all version-dependent params to it
ESP32_COREDUMP_VERSION_ELF_CRC32 = 2 ESP_CORE_DUMP_CHIP_ESP32 = 0
ESP32_COREDUMP_VERSION_ELF_SHA256 = 3 # "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_INFO_TYPE = 8266
ESP_CORE_DUMP_TASK_INFO_TYPE = 678 ESP_CORE_DUMP_TASK_INFO_TYPE = 678
ESP_CORE_DUMP_EXTRA_INFO_TYPE = 677 ESP_CORE_DUMP_EXTRA_INFO_TYPE = 677
ESP_COREDUMP_CURR_TASK_MARKER = 0xdeadbeef 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_FMT = '<5L'
ESP32_COREDUMP_HDR_SZ = struct.calcsize(ESP32_COREDUMP_HDR_FMT) ESP32_COREDUMP_HDR_SZ = struct.calcsize(ESP32_COREDUMP_HDR_FMT)
ESP32_COREDUMP_TSK_HDR_FMT = '<3L' ESP32_COREDUMP_TSK_HDR_FMT = '<3L'
@ -584,6 +594,7 @@ class ESPCoreDumpLoader(object):
"""Base constructor for core dump loader """Base constructor for core dump loader
""" """
self.fcore = None self.fcore = None
self.hdr = {}
def _get_registers_from_stack(self, data, grows_down): def _get_registers_from_stack(self, data, grows_down):
"""Returns list of registers (in GDB format) from xtensa stack frame """Returns list of registers (in GDB format) from xtensa stack frame
@ -713,21 +724,18 @@ class ESPCoreDumpLoader(object):
if self.fcore_name: if self.fcore_name:
self.remove_tmp_file(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 """ Reads the ELF formatted core dump image and parse it
""" """
core_off = off core_off = off
data = self.read_data(core_off, self.ESP32_COREDUMP_HDR_SZ) if self.hdr['ver'] == self.ESP32_COREDUMP_VERSION_ELF_CRC32:
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:
checksum_len = self.ESP32_COREDUMP_CRC_SZ 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 checksum_len = self.ESP32_COREDUMP_SHA256_SZ
else: else:
raise ESPCoreDumpLoaderError("Core dump version '%d' is not supported!" % coredump_ver) raise ESPCoreDumpLoaderError("Core dump version '%d' is not supported!" % self.hdr['ver'])
core_off += self.ESP32_COREDUMP_HDR_SZ
core_elf = ESPCoreDumpElfFile() 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: with open(core_fname, 'w+b') as fce:
try: try:
fce.write(data) fce.write(data)
@ -750,39 +758,27 @@ class ESPCoreDumpLoader(object):
n_ver_len = struct.calcsize("<L") n_ver_len = struct.calcsize("<L")
n_sha256_len = self.ESP32_COREDUMP_SHA256_SZ * 2 # SHA256 as hex string 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]) 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)." % raise ESPCoreDumpError("Invalid application image for coredump: app_SHA256(%s) != coredump_SHA256(%s)." %
(app_sha256, coredump_sha256)) (app_sha256, coredump_sha256))
except ESPCoreDumpError as e: except ESPCoreDumpError as e:
logging.warning("Failed to extract ELF core dump image into file %s. (Reason: %s)" % (core_fname, e)) logging.warning("Failed to extract ELF core dump image into file %s. (Reason: %s)" % (core_fname, e))
return core_fname 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 """Creates core dump ELF file
""" """
core_off = off 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: with open(core_fname, 'w+b') as fce:
tcbsz_aligned = tcbsz tcbsz_aligned = self.hdr['tcbsz']
if tcbsz_aligned % 4: if tcbsz_aligned % 4:
tcbsz_aligned = 4 * (old_div(tcbsz_aligned,4) + 1) 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() core_elf = ESPCoreDumpElfFile()
notes = b'' notes = b''
core_dump_info_notes = b'' core_dump_info_notes = b''
task_info_notes = b'' task_info_notes = b''
task_status = EspCoreDumpTaskStatus() 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_index = i
task_status.task_flags = EspCoreDumpTaskStatus.TASK_STATUS_CORRECT task_status.task_flags = EspCoreDumpTaskStatus.TASK_STATUS_CORRECT
data = self.read_data(core_off, self.ESP32_COREDUMP_TSK_HDR_SZ) 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 task_status.task_tcb_addr = tcb_addr
try: try:
if self.tcb_is_sane(tcb_addr, tcbsz_aligned): if self.tcb_is_sane(tcb_addr, tcbsz_aligned):
if tcbsz != tcbsz_aligned: if self.hdr['tcbsz'] != tcbsz_aligned:
core_elf.add_program_segment(tcb_addr, data[: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) ESPCoreDumpElfFile.PT_LOAD, ESPCoreDumpSegment.PF_R | ESPCoreDumpSegment.PF_W)
else: else:
core_elf.add_program_segment(tcb_addr, data, ESPCoreDumpElfFile.PT_LOAD, ESPCoreDumpSegment.PF_R | ESPCoreDumpSegment.PF_W) 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 notes += note
if ESPCoreDumpElfFile.REG_EXCCAUSE_IDX in extra_regs and len(core_dump_info_notes) == 0: 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 # 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 = [] exc_regs = []
for reg_id in extra_regs: for reg_id in extra_regs:
exc_regs.extend([reg_id, extra_regs[reg_id]]) exc_regs.extend([reg_id, extra_regs[reg_id]])
core_dump_info_notes += Elf32NoteDesc("EXTRA_INFO", self.ESP_CORE_DUMP_EXTRA_INFO_TYPE, 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() struct.pack("<%dL" % (1 + len(exc_regs)), tcb_addr, *exc_regs)).dump()
for i in range(segs_num): if self.hdr['ver'] == self.ESP32_COREDUMP_VERSION_BIN_V2:
data = self.read_data(core_off, self.ESP32_COREDUMP_MEM_SEG_HDR_SZ) for i in range(self.hdr['segs_num']):
core_off += self.ESP32_COREDUMP_MEM_SEG_HDR_SZ data = self.read_data(core_off, self.ESP32_COREDUMP_MEM_SEG_HDR_SZ)
mem_start,mem_sz = struct.unpack_from(self.ESP32_COREDUMP_MEM_SEG_HDR_FMT, data) core_off += self.ESP32_COREDUMP_MEM_SEG_HDR_SZ
logging.debug("Read memory segment %d bytes @ 0x%x" % (mem_sz, mem_start)) mem_start,mem_sz = struct.unpack_from(self.ESP32_COREDUMP_MEM_SEG_HDR_FMT, data)
data = self.read_data(core_off, stack_len_aligned) logging.debug("Read memory segment %d bytes @ 0x%x" % (mem_sz, mem_start))
core_elf.add_program_segment(mem_start, data, ESPCoreDumpElfFile.PT_LOAD, ESPCoreDumpSegment.PF_R | ESPCoreDumpSegment.PF_W) data = self.read_data(core_off, stack_len_aligned)
core_off += mem_sz core_elf.add_program_segment(mem_start, data, ESPCoreDumpElfFile.PT_LOAD, ESPCoreDumpSegment.PF_R | ESPCoreDumpSegment.PF_W)
core_off += mem_sz
# add notes # add notes
try: try:
core_elf.add_aux_segment(notes, ESPCoreDumpElfFile.PT_NOTE, 0) core_elf.add_aux_segment(notes, ESPCoreDumpElfFile.PT_NOTE, 0)
@ -875,17 +872,35 @@ class ESPCoreDumpLoader(object):
# add ROM text sections # add ROM text sections
if rom_elf: if rom_elf:
for ps in rom_elf.program_segments: for ps in rom_elf.program_segments:
if ps.flags & ESPCoreDumpSegment.PF_X: if (ps.flags & ESPCoreDumpSegment.PF_X) == 0:
try: continue
core_elf.add_program_segment(ps.addr, ps.data, ESPCoreDumpElfFile.PT_LOAD, ps.flags) try:
except ESPCoreDumpError as e: core_elf.add_program_segment(ps.addr, ps.data, ESPCoreDumpElfFile.PT_LOAD, ps.flags)
logging.warning("Skip ROM segment %d bytes @ 0x%x. (Reason: %s)" % (len(ps.data), ps.addr, e)) 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_type = ESPCoreDumpElfFile.ET_CORE
core_elf.e_machine = ESPCoreDumpElfFile.EM_XTENSA core_elf.e_machine = ESPCoreDumpElfFile.EM_XTENSA
core_elf.dump(fce) core_elf.dump(fce)
return core_fname 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): def read_data(self, off, sz):
"""Reads data from raw core dump got from flash or UART """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) data = self.read_data(0, self.ESP32_COREDUMP_HDR_SZ)
self.checksum_len = 0 self.checksum_len = 0
_,coredump_ver,_,_,_ = struct.unpack_from(self.ESP32_COREDUMP_HDR_FMT, data) _,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) 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) 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) 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): def gdbmi_freertos_get_task_name(p, tcb_addr):
p,res = gdbmi_data_evaluate_expression(p, "(char*)((TCB_t *)0x%x)->pcTaskName" % 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: if result:
return p,result.group(1) return p,result.group(1)
return p,'' 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('--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', '-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"), ' 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 ' parser_debug_coredump.add_argument('--off', '-o', help='Ofsset of coredump partition in flash '
'(type "make partition_table" to see).', type=int, default=None) '(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. ' 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('--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', '-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"), ' 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 ' parser_info_coredump.add_argument('--off', '-o', help='Offset of coredump partition in flash (type '
'"make partition_table" to see).', type=int, default=None) '"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. ' 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 "esp_core_dump_priv.h"
#include "soc/cpu.h" #include "soc/cpu.h"
#include "esp_debug_helpers.h" #include "esp_debug_helpers.h"
#include "esp_app_format.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #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) #define COREDUMP_TCB_SIZE sizeof(StaticTask_t)
// Gets RTOS tasks snapshot // Gets RTOS tasks snapshot

View File

@ -41,9 +41,15 @@ extern "C" {
#endif #endif
#define COREDUMP_MAX_TASK_STACK_SIZE (64*1024) #define COREDUMP_MAX_TASK_STACK_SIZE (64*1024)
#define COREDUMP_VERSION_BIN 1 // COREDUMP_VERSION_CHIP is defined in ports
#define COREDUMP_VERSION_ELF_CRC32 2 #define COREDUMP_VERSION_MAKE(_maj_, _min_) ((((COREDUMP_VERSION_CHIP)&0xFFFF) << 16) | (((_maj_)&0xFF) << 8) | (((_min_)&0xFF) << 0))
#define COREDUMP_VERSION_ELF_SHA256 3 #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_MARKER 0xDEADBEEF
#define COREDUMP_CURR_TASK_NOT_FOUND -1 #define COREDUMP_CURR_TASK_NOT_FOUND -1
@ -55,7 +61,7 @@ extern "C" {
#define COREDUMP_SHA256_LEN 32 #define COREDUMP_SHA256_LEN 32
#endif #endif
#else #else
#define COREDUMP_VERSION COREDUMP_VERSION_BIN #define COREDUMP_VERSION COREDUMP_VERSION_BIN_CURRENT
#endif #endif
typedef esp_err_t (*esp_core_dump_write_prepare_t)(void *priv, uint32_t *data_len); 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. // limitations under the License.
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include "esp_partition.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_core_dump_priv.h" #include "esp_core_dump_priv.h"
#include "core_dump_elf.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(); 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 /* do nothing by default */
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;
}

View File

@ -13,9 +13,14 @@
// limitations under the License. // limitations under the License.
#include <string.h> #include <string.h>
#include "esp_partition.h" #include "esp_partition.h"
#include "esp32/rom/crc.h" #include "esp_log.h"
#include "esp_core_dump_priv.h" #include "esp_core_dump_priv.h"
#include "esp_flash_internal.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"; 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_) #define ESP_COREDUMP_FLASH_ERASE(_off_, _len_) esp_flash_erase_region(esp_flash_default_chip, _off_, _len_)
#endif #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) 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_core_dump_write(frame, &wr_cfg);
ESP_COREDUMP_LOGI("Core dump has been saved to flash."); 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 #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_core_dump_write((void*)frame, &wr_cfg);
ESP_COREDUMP_LOGI("Core dump has been written to uart."); 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 #endif

View File

@ -1,38 +1,38 @@
UD0AAAIAAAAKAAAAfAEAAAAAAAA= ID0AAAABAAAKAAAAfAEAAAAAAAA=
f0VMRgEBAQAAAAAAAAAAAAQAXgABAAAAAAAAADQAAAAAAAAAAAAAADQAIAAWACgA f0VMRgEBAQAAAAAAAAAAAAQAXgABAAAAAAAAADQAAAAAAAAAAAAAADQAIAAWACgA
AAAAAA== AAAAAA==
BAAAAPQCAAAAAAAAAAAAAMAXAADAFwAABgAAAAAAAAA= BAAAAPQCAAAAAAAAAAAAAMAXAADAFwAABgAAAAAAAAA=
AQAAALQaAACgavs/oGr7P3wBAAB8AQAABgAAAAAAAAA= AQAAALQaAABgYvs/YGL7P3wBAAB8AQAABgAAAAAAAAA=
AQAAADAcAAAgtPs/ILT7P/gBAAD4AQAABgAAAAAAAAA= AQAAADAcAAAQqvs/EKr7P/ABAADwAQAABgAAAAAAAAA=
AQAAACgeAACQrPs/kKz7P3wBAAB8AQAABgAAAAAAAAA= AQAAACAeAAB4ovs/eKL7P3wBAAB8AQAABgAAAAAAAAA=
AQAAAKQfAABwqfs/cKn7PwwDAAAMAwAABgAAAAAAAAA= AQAAAJwfAABgn/s/YJ/7PwQDAAAEAwAABgAAAAAAAAA=
AQAAALAiAABMgPs/TID7P3wBAAB8AQAABgAAAAAAAAA= AQAAAKAiAAA0dvs/NHb7P3wBAAB8AQAABgAAAAAAAAA=
AQAAACwkAACQfvs/kH77P6gBAACoAQAABgAAAAAAAAA= AQAAABwkAACAdPs/gHT7P6ABAACgAQAABgAAAAAAAAA=
AQAAANQlAACwePs/sHj7P3wBAAB8AQAABgAAAAAAAAA= AQAAALwlAACYbvs/mG77P3wBAAB8AQAABgAAAAAAAAA=
AQAAAFAnAADwdvs/8Hb7P6wBAACsAQAABgAAAAAAAAA= AQAAADgnAADgbPs/4Gz7P6QBAACkAQAABgAAAAAAAAA=
AQAAAPwoAAAUafs/FGn7P3wBAAB8AQAABgAAAAAAAAA= AQAAANwoAADUYPs/1GD7P3wBAAB8AQAABgAAAAAAAAA=
AQAAAHgqAABgZ/s/YGf7P6ABAACgAQAABgAAAAAAAAA= AQAAAFgqAAAgX/s/IF/7P6ABAACgAQAABgAAAAAAAAA=
AQAAABgsAACYbPs/mGz7P3wBAAB8AQAABgAAAAAAAAA= AQAAAPgrAABYZPs/WGT7P3wBAAB8AQAABgAAAAAAAAA=
AQAAAJQtAACAvPs/gLz7P6gBAACoAQAABgAAAAAAAAA= AQAAAHQtAABwsvs/cLL7P6ABAACgAQAABgAAAAAAAAA=
AQAAADwvAAD0ivs/9Ir7P3wBAAB8AQAABgAAAAAAAAA= AQAAABQvAADcgPs/3ID7P3wBAAB8AQAABgAAAAAAAAA=
AQAAALgwAAAgifs/IIn7P8ABAADAAQAABgAAAAAAAAA= AQAAAJAwAAAAf/s/AH/7P8gBAADIAQAABgAAAAAAAAA=
AQAAAHgyAAA0+/o/NPv6P3wBAAB8AQAABgAAAAAAAAA= AQAAAFgyAAA0+/o/NPv6P3wBAAB8AQAABgAAAAAAAAA=
AQAAAPQzAABg+fo/YPn6P8ABAADAAQAABgAAAAAAAAA= AQAAANQzAABg+fo/YPn6P8ABAADAAQAABgAAAAAAAAA=
AQAAALQ1AABwWPs/cFj7P3wBAAB8AQAABgAAAAAAAAA= AQAAAJQ1AABYUPs/WFD7P3wBAAB8AQAABgAAAAAAAAA=
AQAAADA3AACwVvs/sFb7P6wBAACsAQAABgAAAAAAAAA= AQAAABA3AACgTvs/oE77P6QBAACkAQAABgAAAAAAAAA=
AQAAANw4AACQUfs/kFH7P3wBAAB8AQAABgAAAAAAAAA= AQAAALQ4AAB4Sfs/eEn7P3wBAAB8AQAABgAAAAAAAAA=
AQAAAFg6AACwT/s/sE/7P8wBAADMAQAABgAAAAAAAAA= AQAAADA6AACgR/s/oEf7P8QBAADEAQAABgAAAAAAAAA=
BAAAACQ8AAAAAAAAAAAAABQBAAAUAQAABgAAAAAAAAA= BAAAAPQ7AAAAAAAAAAAAABQBAAAUAQAABgAAAAAAAAA=
CAAAAEwCAAABAAAA CAAAAEwCAAABAAAA
Q09SRQAAAAA= Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoGr7PwAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYGL7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQ4NQCAIBgD9FABADRUAQP////8AAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARQ4NQCAIBgD9FABADRUAQP////8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgODYDgtPs/ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAODYDQqvs/
AgAAACy1+z8gtfs/cOn6PwAAAAAAAAAABQAAAK3///8gAAAAIGv7PwEAAACAAAAA AgAAAByr+z8Qq/s/cOn6PwAAAAAAAAAABQAAAK3///8gAAAA4GL7PwEAAACAAAAA
AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -40,44 +40,44 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA CAAAAEwCAAABAAAA
Q09SRQAAAAA= Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkKz7PwAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeKL7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1pIAQCAFBgD9FABADRUAQP////8XAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3JIAQCAFBgD9FABADRUAQP////8XAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+TAIAwqvs/ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+TAIAgoPs/
rKr7PwAAAAAAAAAAwBsEAFcAAAA3AAAAnAH+PwAA9D8AAAAAAAAAAAAAAADDGwQA nKD7PwAAAAAAAAAA0hQBAFcAAAA3AAAA9D8AAAAAAAAAAAAAAAAAAHiDCIDAXvs/
AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAICC+z8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA CAAAAEwCAAABAAAA
Q09SRQAAAAA= Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATID7PwAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANHb7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABogOQCAABgBsxABAd8QAQP////8AAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsoUOQCAABgBsxABAd8QAQP////8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM44DYBQf/s/ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFI4DYBAdfs/
AAAAAAAAAAABAAAAAQAAgAMAAAAjAAYA1JcIgEB/+z8DAAAAIwgGACAIBgABAAAA AAAAAAAAAAABAAAAAQAAgAMAAAAjAAYAeJcIgDB1+z8DAAAAIwgGACAIBgABAAAA
IAgGAOCO+z8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA IAgGANCE+z8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA CAAAAEwCAAABAAAA
Q09SRQAAAAA= Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsHj7PwAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmG77PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABogOQCAFBgBsxABAd8QAQP////8AAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsoUOQCAFBgBsxABAd8QAQP////8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM44DYCwd/s/ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFI4DYCgbfs/
AAAAAAMAAAABAAAAAQAAgAMAAAAjAAYAepEIgJB3+z8Ucfs/SB0AQCAEBgABAAAA AAAAAAMAAAABAAAAAQAAgAMAAAAjCgYAHpEIgIBt+z/8Zvs/SB0AQCAEBgABAAAA
IAQGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA IAQGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -85,29 +85,14 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA CAAAAEwCAAABAAAA
Q09SRQAAAAA= Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFGn7PwAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1GD7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASBQIQCAFBgD9FABADRUAQPn///8AAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQIQCADBgD9FABADRUAQPn///8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALqbCIAgaPs/ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF6bCIDgX/s/
AAAAAFojBADUlwiAAFf7PwMAAAAjCAYASBQIgABo+z/cAPA/AQAAADgA+z8BAAAA AAAAAGwcAQB4lwiA8E77PwMAAAAjCAYAFBQIgMBf+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
IAMGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA IAMGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -115,15 +100,30 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA CAAAAEwCAAABAAAA
Q09SRQAAAAA= Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9Ir7PwAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWGT7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASBQIQCAABgAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQIQCABBgD9FABADRUAQPj///8AAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF2pCIDgifs/ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF6bCIAws/s/
AAAAAAAAAAAsgvs/AAAAAAAAAABgXPs/SBQIgMCJ+z/cAPA/AQAAADgA+z9wXPs/ AAAAAGwcAQBxWA2A0J/7PwAIAAAEAPs/FBQIgBCz+z/cAPA/AQAAADgA+z8BAAAA
iCsNQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 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 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -131,13 +131,13 @@ AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA CAAAAEwCAAABAAAA
Q09SRQAAAAA= Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANPv6PwAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANPv6PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASBQIQCAGBgAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQIQCAGBgAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJCNCIAg+vo/ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADSNCIAg+vo/
AAAAAAAAAADoQfs/HQAAAFUAAADgUPs/SBQIgAD6+j/cAPA/AQAAADgA+z8BAAAA AAAAAAAAAADQOfs/FQAAAFUAAADQSPs/FBQIgAD6+j/cAPA/AQAAADgA+z8BAAAA
IAYGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA IAYGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -145,14 +145,14 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA CAAAAEwCAAABAAAA
Q09SRQAAAAA= Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcFj7PwAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWFD7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkI0IQCAIBgAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANI0IQCAIBgAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEMdCIBwV/s/ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8dCIBgT/s/
9FP7PwAAAABIVPs/AAAAAAEAAAAAAAAAkI0IgFBX+z8BAAAABAAAAOxB+z8KAAAA 3Ev7PwAAAAAwTPs/AAAAAAEAAAAAAAAANI0IgEBP+z8BAAAABAAAANQ5+z8KAAAA
AACAABwA9D8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AACAABwA9D8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -160,150 +160,150 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA
CAAAAEwCAAABAAAA CAAAAEwCAAABAAAA
Q09SRQAAAAA= Q09SRQAAAAA=
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkFH7PwAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeEn7PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASBQIQCAOBgAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQIQCAOBgAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJCNCIBwUPs/ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADSNCIBgSPs/
AAAAAAAAAADoQfs/zc0AAAEAAAAAAAAASBQIgFBQ+z/cAPA/AQAAADgA+z8BAAAA AAAAAAAAAADQOfs/zc0AAAEAAAAAAAAAFBQIgEBI+z/cAPA/AQAAADgA+z8BAAAA
IAAGAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA IAAGAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA
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
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAA==
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
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADc5+vE AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADvAbzQ
rKr7PwAAAIAhAAYAIGH7PwAAAADwq/s/mGENQAAAAAAjAAYAYED7P5Cs+z8AAAAA nKD7PwAAAIAhAAYAAFf7PwAAAADgofs/HGENQAAAAAAjAAYASDj7P3ii+z8AAAAA
AAAAABCs+z8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAACi+z8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAcrPs/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAMovs/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA AAAAAA==
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
AAAAAAAAAAAAAAAAAAAAAA== AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
YPn6P8D6+j/Ozs7OeFj7P5hR+z80+/o/cD/7PwMAAADk6vo/5Or6PzT7+j/c6vo/ YPn6P8D6+j/Ozs7OYFD7P4BJ+z80+/o/WDf7PwMAAADk6vo/5Or6PzT7+j/c6vo/
FgAAACTr+j9lc3BfdGltZXIAzs7Ozs4AAAAAACD7+j8AAAAAIQAGAAEAAADOzs7O FgAAACTr+j9lc3BfdGltZXIAzs7Ozs4AAAAAACD7+j8AAAAAIQAGAAEAAADOzs7O
FgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOn6P3Dp+j/Y6fo/ FgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOn6P3Dp+j/Y6fo/
AAAAAAAAAAABAAAAAAAAAAAAAAAAAAAASB0AQAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAABAAAAAAAAAAAAAAAAAAAASB0AQAAAAAAAAAAAAAAAAAAAAAAAAAAA
@ -311,59 +311,60 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADOzs4= AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADOzs4=
nCQIQEgUCEAwBgYAkI0IgCD6+j8AAAAAAAAAAOhB+z8dAAAAVQAAAOBQ+z9IFAiA aCQIQBQUCEAwBgYANI0IgCD6+j8AAAAAAAAAANA5+z8VAAAAVQAAANBI+z8UFAiA
APr6P9wA8D8BAAAAOAD7PwEAAAAgBgYAAAAAAAAAAAD//wAAAAAAAAAAAAAAAAAA APr6P9wA8D8BAAAAOAD7PwEAAAAgBgYAAAAAAAAAAAD//wAAAAAAAAAAAAAAAAAA
AAAAAJwmCEABAAAA/IMIQGSM+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA AAAAAGgmCEABAAAAoIMIQPyN+j8AAAAAAAAAAAAAAAD//z+zAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAJwkCEC0gQhAMAAFAAAAAAAHOA2AQPr6P7jq+j8AAAAA AAAAAAAAAAAAAAAAAAAAAGgkCEBYgQhAMAAFAAAAAACLNw2AQPr6P7jq+j8AAAAA
AAAAAPQ3DUAAAAAAAAAAALyBCICA+vo/AAAAAAAAAAAAAAAAAAAAAAAAAAD///// AAAAAHg3DUAAAAAAAAAAAGCBCICA+vo/AAAAAAAAAAAAAAAAAAAAAAAAAAD/////
AAAAAAAAAADz1gMA3OfrxAzr+j8AAAAAAQAAACMOBgAAAAAAoPr6P/Q3DUAAAAAA AAAAAAAAAACMxAAA7wG80Azr+j8AAAAAAQAAACMOBgAAAAAAoPr6P3g3DUAAAAAA
IwAGALRB+z80+/o/AAAAAAAAAADA+vo/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA IwAGAJw5+z80+/o/AAAAAAAAAADA+vo/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzPr6PwAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzPr6PwAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAA== AAAAAAAAAAAAAAAAAAAAAA==
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
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== AAAAAAAAAAAAAAAAAAAAAAAAAAA=
FAAAAEgAAABKIAAA FAAAAEgAAABKIAAA
RVNQX0NPUkVfRFVNUF9JTkZPAAA= RVNQX0NPUkVfRFVNUF9JTkZPAAA=
AgAAADJhYTkyNjY1YTFiNzg5OWMyZjI4NjhmOGRhZWRmZDVhMWUzNWExYWVhMzY1 AAEAADYxNTFkNThkNGUzNmJmYWI5MmM4ZTYzYzgzYTEzOThlZDdhNjFkYzFhYjk0
ZjkzNmRjODllZThjYzcxNzhhNTMAAAAA NWQxNzI5ZTY3MDUxNmY5N2NiZjQAAAAA
DAAAAJQAAAClAgAA DAAAAJQAAAClAgAA
RVhUUkFfSU5GTwAA RVhUUkFfSU5GTwAA
oGr7P+gAAAAdAAAA7gAAAAUAAADCAAAAAAAAAMMAAAAAAAAAxAAAAAAAAADFAAAA YGL7P+gAAAAdAAAA7gAAAAUAAADCAAAAAAAAAMMAAAAAAAAAxAAAACAIBgDFAAAA
AAAAAMYAAAAAAAAAxwAAAAAAAACxAAAAm4cOQLIAAAAAAAAAswAAAAAAAAC0AAAA AAAAAMYAAAAAAAAAxwAAAAAAAACxAAAAR4UOQLIAAAAAAAAAswAAAAAAAAC0AAAA
AAAAALUAAAAAAAAAtgAAAAAAAAC3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA QCwIQLUAAAAAAAAAtgAAAAAAAAC3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAA== 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. 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 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. 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: 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) * 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) * ELF format (Executable and Linkable Format file for core dump)
* Binary format (Basic binary format 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. 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. 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. 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`). 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 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 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 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:: as it is shown below::
# Name, Type, SubType, Offset, Size # Name, Type, SubType, Offset, Size
@ -58,7 +58,7 @@ as it is shown below::
factory, app, factory, 0x10000, 1M factory, app, factory, 0x10000, 1M
coredump, data, coredump,, 64K 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. 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. 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 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>` 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>` 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". * --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). * --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". * --print-mem,-m Print memory dump. Used only with "info_corefile".
* <prog> Path to program ELF file.